<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jenna Pederson</title>
    <description>The latest articles on DEV Community by Jenna Pederson (@jennapederson).</description>
    <link>https://dev.to/jennapederson</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F174967%2F6a67f6e2-f078-4654-a441-ec5576074cba.jpg</url>
      <title>DEV Community: Jenna Pederson</title>
      <link>https://dev.to/jennapederson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jennapederson"/>
    <language>en</language>
    <item>
      <title>Stop over-engineering your n8n RAG pipeline before you've shipped anything</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Mon, 23 Mar 2026 15:00:00 +0000</pubDate>
      <link>https://dev.to/jennapederson/stop-over-engineering-your-n8n-rag-pipeline-before-youve-shipped-anything-2gc0</link>
      <guid>https://dev.to/jennapederson/stop-over-engineering-your-n8n-rag-pipeline-before-youve-shipped-anything-2gc0</guid>
      <description>&lt;p&gt;I see this pattern a lot in &lt;a href="https://n8n.io/" rel="noopener noreferrer"&gt;n8n&lt;/a&gt;: a developer sets out to build a RAG-powered feature and ends up three days deep configuring (and reconfiguring) text splitters, embedding models, rerankers, and debugging — without a working system to show for it.&lt;/p&gt;

&lt;p&gt;It's a real productivity trap, and it's partly an artifact of how RAG is usually taught. Most tutorials step through the full pipeline from scratch: load documents, split them, embed them, store them, retrieve them, rerank them, generate. You internalize the idea that understanding and owning each step is the price of admission.&lt;/p&gt;

&lt;p&gt;For learning, that's fine. For shipping, it's often the wrong starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two n8n nodes, two different commitments
&lt;/h2&gt;

&lt;p&gt;When building RAG workflows in n8n, you have two primary options for working with &lt;a href="https://www.pinecone.io/" rel="noopener noreferrer"&gt;Pinecone&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Pinecone Assistant node&lt;/strong&gt; is a managed RAG pipeline. You add documents to an Assistant, and Pinecone handles chunking, embedding, query planning, semantic search, and reranking automatically. In your workflow, you work with a single node. The pipeline decisions are made for you — based on Pinecone's retrieval best practices — and they update automatically as the Assistant product improves.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Pinecone Vector Store node&lt;/strong&gt; gives you direct access to the vector database. You build the pipeline yourself: choose your chunking strategy, choose your embedding model, implement your search approach, add a reranker if you need one. You control every variable. You also debug every failure.&lt;/p&gt;

&lt;p&gt;Neither node is inherently better. They represent different tradeoffs, and the right choice depends on what you're actually building — not on which gives you more control.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bias toward complexity
&lt;/h2&gt;

&lt;p&gt;I think engineers are often drawn to the option with more control — I've felt this pull myself, often out of curiosity of "how does this thing really work?" But here's the thing: it makes sense in systems where the details of implementation create meaningful product differentiation. It makes less sense in systems where the infrastructure is not the product.&lt;/p&gt;

&lt;p&gt;For most RAG applications, the retrieval pipeline is not the product. It's the thing that enables the product. A customer support chatbot, an internal knowledge base, a documentation search tool — these applications succeed or fail based on how well they serve users, not based on which chunking algorithm was used under the hood.&lt;/p&gt;

&lt;p&gt;When the retrieval pipeline becomes a thing you maintain, tune, and debug continuously, it consumes engineering attention that could go toward the features users actually see. The Pinecone Assistant node is designed to prevent that: managed retrieval as a building block, not a maintenance burden.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the details actually matter
&lt;/h2&gt;

&lt;p&gt;There are real scenarios where custom pipeline control earns its complexity. The Vector Store node is the right choice when:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your content has specialized retrieval requirements.&lt;/strong&gt; Legal documents often require clause-level chunking precision that generic strategies miss. Technical documentation with code snippets may need language-aware processing. Multilingual content benefits from language-specific embedding models. If your content type has characteristics that standard chunking handles poorly, you need access to those controls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You require a specific embedding model.&lt;/strong&gt; Fine-tuned models trained on domain-specific data, models required for compliance or data residency reasons, or embedding models that outperform defaults for your specific content type — these are legitimate reasons to own the embedding step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You're implementing advanced retrieval techniques.&lt;/strong&gt; Hybrid search (combining vector search with keyword search), multi-stage retrieval with custom reranking, or metadata-heavy filtering strategies all require direct access to the vector store layer.&lt;/p&gt;

&lt;p&gt;The common thread in all three scenarios: the pipeline detail creates a specific, nameable improvement in retrieval quality or system behavior. That's what I check for before reaching for the Vector Store node.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical decision framework
&lt;/h2&gt;

&lt;p&gt;Before choosing, I'd ask one question: what specific user-facing outcome requires custom control over this pipeline step?&lt;/p&gt;

&lt;p&gt;If the answer is concrete — "I'm building a legal document search tool where missed clauses have real downstream consequences" — Pinecone Vector Store is worth the investment. If the answer is vague — "I might need more flexibility later" or "I want to understand how it works" — that's not a product requirement, it's technical curiosity. Ship with the Assistant node and revisit when you hit an actual limitation.&lt;/p&gt;

&lt;p&gt;The mental shift is from "how do I build this?" to "what am I building?" The Assistant node enables that shift by removing the infrastructure layer as an ongoing concern. When retrieval becomes a managed building block, the interesting engineering work moves up the stack — to routing logic, to evaluation, to the product features that actually differentiate what you're making.&lt;/p&gt;

&lt;h2&gt;
  
  
  My practical recommendation
&lt;/h2&gt;

&lt;p&gt;For most n8n builders starting a RAG project, I recommend beginning with the Pinecone Assistant node. It handles the pipeline decisions competently, keeps your workflow readable, and gets you to a working system quickly. You can always migrate to a custom pipeline when you identify a specific reason to do so — and that reason will be clearer once you've shipped something and seen where the actual friction is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpzxh0j5y6y89ytys04j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpzxh0j5y6y89ytys04j.png" alt="Assistant workflow with Pinecone Assistant n8n node" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Complexity is easy to add later, but you can't get back the time you spend on premature optimization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try it out for yourself
&lt;/h3&gt;

&lt;p&gt;Try out the Assistant node with this &lt;a href="https://docs.pinecone.io/guides/assistant/quickstart/n8n-quickstart" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt; or use one of these &lt;a href="https://n8n.io/creators/pinecone/" rel="noopener noreferrer"&gt;n8n workflow templates&lt;/a&gt; I built to get ideas.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>n8n</category>
      <category>pinecone</category>
      <category>rag</category>
    </item>
    <item>
      <title>Build a multi-assistant workflow with Pinecone Assistant in n8n</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Mon, 16 Feb 2026 15:00:00 +0000</pubDate>
      <link>https://dev.to/jennapederson/build-a-multi-assistant-workflow-with-pinecone-assistant-in-n8n-44ia</link>
      <guid>https://dev.to/jennapederson/build-a-multi-assistant-workflow-with-pinecone-assistant-in-n8n-44ia</guid>
      <description>&lt;p&gt;I built an n8n workflow that shows a simple way to use multiple, specialized knowledge bases because sometimes you need knowledge isolation between clients, locations, or even products in your RAG workflows.&lt;/p&gt;

&lt;p&gt;Imagine you manage three vacation rental properties. A guest at one of your properties texts asking how to turn on the heat, but you accidentally send them instructions for your other property's completely different thermostat. You look unprofessional, your guest is confused, and now they are cold.&lt;/p&gt;

&lt;p&gt;To handle this, we can use multiple specialized Pinecone Assistants in an n8n workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's how it works:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Guest sends a question via text/email&lt;/li&gt;
&lt;li&gt;Router identifies which property they're asking about&lt;/li&gt;
&lt;li&gt;Query gets routed to that property's dedicated assistant&lt;/li&gt;
&lt;li&gt;Assistant retrieves the answer from that property's knowledge base (house manual, appliance guides, local recs, WiFi codes)&lt;/li&gt;
&lt;li&gt;Guest gets the RIGHT answer for THEIR property&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each property has its own Pinecone Assistant node with its own knowledge base. No mixing. No confusion. No wrong answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You need separate assistants when knowledge bases can't be combined:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple vacation properties (different rules, amenities, locations)&lt;/li&gt;
&lt;li&gt;Multi-location franchises (different staff, vendors, local procedures)&lt;/li&gt;
&lt;li&gt;Agency managing multiple clients (confidential, distinct brand voices)&lt;/li&gt;
&lt;li&gt;Any scenario where "close enough" isn't good enough&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Copy this url (or the raw json), paste it into a new n8n workflow, and adapt this pattern for your own use case: &lt;code&gt;https://github.com/pinecone-io/n8n-templates/blob/main/vacation-rental-property-manager-assistants/vacation-rental-property-manager-assistants.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What would you build with this?&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready for more?
&lt;/h2&gt;

&lt;p&gt;I hope this has been helpful. If it has, please share this with your friends 👯 or drop a comment below 💬. And if you're ready to learn more about building AI workflows in n8n or have suggestions on content that would help you, let me know.&lt;/p&gt;

&lt;p&gt;Stay tuned here for more updates or follow along with me on &lt;a href="https://www.instagram.com/jennanerdsout/" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/jennapederson/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; where I share short bits of what I'm working on and learning as I go.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>pinecone</category>
      <category>rag</category>
      <category>n8n</category>
    </item>
    <item>
      <title>Build a simple RAG workflow to chat with your docs in n8n</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Fri, 13 Feb 2026 23:00:03 +0000</pubDate>
      <link>https://dev.to/jennapederson/build-a-simple-rag-workflow-to-chat-with-your-docs-in-n8n-1e5</link>
      <guid>https://dev.to/jennapederson/build-a-simple-rag-workflow-to-chat-with-your-docs-in-n8n-1e5</guid>
      <description>&lt;p&gt;You know all that RAG complexity you hate? Gone.&lt;/p&gt;

&lt;p&gt;For the last few months, I've been exploring how people are using &lt;a href="https://n8n.io/" rel="noopener noreferrer"&gt;n8n&lt;/a&gt; and &lt;a href="https://www.pinecone.io/" rel="noopener noreferrer"&gt;Pinecone&lt;/a&gt;. I discovered that people building RAG workflows in automation tools like n8n have the same frustrations as those building with code in their apps. Choosing a chunking strategy, embedding model, and implementing vector search is hard.&lt;/p&gt;

&lt;p&gt;So I started building a ✨new n8n community node for Pinecone Assistant✨ &lt;/p&gt;

&lt;p&gt;And yesterday, it was launched into the world.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handles the entire RAG pipeline in a single node so you don't have to think about file storage, chunking your data, creating embeddings, query planning, vector search, and reranking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What you can do:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connect the Pinecone Assistant node to any n8n node, like Google Drive, Notion, or Slack, and then upload your files, and start querying immediately&lt;/li&gt;
&lt;li&gt;Build workflows to chat with your docs, surface insights from your company's proprietary data, or give AI agents accurate context to make better decisions&lt;/li&gt;
&lt;li&gt;Go from idea to working RAG workflow in minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you can focus on building what matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To try out the new Pinecone Assistant n8n node:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a Pinecone account&lt;/li&gt;
&lt;li&gt;Create an Assistant&lt;/li&gt;
&lt;li&gt;Import this workflow template by copying this url and pasting it on a new workflow canvas &lt;code&gt;https://raw.githubusercontent.com/pinecone-io/n8n-templates/refs/heads/main/assistant-quickstart/assistant-quickstart.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install the Pinecone Assistant node in n8n&lt;/li&gt;
&lt;li&gt;Add your credentials to n8n&lt;/li&gt;
&lt;li&gt;Run step 1 to upload the documents to Pinecone Assistant&lt;/li&gt;
&lt;li&gt;Start chatting with your documents in step 2&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check out the full quickstart &lt;a href="https://docs.pinecone.io/guides/assistant/quickstart/n8n-quickstart" rel="noopener noreferrer"&gt;here&lt;/a&gt; or grab some of the other templates I've created &lt;a href="https://raw.githubusercontent.com/pinecone-io/n8n-templates" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready for more?
&lt;/h2&gt;

&lt;p&gt;I hope this has been helpful. If it has, please share this with your friends 👯 or drop a comment below 💬. And if you're ready to learn more about building AI workflows in n8n or have suggestions on content that would help you, let me know.&lt;/p&gt;

&lt;p&gt;Stay tuned here for more updates or follow along with me on &lt;a href="https://www.instagram.com/jennanerdsout/" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/jennapederson/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; where I share short bits of what I'm working on and learning as I go.&lt;/p&gt;

</description>
      <category>pinecone</category>
      <category>n8n</category>
      <category>ai</category>
      <category>rag</category>
    </item>
    <item>
      <title>Setting up the Pinecone MCP server in your IDE</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Mon, 28 Apr 2025 15:00:00 +0000</pubDate>
      <link>https://dev.to/jennapederson/setting-up-the-pinecone-mcp-server-in-your-ide-8mi</link>
      <guid>https://dev.to/jennapederson/setting-up-the-pinecone-mcp-server-in-your-ide-8mi</guid>
      <description>&lt;p&gt;Want to prototype and test your Pinecone indexes, right from your IDE?&lt;/p&gt;

&lt;p&gt;In this blog post, I'll show you how to avoid the IDE-docs-console-app shuffle by adding the &lt;a href="https://docs.pinecone.io/guides/operations/mcp-server" rel="noopener noreferrer"&gt;Pinecone Developer MCP server&lt;/a&gt; to your IDE. You'll be able to search the &lt;a href="https://docs.pinecone.io/guides/get-started/overview" rel="noopener noreferrer"&gt;official Pinecone docs&lt;/a&gt; and create and manage indexes without flipping back and forth between apps.&lt;/p&gt;

