<?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: Anand Sukumaran</title>
    <description>The latest articles on DEV Community by Anand Sukumaran (@anandrmedia).</description>
    <link>https://dev.to/anandrmedia</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%2F810349%2Fcf268253-ae08-45ec-97b3-252c4cc858c4.png</url>
      <title>DEV Community: Anand Sukumaran</title>
      <link>https://dev.to/anandrmedia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anandrmedia"/>
    <language>en</language>
    <item>
      <title>Building an MCP Server in Javascript</title>
      <dc:creator>Anand Sukumaran</dc:creator>
      <pubDate>Sat, 16 Aug 2025 14:10:10 +0000</pubDate>
      <link>https://dev.to/anandrmedia/building-an-mcp-server-in-javascript-5133</link>
      <guid>https://dev.to/anandrmedia/building-an-mcp-server-in-javascript-5133</guid>
      <description>&lt;h2&gt;
  
  
  What is MCP?
&lt;/h2&gt;

&lt;p&gt;Model Context Protocol (MCP) is the hottest topic in AI world right now! Because it solves a major limitation of the LLMs. LLMs has limited knowledge based on the data on which it was training. It doesn't have any idea about the changes happened in the world after it's training cut-off.&lt;/p&gt;

&lt;p&gt;To solve this problem, we need external tools to give additional information to LLMs. And depending on the judgement of the LLM, it should be able to call these tools whenever required, and the tool will pass the information back to LLM (by calling an external API or so).&lt;/p&gt;

&lt;p&gt;And you can consider MCP as the standardised way to build these external tools. The simplest analogy is if your laptop is an LLM, then USB connector the MCP and the different USB drivers you plugin through this connector are the tools (that provides additional information to your laptop)&lt;/p&gt;

&lt;h2&gt;
  
  
  Building an MCP Server in Javascript
&lt;/h2&gt;

&lt;p&gt;In this article, we will use the &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt; npm package to build a simple MCP server. This MCP server will have the ability to fetch the latest documentations for any given npm package, so the LLM clients using this MCP server don't have to rely on its outdated information about npm packages.&lt;/p&gt;

&lt;p&gt;For example, if you're using Cursor and vibe coding a JS project and you're importing lot of npm packages in your project. But Cursor have no idea how to implement the npm package as per it's latest doc. So it might hallucinate and cause errors, or do some outdated implementation.&lt;/p&gt;

&lt;p&gt;But with our MCP server, it can query and get the official README.md file of the npm package from it's official github repository!&lt;/p&gt;

&lt;h2&gt;
  
  
  Components in our MCP Server
&lt;/h2&gt;

&lt;p&gt;In the MCP server that we're going to build here, we'll have only one tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;get_docs_for_npm_package&lt;/code&gt; and the input parameter is &lt;code&gt;packageName&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tool will fetch the &lt;code&gt;README.md&lt;/code&gt; file from it's github repository and return the raw contents of that file!&lt;/p&gt;

&lt;p&gt;That's it! A simple, yet useful MCP server!&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's start building
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Install the dependencies&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @modelcontextprotocol/sdk zod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Let's create the MCP server object&lt;/strong&gt;&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;server&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;McpServer&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm-package-docs-mcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0.0&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;&lt;strong&gt;&lt;em&gt;Register the tool&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We'll register the tool, describe it, specifcy the input schema and also write the callback function.&lt;/p&gt;

&lt;p&gt;For describing and validating the input parameter, we should use the &lt;a href="https://zod.dev/" rel="noopener noreferrer"&gt;zod&lt;/a&gt; library.&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="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_docs_for_npm_package&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Get Docs for NPM Package&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Get the docs for a npm package&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
        &lt;span class="na"&gt;packageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&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;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name of the npm package&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="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;packageName&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="c1"&gt;// We should use the official npmjs registry api to get the package details&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registryResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://registry.npmjs.org/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;packageName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/latest`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&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;as&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;url&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="c1"&gt;// Fetch the repository URL from the response&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;repositoryUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;registryResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;//Format the URL and extract the Github repo URL and the repository path&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;githubUrl&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;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repositoryUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;git+&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="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;repositoryPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;githubUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.git&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="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Now, lets get the README.md file content using raw.githubusercontent URL. Here we assume the branch is main&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;readmeUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://raw.githubusercontent.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;repositoryPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/refs/heads/main/README.md`&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;readmeResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;readmeUrl&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;readmeContent&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;readmeResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;//Just return the content of the README.md file as text response. That's it!&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;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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&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;readmeContent&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;Done! Our MCP server is ready! &lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the MCP Server
&lt;/h2&gt;

&lt;p&gt;To test this MCP server, we can either use the &lt;code&gt;@modelcontextprotocol/inspector&lt;/code&gt; tool by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;@modelcontextprotocol/inspector npx ts-node src/index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you've &lt;code&gt;ts-node&lt;/code&gt; dependency added to your project and the correct server file path in the argument.&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%2Fiszu9x46h9w9vyeqbww8.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%2Fiszu9x46h9w9vyeqbww8.png" alt=" " width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this inspector tool, you can view the tools in your MCP Server and even test them by providing the input values!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding this MCP Server to your Cursor IDE
&lt;/h2&gt;

&lt;p&gt;You can simply add this MCP server to your Cursor IDE (or any MCP Client), with this configuration&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;"npm-package-docs-mcp"&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 ts-node /full-path-to-your-mcp-server/src/index.ts"&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;"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="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;
  
  
  Video Tutorial
&lt;/h2&gt;

&lt;p&gt;You can watch the video tutorial on creating an MCP server in Javascript here - &lt;a href="https://www.youtube.com/watch?v=H4Odxtncxrk" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=H4Odxtncxrk&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Source code
&lt;/h2&gt;