&lt;p&gt;You'll need a couple bits set up first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://app.pinecone.io/organizations/-/keys" rel="noopener noreferrer"&gt;Pinecone API key&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; installed with &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;npx&lt;/code&gt; on your path&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Add the Pinecone MCP server to your IDE
&lt;/h2&gt;

&lt;p&gt;Let's connect an IDE, in my case Cursor, to the Pinecone MCP server. We'll create an &lt;code&gt;mcp.json&lt;/code&gt; file in the &lt;code&gt;.cursor&lt;/code&gt; directory, paste in the code below, and replace &lt;code&gt;YOUR_PINECONE_API_KEY&lt;/code&gt; with your Pinecone API key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pinecone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@pinecone-database/mcp"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"PINECONE_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_PINECONE_API_KEY"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Check the config status
&lt;/h2&gt;

&lt;p&gt;We'll now check the config status in Cursor to make sure it is connected to the server and the tools are available. Notice how the connection status turns green when connected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqfuhajj65jthhe2guvd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqfuhajj65jthhe2guvd.png" alt="Cursor config screen for MCP Servers, showing the Pinecone MCP server is connected and listing it's tools." width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the Pinecone rules for Cursor
&lt;/h2&gt;

&lt;p&gt;Next, we'll add these extra special Pinecone rules for Cursor, to guide it to even better results, making sure it's using the latest stable version of the Pinecone SDK and searches the official docs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### Tool Usage for Code Generation

- When generating code related to Pinecone, always use the `pinecone` MCP and the `search_docs` tool.

- Perform at least two distinct searches per request using different, relevant questions to ensure comprehensive context is gathered before writing code.

### Error Handling

- If an error occurs while executing Pinecone-related code, immediately invoke the `pinecone` MCP and the `search_docs` tool.

- Search for guidance on the specific error encountered and incorporate any relevant findings into your resolution strategy.

### Syntax and Version Accuracy

- Before writing any code, verify and use the correct syntax for the latest stable version of the Pinecone SDK.

- Prefer official code snippets and examples from documentation over generated or assumed field values.

- Do not fabricate field names, parameter values, or request formats.

### SDK Installation Best Practices

- When providing installation instructions, always reference the current official package name.

- For Pinecone, use `pip install pinecone` not deprecated packages like `pinecone-client`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can customize this to your own situation, depending on how you work. I've set mine to &lt;code&gt;Agent Requested&lt;/code&gt; and given it a description of &lt;code&gt;Used when generating code related to Pinecone&lt;/code&gt; so the agent knows when to include the rule. You can read more about this &lt;a href="https://docs.cursor.com/context/rules" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;p&gt;Here's the best part - creating and testing your first Pinecone index right in your IDE. I use this prompt to build an index based on Last of Us storylines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a Pinecone dense index named "pinecone-mcp-demo-dense" that uses `llama-text-embed-v2`. Generate 10 records of test data based on the tv series The Last of Us and their characters and upsert it into the index.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Cursor agent knows to make the call to the Pinecone MCP server to create the index and then to search records.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fb3x776fz0dpfhxfw8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fb3x776fz0dpfhxfw8j.png" alt="Cursor agent chat showing the prompt and some of the output with calls to the MCP server." width="800" height="1028"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This feedback loop lets me quickly iterate on config, test data, and vector search.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And yes, I'm currently watching the Last of Us, so no spoilers!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that I've prototyped and tested my index, I can start building my app, using the Pinecone MCP tools to search the docs, manage my test data, all right from my IDE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;If you'd like to check out how to configure the Pinecone MCP server with other IDEs, check out this &lt;a href="https://docs.pinecone.io/guides/operations/mcp-server" rel="noopener noreferrer"&gt;guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this has been helpful! If you have feedback or want to share how you're using the Pinecone MCP server in your development workflow, drop a note in the comments.&lt;/p&gt;

</description>
      <category>pinecone</category>
      <category>mcp</category>
      <category>vectordatabase</category>
      <category>ai</category>
    </item>
    <item>
      <title>A conversation with your architecture</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Wed, 18 Dec 2024 18:00:00 +0000</pubDate>
      <link>https://dev.to/aws/a-conversation-with-your-architecture-2mn</link>
      <guid>https://dev.to/aws/a-conversation-with-your-architecture-2mn</guid>
      <description>&lt;p&gt;Over the course of my career I have worked on a number of sprawling software systems. One tool that has been invaluable during my time as a software engineer is the use of software and architecture diagrams. But one pain point I always have with diagrams is that they are almost always complex, with a lot of detail, and coming into an existing system I need to be able to get up to speed quickly. In this article, I will show you the value of software and architecture diagrams, challenges we face with them, and how I’m using generative AI to better understand diagrams, gain deeper insights, make decisions, generate diagrams, and even generate infrastructure code.&lt;/p&gt;

&lt;p&gt;Let’s get started. &lt;/p&gt;

&lt;h3&gt;
  
  
  Why diagrams are important
&lt;/h3&gt;

&lt;p&gt;Software and architecture diagrams are critical tools as they help developers and stakeholders understand complex systems.&lt;/p&gt;

&lt;p&gt;A diagram can help bridge the gap between technical and non-technical stakeholders. With a common visual language, a diagram can communicate complex relationships and details better than pages of text can. They can help us see the big picture so we can better understand how various parts of a system work together or what will be impacted with changes.&lt;/p&gt;

&lt;p&gt;All of this helps us plan for the future, identify risks and dependencies, and make informed decisions.&lt;/p&gt;

&lt;p&gt;Different types of diagrams also have different purposes. With class diagrams you have a blueprint for implementation and can visualize inheritance and composition relationships better. Sequence diagrams help you understand the flow and how objects interact over time.&lt;/p&gt;

&lt;p&gt;Together, the various types of diagrams give a comprehensive view of a system. But they can also pose some challenges&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenges with diagrams
&lt;/h3&gt;

&lt;p&gt;There are a number of challenges with software and architecture diagrams but a couple that are top of mind for me are how quickly they can become complex and how easily they become out of date. &lt;/p&gt;

&lt;p&gt;It’s important to make sure your diagram has the right level of detail for its purpose and audience. Too much detail and they become overwhelming. Too little detail and you don’t have the right information to make a decision. It is a fine balance and takes practice. &lt;/p&gt;

&lt;p&gt;Diagrams are also as of a point in time and if they are not maintained over time, they won’t reflect reality, making it harder to get accurate insights and make decisions.&lt;/p&gt;

&lt;p&gt;There are approaches and tools to manage some of these challenges but today I want to show how using generative AI can help you to better understand diagrams, gain deeper insights, make decisions, generate diagrams, and even generate infrastructure code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's have a conversation with our architecture
&lt;/h3&gt;

&lt;p&gt;What if we could have a conversation with our diagrams? What if we could understand it quicker, get custom recommendations for &lt;strong&gt;our&lt;/strong&gt; system, use real-time data and best practices from &lt;strong&gt;our&lt;/strong&gt; company, and even generate new and updated diagrams?&lt;/p&gt;

&lt;p&gt;We can.&lt;/p&gt;

&lt;p&gt;I’m going to show you how using a &lt;a href="https://github.com/build-on-aws/conversation-with-your-architecture" rel="noopener noreferrer"&gt;demo app&lt;/a&gt; I built with Python using the Amazon Bedrock Converse API. This will let us carry out a conversation, back and forth, between a large language model and the user. We’ll incorporate tool use to get access to real-time data and a knowledge base to pull in data from our company’s custom best practices. &lt;/p&gt;

&lt;h4&gt;
  
  
  Try it yourself
&lt;/h4&gt;

&lt;p&gt;If you’d like to grab the code and run through this yourself with your own diagram or see how it was implemented, you can get it &lt;a href="https://github.com/build-on-aws/conversation-with-your-architecture" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Clone the repo, make sure you're set up with an AWS account, have access to the Claude Sonnet 2.5 model on Amazon Bedrock, and have Python 3.10.16 or later installed. &lt;/p&gt;

&lt;h4&gt;
  
  
  A simple serverless example
&lt;/h4&gt;

&lt;p&gt;We’ll start with this diagram that visualizes a simple serverless application that generates joy from fluffy puppy memes. Very important business!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzovnicm8ele67wvfp12g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzovnicm8ele67wvfp12g.png" alt="Architecture diagram" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This app runs at the command line. Once we’ve started it up, we enter the diagram we want to analyze and our first query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List the AWS Services used in the architecture diagram by official AWS name and excluding any sub-titles.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Certainly! I'll analyze the architecture diagram in the image "demo/fluffy-puppy-joy-generator.png" and list the AWS services used by their official AWS names, excluding any subtitles. Here's the list:

1. Amazon S3 (Simple Storage Service)
2. Amazon Rekognition
3. AWS Lambda
4. Amazon CloudFront

These are the four distinct AWS services that are clearly identifiable in the architecture diagram for the Fluffy Puppy Joy Generator application.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could then ask follow up questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are the recommended strategies for unit testing this architecture?&lt;/li&gt;
&lt;li&gt;How well does this architecture adhere to the AWS Well Architected Framework?&lt;/li&gt;
&lt;li&gt;What improvements should be made to the resiliency of this architecture?&lt;/li&gt;
&lt;li&gt;Convert the data flow from this architecture into a Mermaid formatted sequence diagram.&lt;/li&gt;
&lt;li&gt;What are the quotas or limits in this architecture?&lt;/li&gt;
&lt;li&gt;Can you generate the CloudFormation code to provision this architecture?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach uses the Amazon Bedrock Converse API to have a conversation with an LLM. This API maintains the chat history as context for the future conversation. You can read more about how this works in my past blog post &lt;a href="https://community.aws/content/2jPc4jOx6IHwWhq60PmSxUNycVm/telling-bedtime-stories-with-generative-ai" rel="noopener noreferrer"&gt;here&lt;/a&gt;. This conversation is limited to the training data for the model we have selected (in this case, Claude Sonnet 3.5).&lt;/p&gt;

&lt;h4&gt;
  
  
  Retrieving real-time data with a tool
&lt;/h4&gt;

&lt;p&gt;But what if we wanted to ask more specific questions about this system? For instance, what if we wanted to know how much joy is being generated by this system? We could ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is the joy count of the current system?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to support questions like this that get at real-time data, we'll need to use a tool with Amazon Bedrock. In this app, we have a tool called &lt;code&gt;joy_count_tool.py&lt;/code&gt; that can retrieve the current, up-to-date joy count from the system via an API (our implementation retrieves it from a JSON file for simplicity). During the conversation, the model detects that a tool is needed, replies back to our app with which specific tool to use, and then our app uses the tool to retrieve the joy count. This data is then passed back to the model and a natural language response incorporating the joy count is returned to our app. You can read more about how tool use works with Amazon Bedrock in my past blog post &lt;a href="https://community.aws/content/2mrgQfIpmQ1Cg6rQzO2B3xMR8Tm/bridging-ai-and-real-time-data-with-tools" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Incorporating custom data with an Amazon Bedrock Knowledge Base
&lt;/h4&gt;

&lt;p&gt;Knowing the joy count is helpful, but how do we even know if this number is good or bad? How do we know if it adheres to our company's best practices? We could ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Is a joy count of 189 good or bad?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With an output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Thank you for providing that information. Now I can assess whether the current joy count is good or bad based on the company's best practices.

According to the best practices for the Fluffy Puppy Joy Generator system, the joy count is evaluated on the following scale:

- Joy Count 1-100: Bad
- Joy Count 101-200: OK
- Joy Count 201-300: Good
- Joy Count 301-400: Better
- Joy Count 401+: Best

The current joy count of 189 falls within the "OK" range (101-200). This means that the application is generating some joy, but there is still room for improvement. 

To elaborate:

1. The system is performing adequately, as it's not in the "Bad" category.
2. However, it hasn't yet reached the "Good" level, which starts at 201.
3. There's significant potential for enhancement to move into the higher categories.

The best practices suggest that when the joy count is in this range, more work is required to improve the experience. This could involve:

1. Refining the meme generation algorithms
2. Improving content selection
3. Optimizing distribution strategies

To boost the joy count and move into the "Good" or better categories, the team should focus on these areas of improvement. Regular reviews of the joy count and implementing updates to the system components are recommended to maintain and increase the level of joy generation.

In summary, while the current joy count of 189 is not bad, it indicates that the Fluffy Puppy Joy Generator has room for improvement to reach its full potential in spreading puppy-related joy to users.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To support a question like this, we use an Amazon Bedrock Knowledge Base to provide contextual information to the model. In this case, we have a knowledge base using an Amazon S3 bucket as a data source. This bucket contains data about our company's best practices. We use the Amazon Titan Text Embeddings v2 model with an Amazon OpenSearch Serverless vector store. You can read more about setting up an Amazon Bedrock Knowledge Base in my coworker's blog post &lt;a href="https://community.aws/content/2e3IcBfX4bmhAHVtd6PyIV5H57F/i-built-an-ai-landmark-recommender-for-visiting-new-cities" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This may be a trivial example, but this means we can bring real-time data into our app and gather insights based on our own internal data, like our company's best practices or policies and then generate a natural language response incorporating that data. Then we could ask questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are all our AWS resources properly configured according to our company's compliance requirements?&lt;/li&gt;
&lt;li&gt;Does this architecture adhere to our company best practices?&lt;/li&gt;
&lt;li&gt;Does this class diagram adhere to our naming best practices?&lt;/li&gt;
&lt;li&gt;Where are the current bottlenecks in this system? &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Again, the Fluffy Puppy Joy Generator is only a trivial example but using generative AI as another tool in our toolbox with diagrams opens up more possibilities for visualizing our systems, making decisions, implementation, and getting customers using our software earlier. &lt;/p&gt;

&lt;h3&gt;
  
  
  Where we go from here
&lt;/h3&gt;

&lt;p&gt;Now that we’ve covered how generative AI can help with these challenges, I want to leave you with some hands-on assets to work with your own architecture diagrams. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the code, tweak it to your use case or analyze your own diagram &lt;a href="https://github.com/build-on-aws/conversation-with-your-architecture/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Work through the workshop, &lt;a href="https://catalog.workshops.aws/generative-ai-architecture-diagrams" rel="noopener noreferrer"&gt;Harnessing generative AI to create and understand architecture diagrams&lt;/a&gt; that I co-led at re:Invent 2024.&lt;/li&gt;
&lt;li&gt;Read how Olivier Lemaitre, AWS User Group leader, goes &lt;a href="https://dev.to/welcloud-io/from-diagram-to-code-with-amazon-q-developer-2da4"&gt;from diagram to code with Amazon Q Developer&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this has been helpful. If you'd like more like this, smash that like button 👍, share this with your friends 👯, or drop a comment below 💬 about how you're using generative AI with diagrams. You can also find my other content like this on &lt;a href="https://www.instagram.com/jennanerdsout/" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/jennapederson/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, and &lt;a href="https://www.youtube.com/@JennaPederson" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ai</category>
      <category>architecture</category>
    </item>
    <item>
      <title>What I learned while building my first game</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Tue, 05 Nov 2024 13:00:00 +0000</pubDate>
      <link>https://dev.to/aws/what-i-learned-while-building-my-first-game-1li6</link>
      <guid>https://dev.to/aws/what-i-learned-while-building-my-first-game-1li6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This post was inspired by the &lt;a href="https://awsdevchallenge.devpost.com/" rel="noopener noreferrer"&gt;AWS Game Builder Challenge&lt;/a&gt;. Create a game with AWS services of your choosing: all skill levels welcome!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My family is a game family. Board games, murder mystery party games, escape rooms, game shows, game nights. One of my favorite game shows is Password and I used it as inspiration to create the Cloud Password Game for the &lt;a href="https://awsdevchallenge.devpost.com/" rel="noopener noreferrer"&gt;AWS Game Builder Challenge&lt;/a&gt; running through the month of November.&lt;/p&gt;

&lt;p&gt;In this blog post, I'm going to share about building the game and what I learned along the way. Just want the code? Grab it &lt;a href="https://github.com/jennapederson/cloud-password-game" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's check it out!&lt;/p&gt;

&lt;h2&gt;
  
  
  The game
&lt;/h2&gt;

&lt;p&gt;With the Cloud Password Game, I wanted to test my own cloud and AWS knowledge and I wanted to do that by presenting a secret word, known as the password, and offering one-word clues to guess that password. For every password you guess correctly, you get a point.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgeuzhvrek69yq1o0gss5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgeuzhvrek69yq1o0gss5.png" alt="Screenshot of the Cloud Password Game UI" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the game
&lt;/h2&gt;

&lt;p&gt;This game is built and deployed with AWS Amplify and uses the Amazon Bedrock Converse API to generate the password and clues. I'm not going to cover every step for getting this set up and deployed with Amplify because there is a fantastic &lt;a href="https://docs.amplify.aws/react/start/quickstart/" rel="noopener noreferrer"&gt;getting started guide&lt;/a&gt;.  I’ve also showed how to use the Amazon Bedrock Converse API in &lt;a href="https://community.aws/content/2jPc4jOx6IHwWhq60PmSxUNycVm/telling-bedtime-stories-with-generative-ai" rel="noopener noreferrer"&gt;past blog posts&lt;/a&gt; so we won't go into that detail here. &lt;/p&gt;

&lt;p&gt;But I am using a new (to me) model, the &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/titan-text-models.html#titantx-premier" rel="noopener noreferrer"&gt;Amazon Titan Text G1 - Premier model&lt;/a&gt;, and this required me to learn more about prompt engineering for Titan text models.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt engineering
&lt;/h3&gt;

&lt;p&gt;I quickly discovered there is no support for a system prompt when using the Titan text models, but in talking with my coworkers about this, I learned that's actually ok. I can incorporate that context into the user prompt instead. I started digging through the &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/titan-text-models.html" rel="noopener noreferrer"&gt;Amazon Titan Text models documentation&lt;/a&gt; and discovered this helpful &lt;a href="https://d2eo22ngex1n9g.cloudfront.net/Documentation/User+Guides/Titan/Amazon+Titan+Text+Prompt+Engineering+Guidelines.pdf" rel="noopener noreferrer"&gt;prompt engineering guide&lt;/a&gt; specifically for Titan text models.&lt;/p&gt;

&lt;h4&gt;
  
  
  Building the initial prompt
&lt;/h4&gt;

&lt;p&gt;I started with a persona, &lt;code&gt;an expert AWS and cloud word game show host&lt;/code&gt; and set the stage for the conversation between user and bot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Act like you are an expert AWS and cloud word game show host who generates a secret word and one-word clues to guess that word. The user will only respond with a guess.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, I added specific instructions in bulleted list format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Instructions:
- The secret word should be 1-4 words long
- The secret word should be based on AWS service names
- Do NOT obfuscate the secret word in the output
- The clues you generate will represent the secret word
- The clues MUST be only one word long
- The clues should start out difficult and get increasingly easier over time
- You MUST ONLY share one clue at a time
- ALWAYS generate a new, unique clue
- NEVER generate a clue that is one of the past guesses
- Generate a clue during every interaction
- You MUST answer in JSON format only
- DO NOT use any other format while answering the question
- DO NOT include any additional explanation or information in the JSON output or after the JSON output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I included the rules around how to generate both the secret word and the clues and how to respond, in JSON format only. I've added some emphasis for some words like MUST, NEVER, DO NOT so that the model will strictly obey.&lt;/p&gt;

&lt;p&gt;Notice that I also referred to the password as &lt;code&gt;secret word&lt;/code&gt; throughout this prompt. I found that there was a lot of confusion about this being a real password that couldn't be revealed for security reasons and so that's why there is an instruction to not obfuscate the secret word and no reference to the word &lt;code&gt;password&lt;/code&gt;. Clear, concise, and specific it is!&lt;/p&gt;