&lt;p&gt;The source code for the fully functional MCP server that fetches npm package docs is available here - &lt;a href="https://github.com/meanands/npm-package-docs-mcp" rel="noopener noreferrer"&gt;https://github.com/meanands/npm-package-docs-mcp&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>modelcontextprotocol</category>
      <category>javascript</category>
      <category>llm</category>
    </item>
    <item>
      <title>How to create a Youtube video summariser agent using EnvoyJS</title>
      <dc:creator>Anand Sukumaran</dc:creator>
      <pubDate>Thu, 23 Jan 2025 16:44:58 +0000</pubDate>
      <link>https://dev.to/anandrmedia/how-to-create-a-youtube-video-summariser-agent-using-envoyjs-1d10</link>
      <guid>https://dev.to/anandrmedia/how-to-create-a-youtube-video-summariser-agent-using-envoyjs-1d10</guid>
      <description>&lt;p&gt;In this tutorial, I will explain how you can build a Youtube video summariser AI agent using &lt;a href="https://github.com/anandrmedia/envoyjs" rel="noopener noreferrer"&gt;EnvoyJS&lt;/a&gt;, a minimal agentic framework in Javascript.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea
&lt;/h2&gt;

&lt;p&gt;We will create a youtube video summariser agent and instruct them about their job. We will supply YoutubeTranscript tool to the agent so it can fetch the transcript of a given video.&lt;/p&gt;

&lt;p&gt;We can either use the gpt-4o model, or deep-seek for this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install EnvoyJS library
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @envoyjs/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Import EnvoyJS library, and Youtube Transcript tool
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;youtubeTranscriptTool&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;@envoyjs/core&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;h2&gt;
  
  
  Create the agent
&lt;/h2&gt;

&lt;p&gt;Let's create our agent using the &lt;code&gt;Agent&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agent&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;Agent&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content Summariser Agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;bio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are an expert in reading YouTube video transcripts and summarizing what the video is about.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;steps&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;Read the transcript&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;Understand the entire context&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;Find relevant portions&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;Summarize as text&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;Save it as a file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;modelConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OPEN_AI&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;apiKey&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="c1"&gt;// Don't forget to add your OpenAI API key&lt;/span&gt;
        &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4o&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;youtubeTranscriptTool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileWriterTool&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// Add tools here&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this class, we're giving instructions to the agent on how to do the task. We have given a &lt;code&gt;bio&lt;/code&gt;, and then &lt;code&gt;steps&lt;/code&gt; instructions on how to perform!&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the agent!
&lt;/h2&gt;

&lt;p&gt;Let's prompt the agent to do the work using the &lt;code&gt;print_response()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;printResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Summarise this youtube video - https://www.youtube.com/watch?v=QtYEPYntfL4&amp;amp;t=27s&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;Now sitback and see how the agent analyses the task, take decisions to use the tool to fetch the transcript and summarise the video for you! &lt;/p&gt;

</description>
      <category>envoyjs</category>
      <category>agentic</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to build an AI Agent in Javascript from scratch</title>
      <dc:creator>Anand Sukumaran</dc:creator>
      <pubDate>Mon, 20 Jan 2025 18:53:20 +0000</pubDate>
      <link>https://dev.to/anandrmedia/how-to-build-an-ai-agent-in-javascript-from-scratch-5b6l</link>
      <guid>https://dev.to/anandrmedia/how-to-build-an-ai-agent-in-javascript-from-scratch-5b6l</guid>
      <description>&lt;p&gt;In this tutorial, I'll explain how to build a simple appointment scheduler AI Agent from scratch in Javascript.  We won't be using any agentic AI frameworks.&lt;/p&gt;

&lt;p&gt;So you will understand how agents work without any abstractions!&lt;/p&gt;

&lt;p&gt;I've published the same tutorial as a video on Youtube as well. You can check that &lt;a href="https://www.youtube.com/watch?v=Uq9WlPnT5iw" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture of the AI Agent
&lt;/h2&gt;

&lt;p&gt;You already know what an &lt;a href="https://dev.to/anandrmedia/ai-workflows-vs-ai-agents-whats-the-difference-5fk6"&gt;LLM&lt;/a&gt; is. It is similar to a human brain. It can think and take decisions. But cannot execute things without the help of some external tools. Just like how brain uses hands, legs and other organs to perform tasks!&lt;/p&gt;

&lt;p&gt;So, an LLM combined with external tools, and a process for cordinating this could be defined as an "AI Agent".&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%2Fv9vejnmf2vkkm1h4tntj.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%2Fv9vejnmf2vkkm1h4tntj.png" alt=" " width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our case, the Node program will act as the controller who'll interact with the LLM and interfaces it to external tools, and the end-user.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Javascript and Typescript&lt;/li&gt;
&lt;li&gt;OpenAI API Key&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/readline" rel="noopener noreferrer"&gt;Readline&lt;/a&gt; library for accepting inputs from commandline&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Note: The finished source code of this agent is available on &lt;a href="https://github.com/anandrmedia/ai-agent-js-scratch" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Import the dependencies and initialize them
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&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;openai&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;readline&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;readline&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;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&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="nx"&gt;rl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createInterface&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;input&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;stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;output&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;stdout&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Define the &lt;code&gt;messages&lt;/code&gt; array
&lt;/h3&gt;

&lt;p&gt;We'll define a global &lt;code&gt;messages&lt;/code&gt; array for storing the inputs from the end-user, and the responses from the llm. We'll feed the LLM with this array so that the LLM have the entire context of the conversation!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&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;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Define the SYSTEM_PROMPT
&lt;/h3&gt;

&lt;p&gt;The system prompt is what makes the LLM capable of doing these tasks. We're simply instructing the LLM to act as a scheduler agent, defining his duties and finally the list of available functions the agent can use!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SYSTEM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
You are an appointment scheduler AI agent. You're always interacting with a system. You have the ability to do function calls. 
Your response can be either a reply to the user, or to the system to do a function call. But you cannot reply to the user and system in the same response.
So your response should be in JSON format as specified. -

{
    "to": ""
    "message": "",
    "function_call": {
       "function": "",
       "arguments": []
    }
}

I will explain the keys -

1. to - values could be system or user, depending on whom you are replying
2. message - plain text message. Use this only if you are replying to the user not system
3. function_call - Use this only if you are replying to the system. It is a JSON object that determines which function to call, and it's arguments.
4 a. function - name of the function
4 b. arguments - An array of arguments for the function call where each array item is the value for the argument.

Available functions:

function name - check_appointment_availability
arguments - datetime (ISO 8601 format, UTC timezone)

function name - schedule_appointment
arguments - datetime (ISO 8601 format, UTC timezone), name (String), email (string)

function name - delete_appointment
arguments - datetime (ISO 8601 format, UTC timezone), name (String), email (string)

Here are some instructions - 

Chat with user who wants to schedule an appointment with your owner.
Ask if they have any choice for the appointment time.
You must be able to understand that users might be from a different time zone.
Always use their timezone while chatting about times and dates to the user.
Before scheduling the appointment, you must ask their name and email.
Your owner is in IST timezone (+05:30)
Time and date now for your owner is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;getCurrentTimeInTimeZone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Asia/Kolkata&lt;/span&gt;&lt;span class="dl"&gt;"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;**Key points to note here&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We're instructing the LLM to always respond in a JSON format.&lt;/li&gt;
&lt;li&gt;LLM can respons either to the system (this node program), or to the end user.&lt;/li&gt;
&lt;li&gt;LLM must think and decide which functions to call based on the end users requirement.&lt;/li&gt;
&lt;li&gt;If a function call is requested, the system (this node program) will execute the function and feed back the response into the LLM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;**### Push the system prompt to &lt;code&gt;messages&lt;/code&gt; array&lt;/p&gt;

&lt;p&gt;As we mentioned, we need to push the prompt to our &lt;code&gt;messages&lt;/code&gt; array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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="s1"&gt;system&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="nx"&gt;SYSTEM_PROMPT&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Define the functions
&lt;/h3&gt;

&lt;p&gt;As we instructed the LLM, we need to define the available functions. For simplicity we will instruct all functions to return &lt;code&gt;true&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;check_appointment_availability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Calling check_appointment_availability &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;schedule_appointment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Calling schedule_appointment &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;delete_appointment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Calling delete_appointment &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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;We will also define a function map to call these functions dynamically by using their name from a string variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;function_map&lt;/span&gt; &lt;span class="o"&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;check_appointment_availability&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;check_appointment_availability&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;schedule_appointment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;schedule_appointment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete_appointment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;delete_appointment&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;any&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Defint the &lt;code&gt;send_to_llm&lt;/code&gt; function
&lt;/h3&gt;

&lt;p&gt;This is the one of the core components of this script. This function accepts a message, adds it to the &lt;code&gt;messages&lt;/code&gt; array, and then finally pass the entire array to LLM and wait for it to respond.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;send_to_llm&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="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

    &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&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="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="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-4o&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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;choices&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="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&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;choices&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="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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also see that, once the response is received, we're pushing the response back to the &lt;code&gt;messages&lt;/code&gt; array so the entire conversation history can be maintained.&lt;/p&gt;

&lt;h3&gt;
  
  
  Define the &lt;code&gt;process_llm_response&lt;/code&gt; function
&lt;/h3&gt;

&lt;p&gt;When we receive an input from the LLM, it could be for two purposes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send a message to the end user&lt;/li&gt;
&lt;li&gt;Execute a function call&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;process_llm_response&lt;/code&gt; function will parse the received response and do the appropriate action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;process_llm_response&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;any&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;parsedJson&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;parse&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="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedJson&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="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&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;parsedJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system&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;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parsedJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;function_call&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parsedJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;function_call&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functionResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;function_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;](...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;process_llm_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;send_to_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;response is &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;functionResponse&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&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="s1"&gt;false&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;p&gt;Here, if the message is sent to the &lt;code&gt;user&lt;/code&gt;, then we're simply printing it using &lt;code&gt;console.log()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, if the message is for the &lt;code&gt;system&lt;/code&gt;, we will find the function name, arguments and finally call the function using the &lt;code&gt;function_map&lt;/code&gt; we defined before.&lt;/p&gt;

&lt;p&gt;The response from the function is fed back into the LLM in a specific format, and we'll call the same &lt;code&gt;process_llm_response&lt;/code&gt; function to process the response!&lt;/p&gt;

&lt;h2&gt;
  
  
  Combining everything
&lt;/h2&gt;

&lt;p&gt;Finally, we will write the &lt;code&gt;main()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * main function
 */
async function main(){

    while(true){

        const input: string = await new Promise((resolve)=&amp;gt;{
            rl.question("Say something: ", resolve);
        });

        const response = await send_to_llm(input);
        await process_llm_response(response);

    }

}

main();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we will first accept an input from the user using the &lt;code&gt;readline&lt;/code&gt; library. And then the input is fed into the LLM using the &lt;code&gt;send_to_llm&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Then the response is processed using the &lt;code&gt;process_llm_response&lt;/code&gt; function, which decides whether to print the response, or to execute a function!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Building an agent is not rocket science. It's just instructing the LLM to cordinate with a system program (such as this node script), to execute function or API calls and return the responses accordingly!&lt;/p&gt;

&lt;p&gt;As mentioned earlier, this tutorial is available as a video on Youtube as well. You can check that &lt;a href="https://www.youtube.com/watch?v=Uq9WlPnT5iw" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How RAG works? Retrieval Augmented Generation Explained</title>
      <dc:creator>Anand Sukumaran</dc:creator>
      <pubDate>Wed, 15 Jan 2025 12:10:20 +0000</pubDate>
      <link>https://dev.to/anandrmedia/how-rag-works-retrieval-augmented-generation-explained-1jf4</link>
      <guid>https://dev.to/anandrmedia/how-rag-works-retrieval-augmented-generation-explained-1jf4</guid>
      <description>&lt;p&gt;You might have heard the term RAG, or Retrieval-Augmented Generation, explained, but you might not know exactly what it is or how it works. This article is for you! Here, I will explain what RAG is, why it is needed, and how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before that, a quick dive into how an LLM works
&lt;/h2&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%2F88ythz3f3ksbcuii0hj2.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%2F88ythz3f3ksbcuii0hj2.png" alt="Image description" width="571" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An LLM is simply a deep-learning model trained on a large corpus of text data. Think of it this way: a human baby is born completely new to the world and doesn’t know anything. However, as the baby grows, they learn by observing, listening, reading, and more. By the age of 18 or so, they have accumulated significant knowledge about the world and can make informed decisions.&lt;/p&gt;

&lt;p&gt;Similarly, an LLM is trained using all the text data available on the internet. It has absorbed information from public forum conversations, online books, blogs, research papers, and more. As a result, it knows how to generate text in a human-like manner and possesses knowledge about the world based on what it has read.&lt;/p&gt;

&lt;h2&gt;
  
  
  You know what is prompting, but have you heard of context window?
&lt;/h2&gt;

&lt;p&gt;You interact with an LLM by writing prompts or instructions, just as you would when talking to a human. Now, imagine this scenario: you are explaining a complex task with multiple steps to a friend. After hearing your instructions, the friend says, 'Whoa, whoa... I missed that. Can you slow down so I can take notes?'&lt;/p&gt;

&lt;p&gt;LLMs face a similar challenge. They can only handle a specific amount of input, prompt, or instructions at one time. This limitation is known as the context window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just tell me what is RAG!
&lt;/h2&gt;

&lt;p&gt;Exactly, now you understand that there’s a limit to the amount of context or information you can pass to an LLM. Now, think about this scenario: you want the LLM to understand a huge book (which you’ll provide) and then answer questions on topics from that book.&lt;/p&gt;

&lt;p&gt;The LLM is helpless here for two reasons. First, it hasn’t read this book during its initial training, so it has no prior knowledge of it. Second, the book is so large that it exceeds the context window limit of the LLM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ok, so RAG is a workaround for the context window size limit?
&lt;/h2&gt;

&lt;p&gt;Exactly, you're getting there! RAG is a technique used to solve this context-window size limit. I'll explain how!&lt;/p&gt;

&lt;p&gt;Consider the previous example. When you have a question about that book, what would you do manually? Would you read the book from page one all the way to the end? Of course not! Instead, you’d go to the index, find the relevant section, and refer to just that section, right?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is what RAG is!&lt;/strong&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%2Fnw0naidty3ll0uejjcf4.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%2Fnw0naidty3ll0uejjcf4.png" alt="Image description" width="572" height="663"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you ask a question, another service matches the context of your question to different sections of the book. This is achieved by performing a similarity search on a vector database. (The details of this process are beyond the scope of this article.)&lt;/p&gt;

&lt;p&gt;It’s important to note that this matching process is not done by the LLM itself but by a separate service.&lt;/p&gt;

&lt;p&gt;Once the relevant section is identified, it is retrieved and combined with your original question. This process is called Augmenting the Prompt.&lt;/p&gt;

&lt;p&gt;By providing the LLM with this additional knowledge, it is now equipped to think and answer your question accurately and effectively.&lt;/p&gt;

&lt;p&gt;It’s a simple concept, but it significantly improves the performance of an LLM!&lt;/p&gt;

&lt;p&gt;If you’re interested in learning more AI topics explained in a simplified way, consider following me here. I’ll be sharing more articles that break down complex concepts into easy-to-understand explanations.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ai</category>
      <category>llm</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>AI Workflows vs AI Agents — What’s the Difference?</title>
      <dc:creator>Anand Sukumaran</dc:creator>
      <pubDate>Wed, 15 Jan 2025 05:47:53 +0000</pubDate>
      <link>https://dev.to/anandrmedia/ai-workflows-vs-ai-agents-whats-the-difference-5fk6</link>
      <guid>https://dev.to/anandrmedia/ai-workflows-vs-ai-agents-whats-the-difference-5fk6</guid>
      <description>&lt;p&gt;The tech world is abuzz with talk about one thing — AI Agents! Everywhere you turn — YouTube, Instagram, X — you hear both excitement and fear about AI agents taking over jobs. &lt;/p&gt;

&lt;p&gt;But before AI agents became the topic of discussion, people were already discussing AI Workflows. So, what’s the difference between these two concepts? Let’s explore.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Workflow (Non-AI Workflow)?
&lt;/h2&gt;

&lt;p&gt;A workflow, or automation workflow, has been around for a long time. Businesses use it to complete complex tasks involving multiple steps. &lt;/p&gt;

&lt;p&gt;For example, consider a leave approval workflow in your company. You send a leave request through the HR portal. It goes to your engineering manager for acknowledgment, then to an HR person for approval, and finally, you receive a confirmation email about your leave status.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, What is an AI Workflow?
&lt;/h2&gt;

&lt;p&gt;Simple - using the AI logic in a particular step in your workflow, such as predicting something, calculating some score etc.&lt;/p&gt;

&lt;p&gt;In the HR leave request example we discussed, humans were involved in decision-making at certain steps. For instance, your manager decided whether to approve your leave based on factors like your reason for taking leave, the workload, and deadlines.&lt;/p&gt;

&lt;p&gt;But what if AI logic was integrated into this workflow? AI could analyze data points about your past leave history, workload, and other relevant factors to make an initial decision. This would save time for your manager while keeping the workflow intact. &lt;/p&gt;

&lt;p&gt;The only difference here is that AI logic augments human decision-making in certain steps, and the workflow steps remains the same!&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%2Fa2cgn5k0hp5ujdqdgkuf.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%2Fa2cgn5k0hp5ujdqdgkuf.png" alt="Image description" width="611" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an AI Agent?
&lt;/h2&gt;

&lt;p&gt;As we saw before, using “AI logic” in one or more steps of a workflow seems sufficient, right? Yes, but AI can do more! Let’s think about a more complex scenario.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customer support example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose a customer contacts your company with a support request. Their query could be about a product feature, a warranty claim, a refund, or something entirely unique. &lt;/p&gt;

&lt;p&gt;You cannot pre-define a workflow to handle every possible situation, because you don't know what the customer is asking. Even if you provide the customer with a menu of options to choose from, some cases might not fit into any of them. I'm sure you might felt similar frustration as a user many times.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is where AI Agent helps
&lt;/h2&gt;

&lt;p&gt;An AI agent can handle &lt;strong&gt;such open-ended&lt;/strong&gt; scenarios. First, the agent analyzes the customer’s message to understand the context. It then asks relevant questions to gather more details using &lt;a href="https://dev.to/anandrmedia/how-rag-works-retrieval-augmented-generation-explained-1jf4"&gt;RAG&lt;/a&gt;, dynamically deciding on the next steps without relying on pre-defined workflows. And guess what, it can even decide which tools to be used to solve this case!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coming back to the same customer support example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, the agent reads the customer email. Now it thinks and figure out what this is about. Let's say it determine that the customer’s issue stems from an unusual product configuration, causing error.&lt;/p&gt;

&lt;p&gt;At this moment, the next steps of this resolution workflow might seem totally different than a refund issue, or a billing issue.&lt;/p&gt;

&lt;p&gt;So, the &lt;strong&gt;agent makes a plan&lt;/strong&gt;, on how to proceeed.&lt;/p&gt;

&lt;p&gt;So in this case - It can then suggest tailored troubleshooting steps, by searching an FAQ database. If the customer provides feedback or encounters further errors, the agent adjusts its actions accordingly.&lt;/p&gt;

&lt;p&gt;Let’s say the issue turns out to be a rare error requiring engineering intervention. The agent can understand this, create a support ticket, using the support ticketing as the tool, assign it to an engineer, and notify the customer that the issue has been escalated. All of this happens dynamically, driven by the agent’s ability to think, reason, and act using given tools, just like a human!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here is another example -&lt;/strong&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%2Fja238aj8krqtik693y1j.jpg" 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%2Fja238aj8krqtik693y1j.jpg" alt="Image description" width="471" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes AI Agents Different for Customers?
&lt;/h2&gt;

&lt;p&gt;Customers often dislike chatbots that rely on rigid, predefined steps because they feel these bots cannot address unique or complex issues.&lt;/p&gt;

&lt;p&gt;In contrast, an AI agent is intelligent, flexible, and can even take actions, not just chat! It gathers the necessary information, analyzes the problem, and decides on appropriate actions. It can even escalate the issue to the right team when needed. This personalized approach builds trust and confidence, making the customer experience seamless and efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can I make an AI Agent?
&lt;/h2&gt;

&lt;p&gt;There are lot of agentic frameworks (code and low-code/no-code) available to build your agents!&lt;/p&gt;

&lt;p&gt;Some of them are -&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://crewai.com" rel="noopener noreferrer"&gt;https://crewai.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.langflow.org" rel="noopener noreferrer"&gt;https://www.langflow.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.phidata.com" rel="noopener noreferrer"&gt;https://www.phidata.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ag2.ai" rel="noopener noreferrer"&gt;https://ag2.ai&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'll be writing a post on how to build your own AI agents using these frameworks!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future of AI Agents
&lt;/h2&gt;

&lt;p&gt;This year, we are likely to see more and more cases where AI agents solve complex problems that traditional workflows cannot handle. These agents will not just automate tasks — they will think, reason, use tools, and act, bringing us closer to intelligent robots who thinks like humans!&lt;/p&gt;

&lt;p&gt;You can learn more about the basic concepts of AI and AI-Agents from my Youtube video here -&amp;gt; &lt;a href="https://www.youtube.com/watch?v=QtYEPYntfL4" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=QtYEPYntfL4&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agenticai</category>
      <category>agents</category>
      <category>llm</category>
      <category>aiagents</category>
    </item>
    <item>
      <title>Notifications still disappoint! It needs to be re-invented</title>
      <dc:creator>Anand Sukumaran</dc:creator>
      <pubDate>Sun, 17 Mar 2024 19:50:22 +0000</pubDate>
      <link>https://dev.to/anandrmedia/notifications-still-disappoint-it-needs-to-be-re-invented-2fp2</link>
      <guid>https://dev.to/anandrmedia/notifications-still-disappoint-it-needs-to-be-re-invented-2fp2</guid>
      <description>&lt;p&gt;In every app (web/mobile) development project I worked, there wasn't a single one that didn't need notification.&lt;/p&gt;

&lt;p&gt;Notification in the sense, any form of communication with the user. It's &lt;strong&gt;not&lt;/strong&gt; just push notifications! It could be email, it could be SMS, call, slack or anything.&lt;/p&gt;

&lt;p&gt;It could be triggered from the product such as welcome emails, or subscription reminders or even when two users interact within the product such as liking or replying to someone else's content.&lt;/p&gt;

&lt;p&gt;Usually, for web apps, we try to deliver these messages through email and for mobile apps, we stick to push notifications because that's the norm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the best communication channel!
&lt;/h2&gt;

&lt;p&gt;Think of yourself. You know what's the best way to reach your friends. Some of them are active on email, some of them are best reached via WhatsApp, some of them like calls, Facebook, LinkedIn.&lt;/p&gt;

&lt;p&gt;But what about the apps we make? Unfortunately, our apps don't have this ability. Why? Because the app developers can't just integrate a dozen of communication APIs to their backend!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It could result in&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Sending the same message across every other channel, annoying your users or&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Users not getting the right message at the right time, thus leading to delayed replies or actions!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What's the fix?
&lt;/h2&gt;

&lt;p&gt;Accept the fact that, there is no one best channel to reach your user. And having too many channels won't be good either.&lt;/p&gt;

&lt;p&gt;The best thing is to find the right channel based on the context and the message. Let's take a look at few examples.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sending a welcome message.
&lt;/h4&gt;

&lt;p&gt;Email is widely used for this. But, users are already on your app. Why send an email? They might read it later. But if it has some information to help the user NOW, you lost the context. You should have shown the message inside the app.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sending offers or promotions to an e-commerce app
&lt;/h4&gt;

&lt;p&gt;Usually, this is sent as push notifications. But do you know how many push notifications stacked on your phone's notification tray? And at the end of the day you clear them all at once and boom! Where are the offers now?&lt;/p&gt;

&lt;p&gt;Again, the best way here is to have a message inbox that sits inside your app with the entire message history. So if a user wants that promo code you sent via push, they can find it there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have you observed the pattern here?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The best channel depends on the context. If users are spending more time on the app, In-App is undoubtedly the best channel. If not, then the next best might be Push. If they're offline, and if it's really urgent, it could be SMS, or else Email.&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%2F00vetkfyq8zdibj15kfm.jpg" 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%2F00vetkfyq8zdibj15kfm.jpg" alt="Image description" width="538" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What does this means for developers?
&lt;/h2&gt;

&lt;p&gt;So, for developers, it's not easy as integrating an Email API or an SMS API. You need to build a smart communication layer that understands what's the best channel to reach and when.&lt;/p&gt;

&lt;p&gt;Let's consider this scenario. We have a support ticketing app and the support agent gets a new ticket from a customer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the best way to notify the agent so he can proactively take action?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;If the agent is currently online and working on the app, then a realtime In-App message would be the best to get their attention.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the agent is online, but away from the app, a push notification will do the job!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the agent has snoozed all notifications, then sending it in an email, and a copy inside the In-App inbox makes sure they see it when they're back.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If it's top priority (like your server is on fire), call might be the best channel ever!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2Fc08sohvm64wi1c0kl28p.jpg" 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%2Fc08sohvm64wi1c0kl28p.jpg" alt="Image description" width="742" height="842"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Delivering a message doesn't ends with a single step. It's a workflow!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying the communication triggers
&lt;/h2&gt;

&lt;p&gt;Most likely, you're under communicating with your users. No I'm not talking about the mass promotional notifications or emails you sent. That you should limit anyways!&lt;/p&gt;

&lt;p&gt;I mean the important messages that your users needs to know. For example if you're building a server deployment tool, what are some important communication triggers that adds value?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you let users know when a deployment fails?&lt;/li&gt;
&lt;li&gt;How do they know when a health-check fails?&lt;/li&gt;
&lt;li&gt;How do they know if a deployment is waiting approval?&lt;/li&gt;
&lt;li&gt;What if a infrastructure fails when the user is offline?&lt;/li&gt;
&lt;li&gt;How do they take action out of the alert they received?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unless you effectively communicate with the user about these events, they're missing something. These communication triggers are not a luxury but a necessary feature of your product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, developers must make sure it is easy to build new communication triggers as required&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Respect the user's preferences.
&lt;/h2&gt;

&lt;p&gt;This is important. Even if your system is smart enough to find the best channel to notify a user, it's ultimately their choice.&lt;/p&gt;

&lt;p&gt;How do you do this? Allow them to set their preferences on every communication trigger from your app. Let them choose the frequency. For less-important messages, allow them to get multiple messages batched together instead of sending them one by one!&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%2Fyomw9h7ekh2dwgitm4a4.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%2Fyomw9h7ekh2dwgitm4a4.png" alt="Image description" width="800" height="824"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a developer-first notification infrastructure!
&lt;/h2&gt;

&lt;p&gt;A problem that appeared to be very trivial in the beginning has now become a huge project with several months of effort.&lt;/p&gt;

&lt;p&gt;Now the question is about whether you should spend at least 6 months of your engineering team's effort in building this from scratch or just buy the API?&lt;/p&gt;

&lt;p&gt;Well, engineering teams at companies are almost always occupied. So, trying to build this in-house will probably take you at least an year if you start planning now.&lt;/p&gt;

&lt;p&gt;At Engagespot, we are building a &lt;a href="https://engagespot.co?ref=dev_to_article" rel="noopener noreferrer"&gt;notification infrastructure&lt;/a&gt; for developers to help them build a delightful communication experience in minutes!&lt;/p&gt;

&lt;p&gt;And unlike our competitors, we focus on making notifications actionable, and provides deep integration capabilities with your existing 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%2Fql66bknt4lyrcvp42o9g.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%2Fql66bknt4lyrcvp42o9g.png" alt="Image description" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To learn more about Engagespot, check our website - &lt;a href="https://engagespot.co" rel="noopener noreferrer"&gt;https://engagespot.co&lt;/a&gt;. And good news, we got selected to Techstars NYC 24 batch, one of the top startup accelerators in the world!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Having a great communication experience is a necessity for your product's success. It's not just about regular marketing communication. It's about how your users get informed about the things that they should know, and how quickly they can take action.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>notification</category>
      <category>react</category>
    </item>
    <item>
      <title>How to setup SES Email templates [2024 Guide]</title>
      <dc:creator>Anand Sukumaran</dc:creator>
      <pubDate>Sat, 17 Feb 2024 05:31:35 +0000</pubDate>
      <link>https://dev.to/anandrmedia/how-to-setup-ses-email-templates-2024-guide-5efg</link>
      <guid>https://dev.to/anandrmedia/how-to-setup-ses-email-templates-2024-guide-5efg</guid>
      <description>&lt;p&gt;When I want to build transactional emails in my apps, AWS SES is my first choice! There are several alternatives like Sendgrid, Mailgun but when it comes to pricing, AWS SES wins!&lt;/p&gt;

&lt;p&gt;But the only drawback is that, AWS SES doesn't offer any template editors. Developers should write HTML to build good looking emails, and keep them in S3. &lt;/p&gt;

&lt;p&gt;But that's boring, difficult and hard to maintain.&lt;/p&gt;

&lt;p&gt;In this tutorial, I'll show you an alternative, an easiest way to &lt;a href="https://engagespot.co/notification-templates" rel="noopener noreferrer"&gt;setup SES email templates&lt;/a&gt; using a free tool - Engagespot!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configured SES account&lt;/li&gt;
&lt;li&gt;Engagespot account (&lt;a href="https://console.engagespot.co/auth/register" rel="noopener noreferrer"&gt;signup here&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up SES Email templates
&lt;/h2&gt;

&lt;p&gt;Login to your Engagespot account, navigate to channels -&amp;gt; Enable the AWS SES Email Provider with the API key and secret.&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%2Fnl7s6fdfgnmc56kly1s0.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%2Fnl7s6fdfgnmc56kly1s0.png" alt="Image description" width="800" height="971"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, navigate to Templates and create a new template and add Email channel to it. Now you'll get the email editor.&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%2F6qlih82h78ilbamx191l.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%2F6qlih82h78ilbamx191l.png" alt="Image description" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build a beautiful email editor using one of the existing layouts, or create one from scratch yourself.&lt;/p&gt;

&lt;p&gt;You can also test the template directly using the "Test" template option available in the dashboard!&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending the SES Email template from your backend
&lt;/h2&gt;

&lt;p&gt;Now, to trigger the email template you've created using the SES provider, we will use the &lt;a href="https://docs.engagespot.co/docs/rest-api" rel="noopener noreferrer"&gt;Engagespot REST API&lt;/a&gt;, or a library such as &lt;a href="https://www.npmjs.com/package/@engagespot/node" rel="noopener noreferrer"&gt;@engagespot/node &lt;/a&gt; or &lt;a href="https://packagist.org/packages/engagespot/php-sdk" rel="noopener noreferrer"&gt;Engagespot PHP library&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're using the REST API, this is how you can simply send the templated SES email to your user!&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%2Fhtmgpeb9vzhvehljsqn6.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%2Fhtmgpeb9vzhvehljsqn6.png" alt="Image description" width="800" height="1180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Done! All it took was less than a few minutes! &lt;br&gt;
You can edit the template anytime without having to touch your code!&lt;/p&gt;

</description>
      <category>ses</category>
      <category>aws</category>
      <category>email</category>
      <category>node</category>
    </item>
    <item>
      <title>How to send email attachments using nodemailer</title>
      <dc:creator>Anand Sukumaran</dc:creator>
      <pubDate>Sun, 23 Oct 2022 03:50:06 +0000</pubDate>
      <link>https://dev.to/anandrmedia/how-to-send-email-attachments-using-nodemailer-2n5e</link>
      <guid>https://dev.to/anandrmedia/how-to-send-email-attachments-using-nodemailer-2n5e</guid>
      <description>&lt;p&gt;Nodemailer is a popular library in Node.js to send emails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features of nodemailer are&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has zero dependencies&lt;/li&gt;
&lt;li&gt;Secure email delivery with SSL/TLS support&lt;/li&gt;
&lt;li&gt;Supports email transport via popular providers like Amazon SES, Sendgrid etc.&lt;/li&gt;
&lt;li&gt;Easy to add attachments unlike other libraries.&lt;/li&gt;
&lt;li&gt;In this tutorial we’ll learn how to send email attachments using nodemailer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;1. First, add nodemailer to our project.&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm i nodemailer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Now let’s create a transport&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Like I mentioned above, nodemailer supports other thirdparty providers to be used as transport like Amazon SES, Sendgrid, Mailgun, SMTP etc. In this example, we’ll use SMTP transport.&lt;/p&gt;

&lt;p&gt;I’ll be using Typescript for this example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&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;nodemailer&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;smtpTransport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTransport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;smtp.example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;587&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;secure&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="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&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;p&gt;&lt;strong&gt;3. Construct the email body&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can create the email body as an object with from, to, subject and html.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mailBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;receiver@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sample email sent using nodemailer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;&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;&lt;strong&gt;4. Let’s add our attachment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nodemailer supports different types of attachments like base64, file path, stream etc. To get the complete list of attachment supported by nodemailer, refer their documentation.&lt;/p&gt;

&lt;p&gt;In this example, we’ll be using file path. So, let’s modify our mailBody.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mailBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;receiver@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sample email sent using nodemailer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;attachments&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;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sample_attachment.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;__dirname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sample_attachment.png&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Send the email&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To send the email, use the &lt;code&gt;transport.sendMail()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;smtpTransport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mailBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &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;info&lt;/span&gt;&lt;span class="p"&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;error&lt;/span&gt;&lt;span class="p"&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;log&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="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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email with attachment delivered successfully&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final code to send email attachments using Nodemailer.
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&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;nodemailer&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;smtpTransport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTransport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;smtp.example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;587&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;secure&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="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mailBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;receiver@gmail.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sample email sent using nodemailer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;attachments&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;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sample_attachment.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;__dirname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sample_attachment.png&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;smtpTransport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mailBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &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;info&lt;/span&gt;&lt;span class="p"&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;error&lt;/span&gt;&lt;span class="p"&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;log&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="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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email with attachment delivered successfully&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple! Hope this tutorial has helped you to understand how to &lt;a href="https://engagespot.co/blog/nodemailer-attachments-email-nodejs" rel="noopener noreferrer"&gt;send attachments using nodemailer&lt;/a&gt; in your email notifications.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>node</category>
      <category>nodemailer</category>
    </item>
    <item>
      <title>Migrating a MySQL database to AWS RDS using AWS DMS with zero downtime</title>
      <dc:creator>Anand Sukumaran</dc:creator>
      <pubDate>Sat, 01 Oct 2022 14:31:52 +0000</pubDate>
      <link>https://dev.to/anandrmedia/migrating-a-self-managed-mysql-database-to-aws-rds-using-aws-dms-with-zero-downtime-38mk</link>
      <guid>https://dev.to/anandrmedia/migrating-a-self-managed-mysql-database-to-aws-rds-using-aws-dms-with-zero-downtime-38mk</guid>
      <description>&lt;p&gt;Recently, at &lt;a href="https://engagespot.co" rel="noopener noreferrer"&gt;Engagespot&lt;/a&gt;, we had to migrate our MySQL database which was hosted in an EC2 instance to AWS RDS to ensure high availability, automated backups and get more visibility through Cloudwatch monitoring and logs.&lt;/p&gt;

&lt;p&gt;But the challenge was the size of the database. We had several Gigabytes of data with millions of rows. The next challenge is to ensure sync between both databases. By the time we take the backup and restore it, the data on our original database would have been changed. And, we cannot lock the original database from new writes as it would affect the uptime of our service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative Methods
&lt;/h2&gt;

&lt;p&gt;We tried several solutions like doing a &lt;code&gt;mysqldump&lt;/code&gt; and piping it to the RDS server but it continuously broke the pipe.&lt;/p&gt;

&lt;p&gt;We came across this useful service from Amazon called &lt;a href="https://aws.amazon.com/dms/" rel="noopener noreferrer"&gt;AWS DMS (Database Migration Service)&lt;/a&gt; that helps you migrate any database from one server to another. Not just MySQL, but any other databases like Postgres, MSSQL, etc.&lt;/p&gt;

&lt;p&gt;By using DMS, we were able to migrate our entire production database to RDS without any downtime. &lt;/p&gt;

&lt;p&gt;In this article, I'll explain how to migrate a MySQL database hosted in an EC2 instance (or any other remote server) to RDS. The steps to migrate other databases like Postgres are almost the same, however, the configurations might be different.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;Target RDS instance already created with the schema and table structure. (&lt;em&gt;This is because DMS is not great at replicating your table's auto-increment and other constraints&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Source MySQL database that can be accessed remotely.&lt;/li&gt;
&lt;li&gt;Binary log enabled in source MySQL database with few parameters in your &lt;code&gt;my.cnf&lt;/code&gt; file configured as per AWS documentation &lt;a href="https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MySQL.html#CHAP_Source.MySQL.CustomerManaged" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Copy the entire table structure from your source DB to target manually.
&lt;/h2&gt;

&lt;p&gt;As I mentioned above, you must copy your tables, foreign keys, primary keys, Indexes, and other constraints from your source database to RDS manually, using mysqldump, or any other tools. This is because DMS won't migrate the table structure and its constraints properly.&lt;/p&gt;

&lt;p&gt;You can simply do this using a MySQL client like Tableplus.&lt;/p&gt;

&lt;p&gt;After you've migrated all the table structures, let's proceed to transfer the actual data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Replication Instance
&lt;/h2&gt;

&lt;p&gt;Goto AWS Console, and open the &lt;a href="https://us-west-2.console.aws.amazon.com/dms/v2/home" rel="noopener noreferrer"&gt;DMS service&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To migrate your database, you must first create a DMS replication instance. Navigate to Replication instances -&amp;gt; Create replication instance.&lt;/p&gt;

&lt;p&gt;Specify the name and class of the replication instance. You can select the class identical to the RDS instance or your source database. Don't worry about incurring costs because you can quickly delete the replication instance after the migration is completed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Source endpoint.
&lt;/h2&gt;

&lt;p&gt;After creating the replication instance, you must create the source and target database endpoints. For this, navigate to Endpoints -&amp;gt; create endpoint.&lt;/p&gt;

&lt;p&gt;First, we'll create the source endpoint. Make sure you have the source database credentials ready.&lt;/p&gt;

&lt;p&gt;Select &lt;strong&gt;Source Endpoint&lt;/strong&gt; as the Endpoint Type.&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%2Fupp2qc6f9o2fcw3bxsj6.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%2Fupp2qc6f9o2fcw3bxsj6.png" alt="Image description" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specify your source database credentials. Make sure the MySQL user you specify here has SUPER privileges. Without that, the migration might fail.&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%2Fav545vvc4v6oof1vx7d2.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%2Fav545vvc4v6oof1vx7d2.png" alt="Image description" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, click on the save button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Target endpoint.
&lt;/h2&gt;

&lt;p&gt;The steps are similar to that of creating a source endpoint. There is one additional configuration to specify here. &lt;/p&gt;

&lt;p&gt;Under the &lt;strong&gt;Endpoint settings&lt;/strong&gt;, check Use endpoint connection attributes. And in the textbox labeled &lt;strong&gt;Extra connection attributes&lt;/strong&gt;, add the value &lt;code&gt;initstmt=SET FOREIGN_KEY_CHECKS=0&lt;/code&gt;. This disables Foreign Key checks on your RDS database during migration and avoids foreign key-related errors.&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%2F1yfw6bnu7v9qr8eqqsju.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%2F1yfw6bnu7v9qr8eqqsju.png" alt="Image description" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating source and target endpoints, you can test the connection from the &lt;strong&gt;Connections&lt;/strong&gt; tab to make sure those databases can be reached by DMS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Migration Target
&lt;/h2&gt;

&lt;p&gt;A migration task is a process that copies the database from your source to the target. DMS offers three types of migration tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migrate existing data&lt;/strong&gt; - Choose this type if you just want to copy the existing data from the source to the target once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migrate existing data and replicate ongoing changes&lt;/strong&gt; - Choose this method if you want to copy the existing data from the source to the target and keep syncing new records as they are created on the source DB. This is an ongoing process. And we'll be using this method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migrate existing data and replicate ongoing changes&lt;/strong&gt; - Choose this method if you already have some data migrated and now you want to sync the new data from source to target.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Database migration tasks&lt;/strong&gt; and click &lt;strong&gt;Create task&lt;/strong&gt; button. Choose the replication instance you had created earlier, and select the source and target endpoints. Choose migration type as &lt;strong&gt;Migrate existing data and replicate ongoing changes&lt;/strong&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%2F92a6bsu0rmc705th49eg.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%2F92a6bsu0rmc705th49eg.png" alt="Image description" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under the &lt;strong&gt;Task settings&lt;/strong&gt; section, choose &lt;strong&gt;Target table preparation mode&lt;/strong&gt; as &lt;strong&gt;do nothing&lt;/strong&gt;. This is because you had already migrated the table structure manually.&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%2Fzskb8833zlwc132pftvi.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%2Fzskb8833zlwc132pftvi.png" alt="Image description" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can enable &lt;strong&gt;Cloudwatch logs&lt;/strong&gt; to debug if something goes wrong.&lt;/p&gt;

&lt;p&gt;Just click on &lt;strong&gt;Create task&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;After some time, your task status will be "In Progress". At first, DMS will copy the entire data from source to target, and after that, it will continuously keep the two in sync.&lt;/p&gt;

&lt;p&gt;The initial time to copy the data might take anywhere from a few mins to hours depending on the size of your database.&lt;/p&gt;

&lt;p&gt;Once you confirm that the entire data has been copied to your target DB, you can run a few tests by creating records in your source DB to ensure new records are being synced.&lt;/p&gt;

&lt;p&gt;At this stage, you can update the database credentials of your production app to RDS and that's it! You have migrated your entire production database to RDS without any downtime!&lt;/p&gt;

&lt;p&gt;Please let me know in the comments if you face any issues!&lt;/p&gt;

</description>
      <category>dms</category>
      <category>aws</category>
      <category>mysql</category>
      <category>database</category>
    </item>
  </channel>
</rss>