&lt;p&gt;Then, I added more detail on how to format the output. In addition to the instructions above about formatting the output in JSON, I also included the specific output format so that I could parse it on the other end.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Please follow the output schema as shared below.
Output Schema:
{
  “word”: "the secret word to guess",
  “clue”: "clue1"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also added an example of what I expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Example:
{
  “word”: “AWS”,
  “clue”: “cloud"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One road bump I ran into with the output format and example were that in the prompt engineering guide linked above, it showed the JSON format with backticks, which I understood to mean I should also include them. This created chaos, with the model responding with extra explanations and context AFTER the JSON output I tried to ask for. It took a long while to discover this issue, but once I removed this everything was hunky dory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```json
{{json content}}
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then the final ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate the secret word and the first clue.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of the strategies in the prompt engineering guide linked above was to use &lt;code&gt;User:&lt;/code&gt; and &lt;code&gt;Bot:&lt;/code&gt; to indicate the turn-by-turn conversation flow. I experimented with this early on as I was building this prompt and the model often got confused on what needed to happen next. I suspect this was because I didn't have specific enough instructions early on. I may revisit this in a future version but for now, this works and you can see the final prompt below.&lt;/p&gt;

&lt;h3&gt;
  
  
  My final prompt
&lt;/h3&gt;

&lt;p&gt;Here is the final prompt to initialize the game with a password and the first clue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Act like you are an expert AWS and cloud word game show host who generates a secret word and one-word clues to guess that word. The user will only respond with a guess.

Follow the instructions when responding.
Instructions:
- The secret word should be 1-4 words long
- The secret word should be based on AWS service names
- Do NOT obfuscate the secret word in the output
- The clues you generate will represent the secret word
- The clues MUST be only one word long
- The clues should start out difficult and get increasingly easier over time
- You MUST ONLY share one clue at a time
- ALWAYS generate a new, unique clue
- NEVER generate a clue that is one of the past guesses
- Generate a clue during every interaction
- You MUST answer in JSON format only
- DO NOT use any other format while answering the question
- DO NOT include any additional explanation or information in the JSON output or after the JSON output

Please follow the output schema as shared below.
Output Schema:
{
  “word”: "the secret word to guess",
  “clue”: "clue1"
}

Example:
{
  “word”: “AWS”,
  “clue”: “cloud"
}

Generate the secret word and the first clue.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I used this follow up prompt when submitting a guess:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My guess is: {guess}

Generate the next clue. DO NOT change the secret word. DO NOT use any of the past clues.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I gave it some context (the guess) and the instructions. Sometimes the secret word was changing and occasionally past clues were being reused, so I added a nice little reminder.&lt;/p&gt;

&lt;p&gt;Next, I had to code this up in my web app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assistance while coding
&lt;/h3&gt;

&lt;p&gt;As I mentioned earlier, I used AWS Amplify and the Amazon Bedrock Converse API to implement this game. As we all do, I ran into road bumps as I wrote my code and I want to share how I handled them. I've written before about my experience using generative AI and more specifically Amazon Q Developer to support my development workflow (&lt;a href="https://community.aws/content/2gQKqKLQqKmlvFsnp4zuCENKW8i/i-m-a-lazy-developer-here-s-how-amazon-q-is-enabling-me" rel="noopener noreferrer"&gt;here&lt;/a&gt;, &lt;a href="https://community.aws/content/2i1vLMdryliLgpdceMy2N6o2LPn/a-practical-approach-to-using-generative-ai-in-the-sdlc" rel="noopener noreferrer"&gt;here&lt;/a&gt;, &lt;a href="https://community.aws/content/2ihDE9A59SAbHwUqkLWhyl78Eax/simplify-your-unit-testing-with-generative-ai" rel="noopener noreferrer"&gt;here&lt;/a&gt;, and &lt;a href="https://community.aws/content/2ihRGejp90hD6Cwxq5YO9czEMMM/how-an-ai-coding-companion-keeps-my-code-dry" rel="noopener noreferrer"&gt;here&lt;/a&gt;). While I used those tools throughout building this app, what I found most interesting was a new addition to Amazon Q Developer: the CMD+i keyboard shortcut, also known as inline chat.&lt;/p&gt;

&lt;p&gt;During my coding, I often run up against a question about syntax, how to express some logic in a simple way, want to refactor a block of code, or generate a small snippet of code. Normally, I just forge ahead or more recently I would head over to the Amazon Q Developer chat pane and type out my query, and then copy/paste the results. But while I was building this app out, I used inline chat to assist me. I simplified blocks of code, figured out how to compare the lowercased version of two string values (because apparently my IDE was flagging what I originally wrote as incorrect), printed out the entire contents of the &lt;code&gt;conversation&lt;/code&gt; variable to the console, and made an interpolated string compile. I really did ask "How can I make this compile?" and it gave me an updated version. Turns out there were a bunch of back ticks that needed to be escaped.&lt;/p&gt;

&lt;p&gt;Here's how inline chat works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the block of code you want to work with&lt;/li&gt;
&lt;li&gt;Press ⌘ + i on Mac or Ctrl + i on Windows, in VSCode or JetBrains&lt;/li&gt;
&lt;li&gt;Type out your prompt and press Enter&lt;/li&gt;
&lt;li&gt;Amazon Q Developer will generate a diff inline with your existing code that you can accept or reject.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's what it looks like after selecting the code and triggering the inline chat:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0ud59rgwtt9zi63ec5m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0ud59rgwtt9zi63ec5m.png" alt="Screenshot of selected text and inline chat prompt" width="800" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then to accept/reject the suggestion:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbsh2ud66u2dfw6cmbk3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbsh2ud66u2dfw6cmbk3.png" alt="Screenshot showing the suggestion and how to accept or reject the suggestion" width="800" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's really nice here is that I don't have to flip back and forth between the Amazon Q Developer chat pane and my code, copying over updated code snippets. I get to stay right in the text editor pane as I type out my code. This functionality shines with code updates (like refactoring or helping fix a bug in a block of code), but it also supports code additions, too.&lt;/p&gt;

&lt;p&gt;Check out more uses cases &lt;a href="https://aws.amazon.com/blogs/devops/amazon-q-developer-inline-chat/" rel="noopener noreferrer"&gt;here&lt;/a&gt; on how inline chat works.&lt;/p&gt;

&lt;h3&gt;
  
  
  For the future
&lt;/h3&gt;

&lt;p&gt;This isn't perfect and there are definitely improvements we could make for the future. Here's what I might think about for next time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding authentication (set up Amplify Auth with Cognito &lt;a href="https://docs.amplify.aws/react/build-a-backend/auth/set-up-auth/" rel="noopener noreferrer"&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A leaderboard to track scores against other users&lt;/li&gt;
&lt;li&gt;Refining the prompt for better passwords and clues&lt;/li&gt;
&lt;li&gt;Updating the UI (it's pretty basic)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;In this post, you learned about how to craft a prompt for the Amazon Titan Text models, how to use Amazon Q Developer's new inline chat feature. You can grab the code for this game app &lt;a href="https://github.com/jennapederson/cloud-password-game" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The AWS Game Builder Challenge runs through November and you can build your own game. Check out the details of the hackathon &lt;a href="https://awsdevchallenge.devpost.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Haven't tried Amazon Q Developer yet? Get started with a Builder ID &lt;a href="https://community.aws/builderid?trk=6f73c382-82fb-4650-936e-89cc26f49b15&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this has been helpful. If you'd like more like this, smash that like button 👍, share this with your friends 👯, or drop a comment below 💬. You can also find my other content like this on &lt;a href="https://www.instagram.com/jennanerdsout/" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt; and &lt;a href="https://www.youtube.com/@JennaPederson" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>genai</category>
    </item>
    <item>
      <title>Bridging AI and real-time data with tools</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Wed, 02 Oct 2024 19:03:00 +0000</pubDate>
      <link>https://dev.to/aws/bridging-ai-and-real-time-data-with-tools-5e0m</link>
      <guid>https://dev.to/aws/bridging-ai-and-real-time-data-with-tools-5e0m</guid>
      <description>&lt;p&gt;Have you ever wondered why you can chat with an LLM about how to solve math problems but they struggle with actual mathematical calculations? Or why they cannot reliably provide up to date information? LLMs are trained on text and they learn to predict patterns in that text. They don't have a built in calculator, so they can only approximate based on patterns they've seen, leading to errors especially with large numbers or complex calculations. The text they're trained on is also at a point in time, so asking about the current weather or today's stock prices would only be as current as the training data.&lt;/p&gt;

&lt;p&gt;Many times, though, we'll need to augment LLM responses with real-time data from external tools and APIs. One way we can do this, is using an LLM feature called tool use (or function calling) to give them their own set of tools to use. Tool use can be applied to fetch real-time data from a database or inventory system, stock prices, weather forecasts, or even your cloud resources.&lt;/p&gt;

&lt;p&gt;In this blog post, I'm going to show you how to integrate fetching real-time data from a weather API so you can interact with real-time data using natural language. We'll implement this in Python and using &lt;a href="https://aws.amazon.com/bedrock/" rel="noopener noreferrer"&gt;Amazon Bedrock's&lt;/a&gt; Converse API, we'll define a tool for our AI to use when requested. This creates a seamless interaction between AI and a custom function, allowing us to combine the strengths of both.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To work through this example, you'll need a few bits set up first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account. You can create your account &lt;a href="https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Request access to an AI model (we'll use Claude Sonnet) on Amazon Bedrock before you can use it. Learn about model access &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.python.org/" rel="noopener noreferrer"&gt;Python 3.6.0 or later&lt;/a&gt; setup and configured on your system.&lt;/li&gt;
&lt;li&gt;A python virtual environment setup with packages installed via &lt;a href="https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/python/example_code/bedrock-runtime/requirements.txt" rel="noopener noreferrer"&gt;requirements.txt&lt;/a&gt;. Read more about doing this &lt;a href="https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/python/example_code/bedrock-runtime/README.md#prerequisites" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just want the code? Grab it &lt;a href="https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/bedrock-runtime/cross-model-scenarios/tool_use_demo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Setup
&lt;/h2&gt;

&lt;p&gt;First, we'll set up the system prompt and the tool configuration for our tool.&lt;/p&gt;

&lt;p&gt;The system prompt tells the model that it should use a tool in a specific situation -- when providing current weather data, use the Weather_Tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#
# Step 1: Define system prompt that requires the use of the tool
#
&lt;/span&gt;&lt;span class="n"&gt;SYSTEM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are a weather assistant that provides current weather data for user-specified locations using only
the Weather_Tool, which expects latitude and longitude. Infer the coordinates from the location yourself.
If the user provides coordinates, infer the approximate location and refer to it in your response.
To use the tool, you strictly apply the provided tool specification.

- Explain your step-by-step process, and give brief updates before each step.
- Only use the Weather_Tool for data. Never guess or make up information. 
- Repeat the tool use for subsequent requests if necessary.
- If the tool errors, apologize, explain weather is unavailable, and suggest other options.
- Report temperatures in °C (°F) and wind in km/h (mph). Keep weather reports concise. Sparingly use
  emojis where appropriate.
- Only respond to weather queries. Remind off-topic users of your purpose. 
- Never claim to search online, access external data, or use tools besides Weather_Tool.
- Complete the entire process until you have all required data before sending the complete response.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we define the specification for our weather tool using the Converse API tool definition format. We describe the weather tool and defining the inputs so that the model knows how to interact with it. In this case, the tool expects a latitude and longitude of a location.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#
# Step 2: Define weather tool using the Converse API tool definition format
#
&lt;/span&gt;&lt;span class="n"&gt;WEATHER_TOOL_SPEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;toolSpec&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Weather_Tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Get the current weather for a given location, based on its WGS84 coordinates.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inputSchema&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Geographical WGS84 latitude of the location.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Geographical WGS84 longitude of the location.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Implement the tool
&lt;/h2&gt;

&lt;p&gt;Next, we'll implement the tool. This is where we'll make an API call to the &lt;a href="https://open-meteo.com/" rel="noopener noreferrer"&gt;Open-Meteo API&lt;/a&gt; to retrieve the current weather for a given location.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#
# Step 3: Implement the weather tool function
#
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_weather_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Fetches weather data for the given latitude and longitude using the Open-Meteo API.
    Returns the weather data or an error message if the request fails.

    :param input_data: The input data containing the latitude and longitude.
    :return: The weather data or an error message.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.open-meteo.com/v1/forecast&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;latitude&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;longitude&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_weather&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;weather_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weather_data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;weather_data&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;RequestException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Send conversation to Amazon Bedrock
&lt;/h2&gt;

&lt;p&gt;To send the conversation to Amazon Bedrock, we first create a conversation array with our initial user prompt. In the &lt;a href="https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/bedrock-runtime/cross-model-scenarios/tool_use_demo" rel="noopener noreferrer"&gt;example code repo&lt;/a&gt;, you can see how you might collect this directly from the user interactively.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#
# Step 4: Define the initial message and conversation
#
&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;initial_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is the current weather in Minneapolis, MN?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we make the &lt;code&gt;converse&lt;/code&gt; call, sending along the model, conversation, tool config, and our system prompt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#
# Step 5: Send the message with the tool config and system prompt
#
&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bedrock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;converse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;modelId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MODEL_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inferenceConfig&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxTokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;toolConfig&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;WEATHER_TOOL_SPEC&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SYSTEM_PROMPT&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Process the response and call the tool
&lt;/h2&gt;

&lt;p&gt;Once we have a response from Amazon Bedrock, we have to process the response. We'll check to see if a tool is being requested (&lt;code&gt;toolUse&lt;/code&gt; is returned) and if so, we call the requested tool.&lt;/p&gt;

&lt;p&gt;With a result from the tool, the &lt;code&gt;fetch_weather_data&lt;/code&gt; function, we then prepare a &lt;code&gt;toolResult&lt;/code&gt; to send back to Amazon Bedrock for further processing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#
# Step 6: Process the response and call the tool when requested
#
&lt;/span&gt;&lt;span class="n"&gt;response_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;response_content_blocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response_message&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;follow_up_content_blocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;content_block&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response_content_blocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;content_block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content_block&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;toolUse&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;content_block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;tool_use_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content_block&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;toolUse&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;tool_use_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tool_use_block&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tool_use_name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Weather_Tool&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;tool_result_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_weather_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_use_block&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="n"&gt;follow_up_content_blocks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;toolResult&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;toolUseId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tool_use_block&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;toolUseId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tool_result_value&lt;/span&gt;
                        &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="c1"&gt;# Handle unknown tools
&lt;/span&gt;      &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;follow_up_content_blocks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;toolResult&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;toolUseId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tool_use_block&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;toolUseId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tool_use_name&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Send the tool result back to Amazon Bedrock
&lt;/h2&gt;

&lt;p&gt;With the &lt;code&gt;toolResult&lt;/code&gt; containing the current weather data, we now send this to Amazon Bedrock so we can get the final natural language response from the model incorporating the tool result -- the current weather.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#
# Step 7: Send tool result back to Amazon Bedrock
#
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;follow_up_content_blocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;follow_up_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;follow_up_content_blocks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;follow_up_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bedrock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;converse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;modelId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MODEL_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;inferenceConfig&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxTokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;toolConfig&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;WEATHER_TOOL_SPEC&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SYSTEM_PROMPT&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response_message&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the code
&lt;/h2&gt;

&lt;p&gt;Finally, we're ready to run the code and find the current weather for a location through natural language conversations. Run the following at the command line or in your IDE:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python weather_tool_use_demo.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output we get is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Okay, &lt;span class="nb"&gt;let &lt;/span&gt;me check the current weather conditions &lt;span class="k"&gt;for &lt;/span&gt;Minneapolis, MN using the Weather Tool.

First, I&lt;span class="s1"&gt;'ll need to get the latitude and longitude coordinates for Minneapolis:
Minneapolis, MN coordinates: 44.9778°N, 93.2650°W

Next, I'&lt;/span&gt;ll invoke the Weather Tool with those coordinates:
Here is the current weather report &lt;span class="k"&gt;for &lt;/span&gt;Minneapolis, MN:

The temperature is 17.9°C &lt;span class="o"&gt;(&lt;/span&gt;64.2°F&lt;span class="o"&gt;)&lt;/span&gt; with a partly cloudy sky. Winds are blowing from the west-northwest at 19.8 km/h &lt;span class="o"&gt;(&lt;/span&gt;12.3 mph&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; ☁️ 🍃

Let me know &lt;span class="k"&gt;if &lt;/span&gt;you need any other weather details &lt;span class="k"&gt;for &lt;/span&gt;Minneapolis!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;In this post, you learned why LLMs struggle to make complex calculations and provide real-time information. I showed one approach for augmenting your LLM responses with data from external tools and APIs -- tool use (or function calling). Then, I showed how to implement this in Python with Amazon Bedrock's Converse API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other helpful resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/bedrock-runtime/cross-model-scenarios/tool_use_demo" rel="noopener noreferrer"&gt;The code repo for this article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.instagram.com/p/C__fGWryV4D/" rel="noopener noreferrer"&gt;Exploring tool use with Amazon Bedrock (Instagram)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.aws/content/2hW5367isgQOkkXLYjp4JB3Pe16/intro-to-tool-use-with-the-amazon-bedrock-converse-api?lang=en" rel="noopener noreferrer"&gt;Intro to Tool Use with the Amazon Bedrock Converse API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/developer/code-examples/?code-examples-all.sort-by=item.additionalFields.category&amp;amp;code-examples-all.sort-order=desc&amp;amp;awsf.sdk-code-examples-programming-language=programming-language%23python&amp;amp;awsf.sdk-code-examples-type=*all&amp;amp;awsf.sdk-code-samples-tech-category=*all&amp;amp;awsf.sdk-code-examples-product=product%23bedrock" rel="noopener noreferrer"&gt;Other Python examples for Amazon Bedrock&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this has been helpful. If you'd like more like this, smash that like button 👍, share this with your friends 👯, or drop a comment below 💬.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aws</category>
    </item>
    <item>
      <title>Telling bedtime stories with generative AI</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Thu, 15 Aug 2024 13:00:00 +0000</pubDate>
      <link>https://dev.to/aws/telling-bedtime-stories-with-generative-ai-2dba</link>
      <guid>https://dev.to/aws/telling-bedtime-stories-with-generative-ai-2dba</guid>
      <description>&lt;p&gt;I read to my kid a lot. To be clear, I read one or two books a lot to my kid. To the point that I have the words to both books memorized. What if we could create our own story, together, to tell a new story each night with new characters? In this article, I will show how we can use an AI chat integration and customize it to act as an interactive bedtime storyteller. With this approach, you could build a personalized meal planner, a travel guide, or an assistant to help you ideate and refine your social media copy.&lt;/p&gt;

&lt;p&gt;Let's first check out the high-level solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our solution
&lt;/h2&gt;

&lt;p&gt;I'm working within a React app built and deployed with AWS Amplify. If you'd like to start here, you can spin up the sample app using this quickstart &lt;a href="https://docs.amplify.aws/react/start/quickstart/" rel="noopener noreferrer"&gt;guide&lt;/a&gt; and then incorporate the code I share.&lt;/p&gt;

&lt;p&gt;We'll use &lt;a href="https://aws.amazon.com/bedrock/" rel="noopener noreferrer"&gt;Amazon Bedrock&lt;/a&gt; as a datasource and make a custom query to generate a story using the new Converse API. The Converse API will allow us to handle multi-turn conversations and maintain a conversation history. We'll go a step further, utilizing the &lt;code&gt;systemPrompt&lt;/code&gt; feature to provide context, instructions, and guidelines on how it should respond.&lt;/p&gt;

&lt;p&gt;The example code below is Typescript, but you can also find sample code for other languages &lt;a href="https://community.aws/code/generative-ai" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's get started building!&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a data source
&lt;/h2&gt;

&lt;p&gt;Our first task is to add Amazon Bedrock as a data source to our app. This approach gives an AWS Lambda function (we'll define that in the next step) permission to call a specific foundation model in Amazon Bedrock. We're limiting the actions it can make to &lt;code&gt;bedrock:InvokeModel&lt;/code&gt; and the specific model resource we specify.&lt;/p&gt;

&lt;p&gt;To do this, let's add the following to the &lt;code&gt;amplify/backend.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// amplify/backend.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineBackend&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-amplify/backend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./auth/resource&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CHAT_MODEL_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;generateChatResponseFunction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./data/resource&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PolicyStatement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-iam&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;backend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineBackend&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;generateChatResponseFunction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generateChatResponseFunction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addToRolePolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PolicyStatement&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bedrock:InvokeModel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;`arn:aws:bedrock:*::foundation-model/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CHAT_MODEL_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to define the custom query and connect it to the handler function that will make the call to Amazon Bedrock.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define a custom query
&lt;/h2&gt;

&lt;p&gt;In this step, we first define the &lt;code&gt;generateChatResponseFunction&lt;/code&gt; using &lt;code&gt;defineFunction&lt;/code&gt; and configure it with the model id, timeout, and which Node runtime top use. The &lt;code&gt;entry&lt;/code&gt; key will specify the handler that with the core logic.&lt;/p&gt;

&lt;p&gt;Now, we define a custom query &lt;code&gt;generateChatResponse&lt;/code&gt; and add it to the schema. Here, we define the arguments allowed, the return type, and which function to use.&lt;/p&gt;

&lt;p&gt;To do this, update the &lt;code&gt;amplify/data/resource.ts&lt;/code&gt; file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// amplify/data/resource.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ClientSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defineData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defineFunction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-amplify/backend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CHAT_MODEL_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anthropic.claude-3-sonnet-20240229-v1:0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generateChatResponseFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineFunction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./generateChatResponse.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;CHAT_MODEL_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;timeoutSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;generateChatResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;returns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publicApiKey&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generateChatResponseFunction&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ClientSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineData&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;authorizationModes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;defaultAuthorizationMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apiKey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiKeyAuthorizationMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;expiresInDays&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, the first argument is a JSON string, &lt;code&gt;conversation&lt;/code&gt;. This will include the entire conversation from our interactions with our interactive storyteller.&lt;/p&gt;

&lt;p&gt;The second argument is a string, &lt;code&gt;systemPrompt&lt;/code&gt;. We'll use this to customize our interactions with the model, by providing context, instructions, and guidelines on how to respond.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the handler code
&lt;/h2&gt;

&lt;p&gt;Next, we'll create the handler code with our core logic that makes the call to Amazon Bedrock. Here, we'll initialize the &lt;code&gt;BedrockRuntimeClient&lt;/code&gt;, prepare the input and conversation as a &lt;code&gt;ConverseCommandInput&lt;/code&gt;, and then make the call.&lt;/p&gt;

&lt;p&gt;When this handler code is called, the &lt;code&gt;conversation&lt;/code&gt; argument will be passed a JSON string representing the full conversation between the user and the interactive story teller. This is then parsed and loaded as an object with this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firstUserMessage&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firstResponseMessage&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;secondUserMessage&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows us to maintain a conversation history and handle multi-turn conversations.&lt;/p&gt;

&lt;p&gt;To implement this, create the &lt;code&gt;amplify/data/generateChatResponse.ts&lt;/code&gt; file with the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// amplify/data/generateChatResponse.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./resource&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;BedrockRuntimeClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ConverseCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ConverseCommandInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-bedrock-runtime&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BedrockRuntimeClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;generateChatResponse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;functionHandler&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// System prompt for context&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;systemPrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;}];&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;modelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CHAT_MODEL_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inferenceConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ConverseCommandInput&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ConverseCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jsonResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;jsonResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;maxTokens&lt;/code&gt; inference parameter defines the maximum number of tokens the model can generate and &lt;code&gt;temperature&lt;/code&gt; controls how creative it can get (a number between 0 and 1 with closer to 1 being more creative). Read more about these inference parameters &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/inference-parameters.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the component to facilitate the conversation
&lt;/h2&gt;

&lt;p&gt;Our last big step is creating the component that makes the function call via the custom query. This component will facilitate the conversation between the user and the interactive story teller. Here's what our component will look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff34j40gpega4ncepys86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff34j40gpega4ncepys86.png" alt="React component showing conversation between assistant and user with a text field for user message." width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below, I'll cover the major parts of the &lt;code&gt;ChatComponent.tsx&lt;/code&gt; and how each part works, and then I'll share the full code (jump to [here] if that's all you're looking for).&lt;/p&gt;

&lt;p&gt;In the JSX portion of &lt;code&gt;ChatComponent.tsx&lt;/code&gt;, we iterate over the &lt;code&gt;conversation&lt;/code&gt; between the AI (labeled assistant here) and the user (labeled human). The conversation alternates between the assistant and human, so we style each a little different.&lt;/p&gt;

&lt;p&gt;We add a &lt;code&gt;TextField&lt;/code&gt; component to capture the user's message, setting the &lt;code&gt;inputValue&lt;/code&gt; via &lt;code&gt;handleInputChange&lt;/code&gt; when text is entered and calling &lt;code&gt;setNewUserMessage&lt;/code&gt; whenever the &lt;code&gt;Enter&lt;/code&gt; key is pressed or the Send button is pressed. There are also properties to show an error message if one exists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;60vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Flex&lt;/span&gt; &lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;column&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;wrap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wrap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;justifyContent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;space-between&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;40vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant-message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;colorTheme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;neutral&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Message&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;40vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;human-message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;hasIcon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;colorTheme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;info&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Message&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;))}&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Loader&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TextField&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What would you like to chat about?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prompt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inputValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleInputChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onKeyUp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;setNewUserMessage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="nx"&gt;labelHidden&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;hasError&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;60vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;outerEndComponent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setNewUserMessage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Send&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&amp;gt;} /&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Flex&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll use a simple &lt;code&gt;handleInputChange&lt;/code&gt; function that clears the error if there was one whenever the user starts typing and then sets the input value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleInputChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setInputValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we'll implement &lt;code&gt;setNewUserMessage&lt;/code&gt; to add the new message from the human (using the role &lt;code&gt;user&lt;/code&gt;) to the conversation. This is in the same structure as we covered earlier, alternating between &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;assistant&lt;/code&gt; roles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setNewUserMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newUserMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputValue&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nf"&gt;setConversation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevConversation&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prevConversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newUserMessage&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's time to make the call to the &lt;code&gt;generateChatResponse&lt;/code&gt; query to send the message to the model with Amazon Bedrock. We use the &lt;code&gt;useEffect&lt;/code&gt; hook because we need to wait on &lt;code&gt;setConversation&lt;/code&gt; to be complete before making the call. We implement &lt;code&gt;fetchChatResponse&lt;/code&gt; as an async function to make the actual call and only call it when there is a conversation where the last message is from the user. We do this last check because we only want to send user messages to the model. We do not want to send the assistant's responses, which we also push back onto the conversation (remember that alternating user-assistant conversation array from earlier?) so the model has our entire conversation history as context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchChatResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setInputValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateChatResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;systemPrompt&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setConversation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevConversation&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prevConversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;An unknown error occurred.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;errors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// only fetch the response if there is a conversation and it ends with a user role message&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;fetchChatResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Full code for the component
&lt;/h3&gt;

&lt;p&gt;Here is the full code for the component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ChatComponent.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Flex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Loader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-amplify/ui-react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;generateClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws-amplify/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Schema&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../../amplify/data/resource&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./chat.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;generateClient&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ChatComponent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setConversation&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}[]&lt;/span&gt; &lt;span class="p"&gt;}[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;inputValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setInputValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleInputChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setInputValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchChatResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setInputValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateChatResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;systemPrompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;systemPrompt&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setConversation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevConversation&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prevConversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;An unknown error occurred.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;errors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// only fetch the response if there is a conversation and it ends with a user role message&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;fetchChatResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setNewUserMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newUserMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputValue&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nf"&gt;setConversation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevConversation&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prevConversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newUserMessage&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;60vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Flex&lt;/span&gt; &lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;column&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;wrap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wrap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;justifyContent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;space-between&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;40vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant-message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;colorTheme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;neutral&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Message&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;40vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;human-message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;hasIcon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;colorTheme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;info&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Message&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Loader&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TextField&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What would you like to chat about?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prompt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inputValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleInputChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;onKeyUp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nf"&gt;setNewUserMessage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;}}&lt;/span&gt;
          &lt;span class="nx"&gt;labelHidden&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;hasError&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;60vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;outerEndComponent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setNewUserMessage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Send&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&amp;gt;} /&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Flex&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And to style the human-assistant messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* chat.css */&lt;/span&gt;
&lt;span class="nc"&gt;.assistant-message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.human-message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;Now we have our backend code - the custom query with a handler backed by a Lambda function that makes the call to Amazon Bedrock. And our chat component - a React component that displays the full chat conversation between human and AI assistant with a text field to collect the human's next message.&lt;/p&gt;

&lt;p&gt;We'll add the following to our &lt;code&gt;App.tsx&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// App.tsx
&lt;span class="nt"&gt;&amp;lt;View&lt;/span&gt; &lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;"section"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Heading&lt;/span&gt;
        &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;'60vw'&lt;/span&gt;
        &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;{2}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;      
        Let's tell a story together.
    &lt;span class="nt"&gt;&amp;lt;/Heading&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Text&lt;/span&gt;
        &lt;span class="na"&gt;variation=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt;
        &lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;"p"&lt;/span&gt;
        &lt;span class="na"&gt;lineHeight=&lt;/span&gt;&lt;span class="s"&gt;"1.5em"&lt;/span&gt;
        &lt;span class="na"&gt;fontWeight=&lt;/span&gt;&lt;span class="s"&gt;{400}&lt;/span&gt;
        &lt;span class="na"&gt;fontSize=&lt;/span&gt;&lt;span class="s"&gt;"1em"&lt;/span&gt;
        &lt;span class="na"&gt;fontStyle=&lt;/span&gt;&lt;span class="s"&gt;"normal"&lt;/span&gt;
        &lt;span class="na"&gt;textDecoration=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt;
        &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"60vw"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Start by introducing yourself and saying hi.
    &lt;span class="nt"&gt;&amp;lt;/Text&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Chat&lt;/span&gt;
        &lt;span class="na"&gt;systemPrompt=&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;Pretend&lt;/span&gt; &lt;span class="na"&gt;you&lt;/span&gt; &lt;span class="na"&gt;are&lt;/span&gt; &lt;span class="na"&gt;an&lt;/span&gt; &lt;span class="na"&gt;author&lt;/span&gt; &lt;span class="na"&gt;of&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt; &lt;span class="na"&gt;choose&lt;/span&gt; &lt;span class="na"&gt;your&lt;/span&gt; &lt;span class="na"&gt;own&lt;/span&gt; &lt;span class="na"&gt;adventure&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt; &lt;span class="na"&gt;story&lt;/span&gt; &lt;span class="na"&gt;for&lt;/span&gt; &lt;span class="na"&gt;children&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt; &lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="na"&gt;-5.&lt;/span&gt; &lt;span class="na"&gt;Start&lt;/span&gt; &lt;span class="na"&gt;by&lt;/span&gt; &lt;span class="na"&gt;asking&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt; &lt;span class="na"&gt;series&lt;/span&gt; &lt;span class="na"&gt;of&lt;/span&gt; &lt;span class="na"&gt;three&lt;/span&gt; &lt;span class="na"&gt;questions&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt; &lt;span class="na"&gt;understand&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;theme&lt;/span&gt; &lt;span class="na"&gt;of&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;adventure.&lt;/span&gt; &lt;span class="na"&gt;Tell&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;first&lt;/span&gt; &lt;span class="na"&gt;part&lt;/span&gt; &lt;span class="na"&gt;of&lt;/span&gt; &lt;span class="na"&gt;four&lt;/span&gt; &lt;span class="na"&gt;parts&lt;/span&gt; &lt;span class="na"&gt;of&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;story&lt;/span&gt; &lt;span class="na"&gt;and&lt;/span&gt; &lt;span class="na"&gt;then&lt;/span&gt; &lt;span class="na"&gt;ask&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt; &lt;span class="na"&gt;make&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt; &lt;span class="na"&gt;choice&lt;/span&gt; &lt;span class="na"&gt;about&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt; &lt;span class="na"&gt;they&lt;/span&gt; &lt;span class="na"&gt;would&lt;/span&gt; &lt;span class="na"&gt;like&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt; &lt;span class="na"&gt;take.&lt;/span&gt; &lt;span class="na"&gt;Repeat&lt;/span&gt; &lt;span class="na"&gt;this&lt;/span&gt; &lt;span class="na"&gt;until&lt;/span&gt; &lt;span class="na"&gt;all&lt;/span&gt; &lt;span class="na"&gt;for&lt;/span&gt; &lt;span class="na"&gt;parts&lt;/span&gt; &lt;span class="na"&gt;of&lt;/span&gt; &lt;span class="na"&gt;the&lt;/span&gt; &lt;span class="na"&gt;story&lt;/span&gt; &lt;span class="na"&gt;are&lt;/span&gt; &lt;span class="na"&gt;complete.&lt;/span&gt; &lt;span class="na"&gt;Each&lt;/span&gt; &lt;span class="na"&gt;part&lt;/span&gt; &lt;span class="na"&gt;is&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="na"&gt;-4&lt;/span&gt; &lt;span class="na"&gt;paragraphs&lt;/span&gt; &lt;span class="na"&gt;long.&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/View&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make this customized to our use case -- interactive bedtime storyteller -- we set the &lt;code&gt;systemPrompt&lt;/code&gt; to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Pretend you are an author of a choose your own adventure style story for children age 3-5. Start by asking the user a series of three questions to understand the theme of the adventure. Tell the first part of four parts of the story and then ask the user to make a choice about the path they would like to take. Repeat this until all for parts of the story are complete. Each part is 2-4 paragraphs long.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can customize this to your own use case so that your assistant has context, instructions, and guidelines on how to respond to your user.&lt;/p&gt;

&lt;p&gt;Additionally, you may also want to update the &lt;code&gt;CHAT_MODEL_ID&lt;/code&gt; in &lt;code&gt;amplify/data/resource.ts&lt;/code&gt; to use a different model that works for your use case. You can find supported Amazon Bedrock models &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;And that's it! In this article, we used the interactive bedtime storyteller use case to show how to integrate the Amazon Bedrock Converse API into your Amplify (Gen 2) app, how to send the full conversation to maintain a history and handle multi-turn conversations, and how to use the &lt;code&gt;systemPrompt&lt;/code&gt; and inference parameters, &lt;code&gt;maxTokens&lt;/code&gt; and &lt;code&gt;temperature&lt;/code&gt;, to customize the assistant even more. To explore more ways to use Amazon Bedrock, check out these &lt;a href="https://community.aws/code/generative-ai" rel="noopener noreferrer"&gt;code samples in various languages&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this has been helpful. If you'd like more like this, smash that like button 👍, share this with your friends 👯, or drop a comment below 💬.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ai</category>
      <category>amplify</category>
      <category>typescript</category>
    </item>
    <item>
      <title>How an AI coding companion keeps my code DRY</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Thu, 18 Jul 2024 14:00:00 +0000</pubDate>
      <link>https://dev.to/aws/how-an-ai-coding-companion-keeps-my-code-dry-3p3m</link>
      <guid>https://dev.to/aws/how-an-ai-coding-companion-keeps-my-code-dry-3p3m</guid>
      <description>&lt;p&gt;One of the challenges with working in a large code base is that you have remember all the things: coding styles, best practices, your own company's patterns, your custom libraries and their APIs. If you aren't able to memorize it all (because most people can't), you're left digging through code or docs trying to figure it out, relying on tools to remind you about styles, or using pre-commit hooks to fix issues for you. Maybe you're waiting for that dreaded code review. They're either going to remind you that you're not using the established pattern and you have more work to do. Or they'll drop a comment in the pull request &lt;a href="https://www.reddit.com/r/ProgrammerHumor/comments/w92k2i/lgtm/" rel="noopener noreferrer"&gt;"LGTM"&lt;/a&gt; and merge it with barely a glance and then bugs are found later in production.&lt;/p&gt;

&lt;p&gt;Instead of relying on that that grumpy code reviewer, you can use an AI coding companion (who's also a little less grumpy) customized to your unique code base, company's coding styles, best practices, patterns, and custom libraries and APIs. In this article, I will show how your company's Amazon Q Developer customizations will help you create more consistent code so you can keep your code DRY (the &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="noopener noreferrer"&gt;Don't Repeat Yourself principle&lt;/a&gt; of software development), improve on-boarding and knowledge transfer, and improve collaboration among your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customization prerequisites
&lt;/h2&gt;

&lt;p&gt;You'll need to have an Amazon Q Developer Pro subscription and your administrator will need to have already configured your access to the customizations. You can read more about the setup &lt;a href="https://aws.amazon.com/blogs/aws/customize-amazon-q-developer-in-your-ide-with-your-private-code-base/" rel="noopener noreferrer"&gt;here&lt;/a&gt; (or just pass it over to your admin to handle).&lt;/p&gt;

&lt;p&gt;In this article, I'm using a customization created based on the &lt;a href="https://github.com/spring-projects/spring-petclinic/tree/main" rel="noopener noreferrer"&gt;spring-petclinic projects and libraries&lt;/a&gt;. By creating the customization with your own unique coding style, libraries, and APIs, even different languages, Amazon Q will have more sample data to learn from and will be more equipped to match your intent to what it knows so it can provide better suggestions as you encounter various coding problems.&lt;/p&gt;

&lt;p&gt;Let's check out a couple examples of how customizations work right in your IDE!&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a new entity using chat
&lt;/h2&gt;

&lt;p&gt;I've been tasked with implementing a new entity, &lt;code&gt;Order&lt;/code&gt;. Doing this without an AI coding companion means I'll need to look for existing patterns, copy/paste, find APIs we need, or code it up from scratch. This has the potential to create more code that is inconsistent with the rest of the code base. Instead, I'll use Amazon Q Developer to generate a code suggestion. I ask:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Create an implementation for a new entity called Order, in Java. Make sure to create the entity class and the repository implementation using JPA.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The response I get back is pretty generic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.persistence.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.time.LocalDate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Table&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"orders"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;orderDate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Constructors, getters, and setters&lt;/span&gt;

    &lt;span class="c1"&gt;// Additional fields and relationships as needed&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I know that my team has established patterns for this code base that I should be following. This suggestion doesn't adhere to these patterns or use our libraries because Amazon Q doesn't have the full context. In this case, I know that the &lt;code&gt;Order&lt;/code&gt; class should be extending the &lt;code&gt;BaseEntity&lt;/code&gt; class that defines some base properties and logic that all of this project's entities should have. Imagine you're a developer new to this project. You may not have the same context I have.&lt;/p&gt;

&lt;p&gt;This is where a Amazon Q Developer customizations can come in to help us. If we have a customization created and the chat customization feature (now in Preview) is enabled, we can ask Amazon Q again and get more customized information. I've written &lt;a href="https://community.aws/content/2ihDE9A59SAbHwUqkLWhyl78Eax/simplify-your-unit-testing-with-generative-ai" rel="noopener noreferrer"&gt;before about asking Amazon Q chat for code examples&lt;/a&gt; and we'll do the same here after selecting a customization to use.&lt;/p&gt;

&lt;p&gt;When getting started with our work, we can select our code base's customization. First, select Amazon Q in the lower menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhy73cj9pa1xfhpkr4b6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhy73cj9pa1xfhpkr4b6.png" alt="Orange arrow pointing to Amazon Q item in lower menu in VSCode." width="800" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then in the popup menu, select "Select Customization".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtq2rhpjph4swtyv2e00.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtq2rhpjph4swtyv2e00.png" alt="Amazon Q command pane in VSCode with Select Customization highlighted in orange" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then select your customization to use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg124guyo9djy3iuxmvxs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg124guyo9djy3iuxmvxs.png" alt="spring-petclinic customization highlighted in orange" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now when I ask Amazon Q the same question, I get the following suggestion, which is using our established pattern of extending &lt;code&gt;BaseEntity&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Table&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"orders"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseEntity&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"order_date"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;orderDate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"total_amount"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="n"&gt;totalAmount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Constructors, getters, and setters&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Default constructor&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;orderDate&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="n"&gt;totalAmount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orderDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orderDate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;totalAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;totalAmount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Getters and setters&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where Amazon Q Developer takes the selected customization and uses it to match my intentions to what it has learned so that it can generate a customized suggestion for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a new entity using inline code suggestions
&lt;/h2&gt;

&lt;p&gt;In the example below, we could also create the shell of our class file and use a comment to get an inline code suggestion from Amazon Q Developer to create this &lt;code&gt;Order&lt;/code&gt; entity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.anycompany.order&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// class representing an order entity using JPA&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After triggering Amazon Q, the following code might be suggested if we're not using a customization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.anycompany.order&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// class representing an order entity using JPA&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.persistence.GenerationType&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Date&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Table&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"orders"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"order_date"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt; &lt;span class="n"&gt;orderDate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// constructors, getters and setters&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we select a customization and then trigger Amazon Q inline again, we would get a customized suggestion like the one we got using chat, including the use of the &lt;code&gt;BaseEntity&lt;/code&gt; superclass.&lt;/p&gt;

&lt;p&gt;As with other interactions with Amazon Q, if the suggestions aren't what you're looking for, you can either accept one and tailor it to your needs (you probably will have to do this at some point) or you can provide more context to nudge it in the right direction. You could import libraries you know you want to use, add some additional comments, and ensure you're using descriptive function and variable names. &lt;code&gt;doStuff&lt;/code&gt; isn't going to cut it here!&lt;/p&gt;

&lt;p&gt;Now that we've checked out how this works in action, let's review some of the benefits we get.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep your code DRY
&lt;/h2&gt;

&lt;p&gt;Using a customization could be really powerful in the context of a large, quickly moving code base with many developers working in it. In the first example, it helps us keep our code DRY so that if the underlying implementation ever changes, the calling code doesn't also need to be changed.&lt;/p&gt;

&lt;p&gt;When keeping our code DRY, we write less code. Our code becomes more readable (assuming the code we're calling uses descriptive names) and is easier to maintain and test.&lt;/p&gt;

&lt;p&gt;It also means less can go wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improve on-boarding and knowledge transfer
&lt;/h2&gt;

&lt;p&gt;Imagine if I'm new to this code base and don't yet know about all the existing libraries and APIs. I can ask Amazon Q to explain code snippets from a code base I'm just discovering or ask it to provide example code. I can describe my intent in a comment or function signature and Amazon Q will suggest code based on examples it learned from my company's private code base.&lt;/p&gt;

&lt;p&gt;I've been using Amazon Q Developer's chat feature quite a bit to learn more about how a piece of code works, ask questions about my options for design and architecture or how to implement something, but now I can get suggestions based on my selected customization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improve collaboration
&lt;/h2&gt;

&lt;p&gt;I mentioned earlier that grumpy code reviewer (we've all experienced one, right?!). Writing consistent code like we've covered here can also improve collaboration during code reviews and pair programming. Not only does my code reviewer or pair not have to remind me to use our already written, maintained, and tested library, but I have easy access to coding styles, standards, and best practices. Code suggestions while using a customization will already incorporate these and it's less likely that we'll argue over two spaces or four or whether or not we need to implement &lt;code&gt;getOrderTotal&lt;/code&gt; three different ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;If you're working in a large code base, you might benefit from using a customized AI coding companion, like Amazon Q Developer. Today, I showed how using a customization based on your company's patterns, best practices, style guide, libraries, and APIs can help with readability and maintenance, on-boarding and knowledge transfer, and collaboration.&lt;/p&gt;

&lt;p&gt;The Amazon Q Developer customizations feature for inline code suggestions just left Preview and the chat customization feature was released in Preview, both on July 10th. You can create your own customization (or ask your admin to set it up) by following &lt;a href="https://aws.amazon.com/blogs/aws/customize-amazon-q-developer-in-your-ide-with-your-private-code-base/" rel="noopener noreferrer"&gt;these steps&lt;/a&gt;. Both features are continuously being improved based on your feedback, so if something isn't working as you expect, you find a bug, or even have suggestions to improve how it works in your development flow, let me know in the comments!&lt;/p&gt;

&lt;p&gt;If you haven't yet tried out &lt;a href="https://aws.amazon.com/developer/generative-ai/amazon-q/" rel="noopener noreferrer"&gt;Amazon Q Developer&lt;/a&gt; in your development workflow, check out how to get started in &lt;a href="https://community.aws/content/2fVw1hN4VeTF3qtVSZHfQiQUS16/getting-started-with-amazon-q-developer-in-visual-studio-code" rel="noopener noreferrer"&gt;VSCode&lt;/a&gt; or &lt;a href="https://community.aws/content/2fXj10wxhGCExqPvnsJNTycaUcL/adding-amazon-q-developer-to-jetbrains-ides" rel="noopener noreferrer"&gt;JetBrains IDEs&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ai</category>
    </item>
    <item>
      <title>Simplify your unit testing with generative AI</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Wed, 03 Jul 2024 14:30:00 +0000</pubDate>
      <link>https://dev.to/aws/simplify-your-unit-testing-with-generative-ai-2cnj</link>
      <guid>https://dev.to/aws/simplify-your-unit-testing-with-generative-ai-2cnj</guid>
      <description>&lt;p&gt;When I write code, I write tests. But I especially hate the process of getting my test framework setup in my project and writing those first few tests that will eventually guide the way for a more full-fledged test suite.&lt;/p&gt;

&lt;p&gt;Because of this, I have been experimenting with generative AI tools, like &lt;a href="https://aws.amazon.com/developer/generative-ai/amazon-q/" rel="noopener noreferrer"&gt;Amazon Q Developer&lt;/a&gt;, to support my testing efforts and to write and fix tests more quickly. I want to share with you today how I'm getting my test framework setup, creating those first few tests, and the back and forth prompts I'm using to be more productive.&lt;/p&gt;

&lt;p&gt;In the examples below, I have a small React app using Typescript, deployed with &lt;a href="https://docs.amplify.aws/react/start/quickstart/" rel="noopener noreferrer"&gt;AWS Amplify Gen 2&lt;/a&gt;. I like to get my test suite set up as I'm kicking off a project, so now is the time. Once my test suite is set up, I'll show you how to write a couple of tests and get a passing test suite.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a test suite
&lt;/h2&gt;

&lt;p&gt;It's been a bit since I've worked with React and so I'm looking to learn more about which testing framework is common practice to use. I've used Jest in the past, so I expect that will show up in my research.&lt;/p&gt;

&lt;p&gt;I start by asking Amazon Q: &lt;code&gt;What are some options for test frameworks for testing this React app? Test framework needs to support Typescript, be able to use the React Testing Library for component testing, and support mocking.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzjszehv3xx05jhnz7cv4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzjszehv3xx05jhnz7cv4.png" alt="Amazon Q prompt asking for test framework options" width="706" height="728"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I get four options here, with Jest being one of them. &lt;a href="https://vitest.dev/" rel="noopener noreferrer"&gt;Vitest&lt;/a&gt; looks interesting and this project is using Vite, so I ask for more info: &lt;code&gt;Why would I choose Jest over Vitest?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuc4z57rz110f285oyxz6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuc4z57rz110f285oyxz6.png" alt="Amazon Q prompt asking why Jest over Vitest" width="725" height="964"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I decide to go with Vitest and next I ask Amazon Q how to get my test suite set up: &lt;code&gt;What are the steps I need to take to set up this project to use Vitest? Include React Testing Library, support for typescript.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj126jv2ei0kbkpze7dpv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj126jv2ei0kbkpze7dpv.png" alt="Amazon Q prompt asking what the steps are to setup Vitest in this project." width="800" height="834"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivwmlknx197hk38f04fr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivwmlknx197hk38f04fr.png" alt="Steps 3-4 from Amazon Q prompt asking what the steps are to setup Vitest in this project." width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use the steps from the Amazon Q response as my guide to setting up the test suite. Before going through each step, I review them to make sure it's what I need, to make sure it's accurate enough to proceed. There were a couple of spots that gave me trouble and I'll point them out below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Install dependencies
&lt;/h3&gt;

&lt;p&gt;I run the proposed command at the command line to install the Vitest, React Testing Library, and related dependencies:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install -D vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Configure Vitest
&lt;/h3&gt;

&lt;p&gt;I create a &lt;code&gt;vitest.config.ts&lt;/code&gt; file in the root of my project and paste in the proposed code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// &amp;lt;reference types="vitest" /&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;reference types="vite/client" /&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsdom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;setupFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/setupTests.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Create a setup file
&lt;/h3&gt;

&lt;p&gt;I create the &lt;code&gt;setupTests.ts&lt;/code&gt; file in the &lt;code&gt;src&lt;/code&gt; directory as referenced in the previous step and add the proposed code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/setupTests.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/jest-dom/extend-expect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ Warning: For anyone scanning through this article for the code, the line above is actually incorrect and we fix it in the next section!&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Update package.json
&lt;/h3&gt;

&lt;p&gt;Finally, I update the &lt;code&gt;package.json&lt;/code&gt; file to add the following to the &lt;code&gt;scripts&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vitest"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will allow me to run &lt;code&gt;npm test&lt;/code&gt; at the command line to run the tests and watch for changes. Everything so far has been smooth. Now it's time to write my first test. &lt;/p&gt;

&lt;h2&gt;
  
  
  Writing some tests
&lt;/h2&gt;

&lt;p&gt;So far, the bulk of my work is in the &lt;code&gt;RecipeList&lt;/code&gt; component that either lists a user's recipes or shows a "New recipe" button if they don't have any recipes yet. I know that I want the following five test cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;display "Your Recipes" header text&lt;/li&gt;
&lt;li&gt;display a button to create a new recipe&lt;/li&gt;
&lt;li&gt;render a list of recipes when user has recipes&lt;/li&gt;
&lt;li&gt;render a button to view each recipe when user has recipes&lt;/li&gt;
&lt;li&gt;render a button to create a new recipe when user has no recipes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I have two approaches to create tests with Amazon Q. I can start by asking Q to suggest an example test: &lt;code&gt;Give me an example vitest test for RecipeList. One test will test that RecipeList displays "Your Recipes" text. The second test will test that a button to create a "New Recipe" is displayed. Mock the useRecipeData hook to return a list of recipes from the default function.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mjll45utf8mrd97x9i2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mjll45utf8mrd97x9i2.png" alt="Amazon Q prompt asking for an example test." width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Starting with this example, I clean this up. In the &lt;code&gt;useRecipeData&lt;/code&gt; mock, I fix two issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;remove the imports for React (unnecessary) and vitest (I'm using a global setup, so already imported; see step 2 in the previous section)&lt;/li&gt;
&lt;li&gt;change the module path to &lt;code&gt;../hooks/useRecipeData&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;swap &lt;code&gt;recipes&lt;/code&gt; for &lt;code&gt;default&lt;/code&gt; because the hook I'm mocking uses a default export rather than a named export. In both tests, I add a &lt;code&gt;&amp;lt;BrowserRouter&amp;gt;&lt;/code&gt; wrapper around the &lt;code&gt;&amp;lt;RecipeList&amp;gt;&lt;/code&gt; component.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The test now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// RecipeList.test.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;vi&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RecipeList&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./RecipeList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BrowserRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../hooks/useRecipeData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;recipes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RecipeList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should display "Your Recipes" text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RecipeList&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BrowserRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yourRecipesText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your Recipes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yourRecipesText&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should display a button to create a new recipe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RecipeList&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BrowserRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newRecipeButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/New Recipe/i&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newRecipeButton&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, it's time to check if the tests pass or fail!&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the test suite to get green
&lt;/h2&gt;

&lt;p&gt;In the terminal, I run &lt;code&gt;npm test&lt;/code&gt; to run the tests and watch for changes. I immediately run into an error. I'm not sure what this means, so I ask Amazon Q for help:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;What does this error message mean:&lt;/code&gt;&lt;code&gt;Error: Missing "./extend-expect" specifier in "@testing-library/jest-dom" package&lt;/code&gt;&lt;code&gt;when running&lt;/code&gt;&lt;code&gt;npm test&lt;/code&gt;&lt;code&gt;?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Based on the response, I need to update our &lt;code&gt;setupTests.ts&lt;/code&gt; file from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// setupTests.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/jest-dom/extend-expect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// setupTests.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/jest-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So that it uses the default export, rather than the removed &lt;code&gt;extend-expect&lt;/code&gt; named export.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9gzthu2n4wu7difch931.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9gzthu2n4wu7difch931.png" alt="Amazon Q prompt asking what a specific error message means." width="714" height="967"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After saving the file, the tests are automatically rerun and this issue is resolved. However, the tests are not yet green and passing. The test &lt;code&gt;should display "Your Recipes" text&lt;/code&gt; fails because &lt;code&gt;Your Recipes&lt;/code&gt; should only be displayed when the user has no recipes and we set this up with an empty list.&lt;/p&gt;

&lt;p&gt;Let's fix that by adding some mock recipes. Because &lt;code&gt;vi.mock&lt;/code&gt; is hoisted to the top of the file, I also need to make &lt;code&gt;mockRecipes&lt;/code&gt; hoisted, by using &lt;code&gt;vi.hoisted&lt;/code&gt;. I then move these to a &lt;code&gt;beforeEach&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hoisted&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;mockRecipes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Recipe 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Instructions 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Recipe 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Instructions 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../hooks/useRecipeData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;recipes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mocks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mockRecipes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After saving the file, all of the tests are passing! My (very small) test suite is green! Next, I can write a few more tests to extend the test suite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Add more tests
&lt;/h2&gt;

&lt;p&gt;Once I have the core of a test stubbed out, I can start typing out code and let Amazon Q's inline code prompting make suggestions for me. Another test I want to add is &lt;code&gt;render a list of recipes when user has recipes&lt;/code&gt;. To use Amazon Q's inline code suggestions, I start typing out the test with the description of what I want. In the screenshot below, I start typing this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should render a list of recipes when user has recipes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Amazon Q will provide a suggestion automatically (see the light grey suggestion in the screenshot, between lines 47-48) or I can use the &lt;a href="https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/actions-and-shortcuts.html" rel="noopener noreferrer"&gt;shortcuts&lt;/a&gt; &lt;code&gt;Option+C&lt;/code&gt; (Mac) or &lt;code&gt;Alt+C&lt;/code&gt; (Windows). I like the suggestion, so I hit &lt;code&gt;Tab&lt;/code&gt; to accept it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffzmytp0wp6n9r0sc38ug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffzmytp0wp6n9r0sc38ug.png" alt="Using Amazon Q inline code suggestion to write a test." width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My final test looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// RecipeList.test.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cleanup&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RecipeList&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./RecipeList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BrowserRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hoisted&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;mockRecipes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Recipe 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Instructions 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Recipe 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Instructions 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RecipeList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../hooks/useRecipeData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;recipes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mocks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mockRecipes&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should display "Your Recipes" text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RecipeList&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BrowserRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yourRecipesText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your Recipes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yourRecipesText&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should display a button to create a new recipe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RecipeList&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BrowserRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newRecipeButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/New Recipe/i&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newRecipeButton&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should render a list of recipes when user has recipes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RecipeList&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BrowserRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Recipe 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Recipe 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should render a button to view each recipe when user has recipes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RecipeList&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BrowserRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;viewButtons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findAllByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;View&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;viewButtons&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should render a button to create a new recipe when user has no recipes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../hooks/useRecipeData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;recipes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RecipeList&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BrowserRouter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New Recipe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;That's it! The test suite is green. In this article, I showed you how to setup a Vitest test suite to be used with Typescript and React Testing Library. We chose Vitest over Jest because the project uses Vite but we still interact with it a lot like Jest. We wrote some tests and then ran them from the command line using Vitest's test runner command that watches for changes to tests or code under test. We used Amazon Q Developer to support our work throughout, asking it questions, for example code, for help with errors, and used inline code suggestions. Ready to try Amazon Q Developer in your testing flow? Check out how to get started in &lt;a href="https://community.aws/content/2fVw1hN4VeTF3qtVSZHfQiQUS16/getting-started-with-amazon-q-developer-in-visual-studio-code" rel="noopener noreferrer"&gt;VSCode&lt;/a&gt; or &lt;a href="https://community.aws/content/2fXj10wxhGCExqPvnsJNTycaUcL/adding-amazon-q-developer-to-jetbrains-ides" rel="noopener noreferrer"&gt;JetBrains IDEs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have you been using an AI assistant to help you with testing? Drop a comment 💬 below to share what tool you're using and how it helps you.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ai</category>
      <category>productivity</category>
      <category>testing</category>
    </item>
    <item>
      <title>A practical approach to using generative AI in the SDLC</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Wed, 19 Jun 2024 13:02:00 +0000</pubDate>
      <link>https://dev.to/aws/a-practical-approach-to-using-generative-ai-in-the-sdlc-3jdh</link>
      <guid>https://dev.to/aws/a-practical-approach-to-using-generative-ai-in-the-sdlc-3jdh</guid>
      <description>&lt;p&gt;Have you ever taken requirements from a stakeholder, implemented them, only to have them come back to you and say "That's not what I asked for! I meant this..." It happens all the time. Sometimes we heard them wrong, sometimes we made incorrect assumptions, or maybe even the needs of the end-user changed.&lt;/p&gt;

&lt;p&gt;You may have already seen how an AI assistant like &lt;a href="https://aws.amazon.com/developer/generative-ai/amazon-q" rel="noopener noreferrer"&gt;Amazon Q Developer&lt;/a&gt; can help you write code and make your development more productive, and today I'd like to show you how I'm using an AI assistant to support the rest of my software development process, from idea to launch and beyond.&lt;/p&gt;

&lt;p&gt;In the examples below, my stakeholders want to build a way for their customers to share and discover recipes and I'm using Amazon Q Developer to help me figure out what to build and how to build it. We'll step through each phase of the software development life cycle (SDLC) and this will be relevant whether you're using a traditional waterfall process or agile methodologies.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis, requirements, and planning
&lt;/h2&gt;

&lt;p&gt;During the analysis, requirements, and planning phases of the SDLC, I'm doing a lot of information gathering, asking questions, and researching the domain. I can use Amazon Q Developer to help me with this. Using the stakeholder business idea to create a recipe sharing and discovery app, I can ask the following questions:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;I'm creating a platform for users to share and discover recipes, including ingredients, steps, and images. What sort of functional and non-functional requirements should I be thinking about?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqqrniqwppw3h0gm45p1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqqrniqwppw3h0gm45p1.png" alt="Asking Amazon Q Developer a question about analysis, requirements, and planning" width="800" height="597"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some other questions I might ask:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;What questions should I be asking my customer?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;What are some challenges in the recipe app domain that I need to account for?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;What are some questions I should be asking you about the functional and non-functional requirements of this recipe app?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I can use these tools to better prepare me for planning meetings, ask the right questions, help think about functional and non-functional requirements, all as input into the design and architecture phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design and architecture
&lt;/h2&gt;

&lt;p&gt;During the design phase, I start thinking more concretely about what the architecture will look like.&lt;/p&gt;

&lt;p&gt;I need to find accurate, up-to-date information and guidance to help me understand potential solutions, which AWS services I should use, and how to use them. Instead of spending hours reading through AWS documentation, reading through blog posts, searching on Google, before even getting started, I can explore different approaches and provide initial ideas for the design and architecture phase, evaluate pros and cons, and even get a recommendation from an AI assistant like Amazon Q Developer.&lt;/p&gt;

&lt;p&gt;Whether you enter this phase as someone new to the tech or the domain or you're armed with knowledge and years of experience, you still have to sift through it the information, evaluate your options, and make decisions. These tools help me gain clarity by narrowing down options based on the inputs I already have (functional and non functional requirements), the trade-offs I need to think about, and help make design and architectural decisions. &lt;/p&gt;

&lt;p&gt;In the recipe sharing app my stakeholders want me to build, I can ask questions like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;I would like to use AWS to deploy this web app. My team is made up of mostly Python engineers. We'll use Flask to build the app. What options do I have to deploy this app on AWS that include using infrastructure as code?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4a5myy4npe07eyfb390.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4a5myy4npe07eyfb390.png" alt="Asking Amazon Q Developer a question about design and architecture" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some other questions I might ask:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;What are the different tradeoffs I need to think about when choosing to use Amazon ECS for this app?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Assuming we use ECS, what are the different tradeoffs I need to think about when choosing to use AWS CDK or CloudFormation for this project?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;At this point, I have enough information to make a decision on how to proceed. I've decided to use Amazon ECS with Fargate to deploy this Flask app. Now I can start on the development of the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Development
&lt;/h2&gt;

&lt;p&gt;An AI assistant also helps me with many of my development tasks. Once I know what I need to build and how to communicate that to my tools, I can start asking questions about the implementation details.&lt;/p&gt;

&lt;p&gt;I can use it to learn how to work with libraries and APIs, explain a block of code, refactor, ask for steps on how to implement a new feature with code examples, get code completions based on existing code and comments.&lt;/p&gt;

&lt;p&gt;Using the same example, I ask:&lt;br&gt;
&lt;code&gt;What are the steps to bootstrap a simple Flask app that has one route "/recipes" that outputs "My Recipes" text? I need to set up a python virtual environment and requirements.txt as part of this.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqur7214cdjxvew55ezo2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqur7214cdjxvew55ezo2.png" alt="Asking Amazon Q Developer a question about development" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can generate code inline, right in my IDE, based on existing code and comments:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eryqgngwd8vo8grls04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eryqgngwd8vo8grls04.png" alt="Inline code completion of a function using a comment as a prompt" width="800" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can also troubleshoot and debug issues, fix faulty code, or configuration. I often paste in my stack traces and ask for help:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;When I run "python app.py" my Flask app does not start. There is no output when the command completes. Where should I investigate?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;I'm getting this stack trace when I hit the recipes route /recipes. The app starts ok and the root route / works ok. What are some reasons I might get this error and how can I resolve it?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Hopefully, this means less forgotten &lt;code&gt;print('GOT HERE')&lt;/code&gt; lines! Using an AI assistant to debug an issue after I've found is great, but I can also use one to prevent bad code by helping me write tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;One of my favorite ways to use an AI assistant is to help with my tests. Often there's a recipe (pun intended!) to setting up the test suite and getting the first piece of code under test. Often this is boilerplate code, so I can use Amazon Q Developer to set up my test suite, to stub out a new test class, generate test cases based on existing code or a set of requirements via prompt, and even generate synthetic data for testing purposes.&lt;/p&gt;

&lt;p&gt;In the recipe sharing app, I can ask questions like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;I want to create a unit test for the "/recipes" route using the unittest framework. What are the steps and example code to do that?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Falqua069ts2z5k4cn9nt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Falqua069ts2z5k4cn9nt.png" alt="Asking Amazon Q Developer a question about testing" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I might also ask questions about how to set up my test suite and run it, especially if this is a new-to-me code base:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;I have python tests cases created in this project. Which dependencies need to be installed so that I can run these tests and how do I run the test suite?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or to use the mocking library:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;I need to mock the API call to Amazon Bedrock in the /generate-recipe route. How can I use the unittest.mock library to do this? Please provide an example.&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;During the deployment phase, I can use an AI assistant to help write my infrastructure code, create deployment scripts, learn about command line deployment tools, and create images and diagrams for my docs.&lt;/p&gt;

&lt;p&gt;For my app, I can ask:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;What are the steps to deploy this Flask app as a container to ECS using Fargate?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gfg4bhuysdewbyhcx87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gfg4bhuysdewbyhcx87.png" alt="Asking Amazon Q Developer a question about deployment" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And when I'm ready to set up my CI/CD pipeline, I might start by asking for high-level steps and then drill down into each step with more specific questions:&lt;br&gt;
&lt;code&gt;What are the steps to set up this project's CI/CD pipeline using GitHub Actions? When a commit is made to the code repository, this action will automatically coordinate building, testing, and deploying the application to ECS for every push to the repository.&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Once I've deployed the app to production and end-users are using it, I'm not done. I still need to maintain it over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maintenance
&lt;/h2&gt;

&lt;p&gt;During the maintenance phase, I can use an AI assistant to learn about legacy codebases, an application's architecture, or a new programming language.&lt;/p&gt;

&lt;p&gt;I can use the Amazon Q Developer's Explain feature to get more info about a selected block of code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwbkvlaqfb80imybqeg82.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwbkvlaqfb80imybqeg82.png" alt="Using Amazon Q Developer's Explain feature" width="800" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or even get ideas on how to optimize my AWS bill right from the AWS Console:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;How can I optimize my bill this month?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymzq6yyj8dbv44avckx2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymzq6yyj8dbv44avckx2.png" alt="Asking Amazon Q in the Console how to optimize my bill" width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can transform, migrate, and upgrade a codebase or an application and I can refactor or optimize code, or even evaluate security vulnerabilities using an AI assistant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;As you use a tool like this, it's important to understand how your AI assistant is trained -- on what data, for what tasks -- and then use it appropriately, using your own judgement. You may not use Amazon Q Developer in your IDE to ask about stakeholder questions, but in my situation, it worked for me. You likely wouldn't ask for unit test code examples in the AWS Console, but you would in your IDE, because that's where you are doing that work.&lt;/p&gt;

&lt;p&gt;These are only some of the many ways you could use an AI assistant like Amazon Q Developer to help you throughout the SDLC. Whether you're using a variation of waterfall or an agile process, you can incorporate an AI assistant like Amazon Q Developer into your process. Read more about AI assistants on the Community.aws space or get started in &lt;a href="https://community.aws/content/2fVw1hN4VeTF3qtVSZHfQiQUS16/getting-started-with-amazon-q-developer-in-visual-studio-code" rel="noopener noreferrer"&gt;VSCode&lt;/a&gt;, &lt;a href="https://community.aws/content/2fXj10wxhGCExqPvnsJNTycaUcL/adding-amazon-q-developer-to-jetbrains-ides" rel="noopener noreferrer"&gt;JetBrains IDEs&lt;/a&gt;, or even the &lt;a href="https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-getting-started-installing.html" rel="noopener noreferrer"&gt;command line&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;How are you using AI assistants to help you with your development process? Drop a comment below to share and help others.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I'm a lazy developer. Here's how Amazon Q is enabling me</title>
      <dc:creator>Jenna Pederson</dc:creator>
      <pubDate>Tue, 18 Jun 2024 19:27:06 +0000</pubDate>
      <link>https://dev.to/aws/im-a-lazy-developer-heres-how-amazon-q-is-enabling-me-2cfc</link>
      <guid>https://dev.to/aws/im-a-lazy-developer-heres-how-amazon-q-is-enabling-me-2cfc</guid>
      <description>&lt;p&gt;I'm always on the hunt for ways to improve my productivity as a developer. I've spent the better part of the last two weeks diving head first into using &lt;a href="https://aws.amazon.com/developer/generative-ai/amazon-q" rel="noopener noreferrer"&gt;Amazon Q Developer&lt;/a&gt;, experimenting with how it might work in my development flow, learning the ins and outs, and chatting with coworkers about how they are using it. Today, I want to share what I've learned so far, how I'm tweaking my productivity and &lt;a href="https://github.blog/2024-01-22-how-to-get-in-the-flow-while-coding-and-why-its-important/" rel="noopener noreferrer"&gt;staying in the flow&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Reduce my context switching
&lt;/h2&gt;

&lt;p&gt;When I'm writing code, I want to get in the flow and stay in the flow. &lt;a href="https://leaddev.com/process/managing-chaos-context-switching" rel="noopener noreferrer"&gt;Context switching&lt;/a&gt; -- flipping between apps, back and forth between browser tabs, a google search here, and StackOverflow search there, the ding of an email, a bleep of a Slack notification (oops, I'm late for a meeting) -- all of this &lt;a href="https://news.ycombinator.com/item?id=35459333" rel="noopener noreferrer"&gt;comes with a cost&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm finding that Amazon Q Developer keeps me in my IDE. Instead of hopping over to a browser to do a google search or to read through documentation for my programming language, the framework I'm using, or the AWS docs, I can use this tool to do this digging for me.&lt;/p&gt;

&lt;p&gt;I can ask how to get started with a new project. Here, I started with the prompt &lt;code&gt;What are the steps to creating a python Flask app?&lt;/code&gt; Amazon Q Developer outlines the steps I need to take to get started, providing me with both code snippets and explanations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbf53hg3u0cl6ya4xt86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbf53hg3u0cl6ya4xt86.png" alt="Amazon Q chat with prompt " width="800" height="845"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can never remember the steps to create a python virtual environment so I ask it questions like &lt;code&gt;How do I initialize a python virtual environment?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xg2ja20wi1e1tqahjgm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xg2ja20wi1e1tqahjgm.png" alt="Amazon Q chat with prompt " width="800" height="689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if I want to go deeper, I'm even presented with external references backing up the responses.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4f86hpcauj05mokwkhp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4f86hpcauj05mokwkhp.png" alt="The sources used to prepare the response." width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of this allows me to stay in my IDE, reducing my context switching, and stay in the flow. Check out how my colleague &lt;a href="https://community.aws/content/2fo810EHkduTy0eRQRfxCmEFX10/using-amazon-q-developer-in-my-development-flow" rel="noopener noreferrer"&gt;stays in the flow with Amazon Q&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support for my lazy developer mentality
&lt;/h2&gt;

&lt;p&gt;According to the creator of the Perl programming language, Larry Wall, laziness is one of the virtues of a good programmer. For a programmer to be effective and efficient, they must also be lazy. But not in the traditional, lounge on your couch and watch TV all day and be lazy sense. Instead, a lazy developer is interested in saving time, automating tasks, especially the boring, time consuming, or brittle ones, documenting work for others.&lt;/p&gt;

&lt;p&gt;That's me. I'm a lazy developer.&lt;/p&gt;

&lt;p&gt;I don't remember all the properties for an HTML text area. So I ask Amazon Q to do the research for me and propose examples for boilerplate code like HTML elements and unit tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1bb9vdvbam37cnq7czg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1bb9vdvbam37cnq7czg.png" alt="Amazon Q chat with prompt " width="800" height="792"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I ask it to explain a block of code by selecting it and then using the "Send to Amazon Q" menu option:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93hbjyhh9cnl8vaacsx5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93hbjyhh9cnl8vaacsx5.png" alt="The Send to Amazon Q -&amp;gt; Explain menu." width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the response I get back:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcytl5o1klp60x6kazvrx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcytl5o1klp60x6kazvrx.png" alt="Prompt " width="656" height="1183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then I wanted more detail on the &lt;code&gt;json.loads&lt;/code&gt; line:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frup3ffgkhff5ygyxyxoy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frup3ffgkhff5ygyxyxoy.png" alt="Prompt " width="657" height="839"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a previous life, I often worked as a team of one, inheriting someone else's codebase. I would come into a new codebase with no other teammates to help me figure out what was going on. This is where Amazon Q can help you get up to speed quickly, summarizing blocks of code, functions, or even whole files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Help me debug
&lt;/h2&gt;

&lt;p&gt;One challenging task for developers is debugging hairy bugs. It's hard because you end up having to shove a bunch of info into your short term memory in order to trace through layers and layers of code, some of which you may not even be familiar with. Then... BAM! Slack notification, time for a meeting! You drop everything for an hour and come back to debugging and have to start that trace over again. Or you're chasing through multiple API docs trying to figure out whether you've correctly understood how to make a call and which parameters to send and how to handle the response.&lt;/p&gt;

&lt;p&gt;That's exactly what just happened to me as I was trying to make a call to Amazon Bedrock's &lt;code&gt;invoke_model&lt;/code&gt; API.&lt;/p&gt;

&lt;p&gt;I messed it up! So I asked Amazon Q for an assist:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuuxwvhx1x9p0p45degg6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuuxwvhx1x9p0p45degg6.png" alt="Asking Q chat to help me debug the error." width="631" height="671"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I had also messed up the format of the response body, so I used Amazon Q to help me debug through that as well:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfw7ne7mxrj4h6b2bsst.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfw7ne7mxrj4h6b2bsst.png" alt="Prompt " width="692" height="1029"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's important to recognize that LLMs are backing Amazon Q, which means it will experience hallucinations just like any other model. I did have some extra debugging because of this as the example code proposed using &lt;code&gt;ModelId&lt;/code&gt; and &lt;code&gt;Body&lt;/code&gt; when calling &lt;code&gt;invoke_model&lt;/code&gt; when they should have been lower-case &lt;code&gt;modelId&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Want to see more complex debugging scenarios with Amazon Q? Check out my colleagues' experiences solving a &lt;a href="https://community.aws/content/2fbWIDtx027BQjqmNNSA2R7sTqI/kafka-go-and-protocol-buffers-how-amazon-q-solved-a-nasty-data-deserialization-problem" rel="noopener noreferrer"&gt;data serialization problem&lt;/a&gt; and &lt;a href="https://community.aws/content/2fbDOb7FOMzJJgTdhmCam7DVW1s/ai-found-a-concurrency-bug-in-this-code-then-fixed-it" rel="noopener noreferrer"&gt;finding and fixing a concurrency bug&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Help me write tests
&lt;/h2&gt;

&lt;p&gt;I am an avid tester, so when I'm writing code, I'm often pairing it up with unit tests at a minimum. I have not had much experience using mocks in Python tests, so I asked Q &lt;code&gt;How would you write a test for the send_prompt_to_bedrock function using mocks?&lt;/code&gt; and got this response:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ellabgt38follcvw3gf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ellabgt38follcvw3gf.png" alt="Prompt " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It gets me a lot closer than had I started with a google search, dug through some documentation, and started by writing the boilerplate code myself. This response is an example customized to what I am doing, so I don't have to try to translate what one blog post author was trying to do in their situation to what I'm trying to do in my situation. I didn't spend much time getting this test to pass, most of my time was making sure the request/response objects were prepared correctly.&lt;/p&gt;

&lt;p&gt;Read more about how my colleagues are using Amazon Q for &lt;a href="https://community.aws/content/2gBZtC94gPzaCQRnt4P0rIYWuBx/shift-left-workload-leveraging-ai-for-test-creation" rel="noopener noreferrer"&gt;writing tests earlier&lt;/a&gt; and for &lt;a href="https://community.aws/content/2freQx3PAGvuHlULJ2kJ57WP34E/test-driven-development-with-amazon-q-developer" rel="noopener noreferrer"&gt;test driven development&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Hopefully the only thing you took away from this article wasn't that I'm a lazy developer! Here, I covered four different ways I'm tweaking my productivity as a developer so I can stay in the flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I'm reducing my context switching by staying in my IDE&lt;/li&gt;
&lt;li&gt;I'm getting support for my lazy developer mentality by generating boilerplate code, summarizing what code is doing, and getting help with refactoring&lt;/li&gt;
&lt;li&gt;I'm delegating my debugging work&lt;/li&gt;
&lt;li&gt;I'm getting help with writing my unit tests&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Are you ready to get started with Amazon Q Developer in your IDE? Check out how to set it up for &lt;a href="https://community.aws/content/2fVw1hN4VeTF3qtVSZHfQiQUS16/getting-started-with-amazon-q-developer-in-visual-studio-code" rel="noopener noreferrer"&gt;VS Code&lt;/a&gt; or &lt;a href="https://community.aws/content/2fXj10wxhGCExqPvnsJNTycaUcL/adding-amazon-q-developer-to-jetbrains-ides" rel="noopener noreferrer"&gt;JetBrains IDEs&lt;/a&gt; or even the &lt;a href="https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-getting-started-installing.html" rel="noopener noreferrer"&gt;command line&lt;/a&gt;. Amazon Q Developer just left Preview on April 30th and is continuously being improved based on your feedback. If something isn't working as you expect, you find a bug, or even have suggestions to improve how it works in your development flow, let me know in the comments!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>ai</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
