<?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: Dmitry Bogomolov</title>
    <description>The latest articles on DEV Community by Dmitry Bogomolov (@doctornick42).</description>
    <link>https://dev.to/doctornick42</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%2F140105%2F34b1ffc6-87e1-4568-b35b-c7b0af2a31fe.jpg</url>
      <title>DEV Community: Dmitry Bogomolov</title>
      <link>https://dev.to/doctornick42</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/doctornick42"/>
    <language>en</language>
    <item>
      <title>Building FatAdvisor: A .NET Nutrition AI Agent. Part 2: Agent goes outside</title>
      <dc:creator>Dmitry Bogomolov</dc:creator>
      <pubDate>Sat, 10 Jan 2026 13:11:21 +0000</pubDate>
      <link>https://dev.to/doctornick42/building-fatadvisor-a-net-nutrition-ai-agent-part-2-agent-goes-outside-35da</link>
      <guid>https://dev.to/doctornick42/building-fatadvisor-a-net-nutrition-ai-agent-part-2-agent-goes-outside-35da</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
In the previous episodes…

&lt;ul&gt;
&lt;li&gt;Plugins&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Coding

&lt;ul&gt;
&lt;li&gt;Interfaces and Stubs&lt;/li&gt;
&lt;li&gt;Plugin implementation&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Dependency Injection&lt;/li&gt;

&lt;li&gt;Running the Application&lt;/li&gt;

&lt;li&gt;Conclusions&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  In the previous episodes...
&lt;/h3&gt;

&lt;p&gt;we created a .Net application powered by Semantic Kernel. We connected it to GitHub Models and added a basic system message asking it to act as a nutrition and fitness assistant. &lt;/p&gt;

&lt;p&gt;From the technical standpoint, we also created a basic "architecture", splitting the solution into three projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI — AI-related logic,&lt;/li&gt;
&lt;li&gt;FatSecretAPI — for integrating FatSecret API, &lt;/li&gt;
&lt;li&gt;Console — a simple basic interface for user interactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So far the app runs and answers our questions, but it still doesn't know anything about us! It's time to give it some hints, showing who we are and what do we eat.&lt;/p&gt;

&lt;p&gt;In this chapter we will create a Plugin for Semantic Kernel. But first, let’s quickly discuss what a Plugin actually is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plugins
&lt;/h3&gt;

&lt;p&gt;In &lt;a href="https://learn.microsoft.com/en-us/semantic-kernel/concepts/plugins/?pivots=programming-language-csharp" rel="noopener noreferrer"&gt;Semantic Kernel documentation&lt;/a&gt; we can read that Plugins "encapsulate your existing APIs into a collection that can be used by AI". Basically, there are two main types of things we can encapsulate in a Plugin: something to fetch and something to do. For example, AI agent in your IDE can read your codebase ("fetch data") and make changes in the code ("do actions"). &lt;br&gt;
This concept is what makes an agent an agent: a language model itself is like a head in a jar (any Futurama fans?), and Plugin is an interface that connects this "head" with the world around it.&lt;/p&gt;

&lt;p&gt;In general, there are four ways of providing a plugin to your app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;adding native code plugin (&lt;a href="https://learn.microsoft.com/en-us/semantic-kernel/concepts/plugins/adding-native-plugins?pivots=programming-language-csharp" rel="noopener noreferrer"&gt;Microsoft documentation&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;adding OpenAPI as a plugin (&lt;a href="https://learn.microsoft.com/en-us/semantic-kernel/concepts/plugins/adding-openapi-plugins?pivots=programming-language-csharp" rel="noopener noreferrer"&gt;Microsoft documentation&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;adding plugin from an MCP server (&lt;a href="https://learn.microsoft.com/en-us/semantic-kernel/concepts/plugins/adding-mcp-plugins?pivots=programming-language-csharp" rel="noopener noreferrer"&gt;Microsoft documentation&lt;/a&gt;),&lt;/li&gt;
&lt;li&gt;integrating with Azure Logic Apps (&lt;a href="https://learn.microsoft.com/en-us/semantic-kernel/concepts/plugins/adding-logic-apps-as-plugins" rel="noopener noreferrer"&gt;Microsoft documentation&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our application's main goal is actually to learn, so we will go with the first option - a native code plugin. This means that we will implement a C# class with all the logic we need.&lt;/p&gt;

&lt;p&gt;The other three options are more specific. They can be useful, but I don't want to concentrate on them now, so we don't get distracted from our basic application. &lt;/p&gt;

&lt;p&gt;Just a small remark: the OpenAPI option looks too interesting to completely ignore. If you have created some HTTP APIs you probably know what Swagger/OpenAPI is. In Semantic Kernel you can introduce your OpenAPI specification by providing a link to it. And then, your LLM can send HTTP requests to the endpoints described in your specification. Sounds like a fun thing to try out one day! See the link above to read more about this way of introducing a Plugin.&lt;/p&gt;

&lt;p&gt;Anyway, let's get back to our FatAdvisor and to our decision to implement the Plugin as a native code (a C# class).&lt;/p&gt;

&lt;p&gt;We want our LLM to be able to fetch some knowledge from the outside. In this version of the app, we won't teach our agent to invoke any actions, we will only let it receive the data it needs. We create what is, from the programming language's point of view, a class with methods. Each of these methods will provide some functionality for the LLM to use. Though "method" is a common concept in OOP and in C# in particular, in AI agent terminology you will find such entry points called "functions", "tools" or "actions". Semantic Kernel allows us to provide descriptions for these methods via attributes. The LLM then reads these descriptions, and it should be enough for it to understand for which purposes which function can be invoked. &lt;/p&gt;

&lt;p&gt;We will implement our Plugin as a C# class, so we can inject any services (HTTP clients, DB connections etc.) in it. In our case, the Plugin that we're going to make will be a wrapper over the FatSecret API. We will add only those functions that our application really needs.&lt;/p&gt;
&lt;h3&gt;
  
  
  Coding
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Interfaces and Stubs
&lt;/h4&gt;

&lt;p&gt;To keep this chapter from becoming too long and to concentrate on the Plugin itself, we will not implement the real integration with third-party services such as the FatSecret API or any others. We will define interfaces and create stub implementation of it imitating the desired behavior. Don't worry — the real implementation will be described in the next chapter. In addition, with these mocking services I can lie to our FatSecret giving it much better impression of what I'm eating than my real diet.&lt;/p&gt;

&lt;p&gt;Let's define what interfaces we need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IFatSecretApiClient&lt;/strong&gt; - the most important interface for us. It will contain the methods that we can invoke in FatSecret API. The real version sends HTTP requests, while the stub simply returns predefined responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IFatSecretOAuth&lt;/strong&gt; - the authorization workflow for FatSecret.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IProfileTokenStorage&lt;/strong&gt; - not really mandatory, but we want to store our token returned by IFatSecretOAuth, so we can reuse and refresh them properly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And for each of them let's create a stub implementation that returns static data.&lt;/p&gt;

&lt;p&gt;Now the FatAdvisor.FatSecretApi project structure will look like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stubs

&lt;ul&gt;
&lt;li&gt;ApiStubData

&lt;ul&gt;
&lt;li&gt;FoodLog0.json&lt;/li&gt;
&lt;li&gt;WeightLog0.json&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;FatSecretApiClientStub.cs&lt;/li&gt;
&lt;li&gt;FatSecretOAuthStub.cs&lt;/li&gt;
&lt;li&gt;ProfileTokenStorageStub.cs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;FatSecretApiModule.cs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;ApiStubData&lt;/code&gt; folder there are JSON files that imitate responses from the FatSecret API.&lt;/p&gt;

&lt;p&gt;FatAdvisor.FatSecretApi/Stubs/ApiStubData/FoodLog0.json:&lt;br&gt;
(full sample JSON file is available &lt;a href="https://github.com/doctornick42/fat-advisor-for-article/blob/part2/src/FatAdvisor.FatSecretApi/Stubs/ApiStubData/FoodLog0.json" rel="noopener noreferrer"&gt;in the repository&lt;/a&gt;)&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;"food_entries"&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;"food_entry"&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="nl"&gt;"calories"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"64"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"carbohydrate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"13.32"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date_int"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20394"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"fat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"food_entry_description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.3 serving 30 g Bread slice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"food_entry_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"72145983012"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"food_entry_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bread slice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"food_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"84213058"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"meal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Breakfast"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"number_of_units"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.300"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"protein"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.19"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"serving_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"29396720"&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="err"&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;p&gt;FatAdvisor.FatSecretApi/Stubs/ApiStubData/WeightLog0.json:&lt;br&gt;
(full sample JSON file is available &lt;a href="https://github.com/doctornick42/fat-advisor-for-article/blob/part2/src/FatAdvisor.FatSecretApi/Stubs/ApiStubData/WeightLog0.json" rel="noopener noreferrer"&gt;in the repository&lt;/a&gt;)&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;"month"&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;"day"&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="nl"&gt;"date_int"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20362"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"weight_kg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"60.7000"&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="err"&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;"from_date_int"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20362"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"to_date_int"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20392"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the implementation of FatSecret API client that reads data from these stub files:&lt;/p&gt;

&lt;p&gt;FatAdvisor.FatSecretApi/Stubs/FatSecretApiClientStub.cs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai.Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.FatSecretApi.Stubs&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FatSecretApiClientStub&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IFatSecretApiClient&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ReadDataFromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Stubs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ApiStubData"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllTextAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetFoodsForDateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ReadDataFromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FoodLog0.json"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetWeightDiary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ReadDataFromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"WeightLog0.json"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TokenInfo&lt;/span&gt; &lt;span class="n"&gt;tokenInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Do nothing&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;We also need to make temporary fake services for authorization. We need just to return something, any string will work.&lt;/p&gt;

&lt;p&gt;FatAdvisor.FatSecretApi/Stubs/FatSecretOAuthStub.cs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai.Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.FatSecretApi.Stubs&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FatSecretOAuthStub&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IFatSecretOAuth&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TokenInfo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAccessTokenAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;requestToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;requestTokenSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;verifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
            &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TokenInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"access_token_stub"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"access_token_secret_stub"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetAuthorizationUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;requestToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;callbackUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;$"http://localhost?token=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;requestToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TokenInfo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetRequestTokenAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;callbackUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
            &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TokenInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"request_token_stub"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"request_token_secret_stub"&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;The same with the token storage service. Earlier we pretended to receive a token, now we pretend to store it:&lt;/p&gt;

&lt;p&gt;FatAdvisor.FatSecretApi/Stubs/ProfileTokenStorageStub.cs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai.Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.FatSecretApi.Stubs&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProfileTokenStorageStub&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IProfileTokenStorage&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TokenInfo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;FindTokenInStorage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TokenInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"access_token_stub"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"access_token_secret_stub"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SaveTokenToStorage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TokenInfo&lt;/span&gt; &lt;span class="n"&gt;accessTokenInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;h4&gt;
  
  
  Plugin implementation
&lt;/h4&gt;

&lt;p&gt;We have created a fake implementation of external services and now we are ready for the most interesting part of this chapter. We are going to create The Plugin!&lt;/p&gt;

&lt;p&gt;There are two main functions we need for our agent to start with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;get_consumed_food&lt;/strong&gt; – get all the consumed food (food log) for the selected day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;get_weight_diary&lt;/strong&gt; – get the weight diary for the month until the specified date&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They will help us find the answer to the main nutrition questions: what did I eat and what are the consequences of it? We will explain to the agent that it can use these functions when it needs them.&lt;/p&gt;

&lt;p&gt;So here's the implementation. Let's take a look at it, and then we will walk through it. It's very simple:&lt;/p&gt;

&lt;p&gt;FatAdvisor.Ai/FatSecretProfileDataPlugin.cs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai.Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.ComponentModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FatSecretProfileDataPlugin&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IFatSecretApiClient&lt;/span&gt; &lt;span class="n"&gt;_fatSecretApiClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IFatSecretOAuth&lt;/span&gt; &lt;span class="n"&gt;_fatSecretOAuth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IProfileTokenStorage&lt;/span&gt; &lt;span class="n"&gt;_profileTokenStorage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FatSecretProfileDataPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;IFatSecretApiClient&lt;/span&gt; &lt;span class="n"&gt;fatSecretApiClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;IFatSecretOAuth&lt;/span&gt; &lt;span class="n"&gt;fatSecretOAuth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;IProfileTokenStorage&lt;/span&gt; &lt;span class="n"&gt;profileTokenStorage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_fatSecretApiClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fatSecretApiClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;_fatSecretOAuth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fatSecretOAuth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;_profileTokenStorage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;profileTokenStorage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;KernelFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"get_consumed_food"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Get all the consumed food (food log) for selected day"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetConsumedFood&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;accessTokenInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_profileTokenStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindTokenInStorage&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="n"&gt;accessTokenInfo&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// If no token is found, we need to authorize the user&lt;/span&gt;
                &lt;span class="n"&gt;accessTokenInfo&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;AuthorizeAndSaveToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;_fatSecretApiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accessTokenInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;todaysFood&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_fatSecretApiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFoodsForDateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;todaysFood&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;KernelFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"get_weight_diary"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Get the weight diary for month due to the specified date"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetWeightDiaryForMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;accessTokenInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_profileTokenStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindTokenInStorage&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="n"&gt;accessTokenInfo&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// If no token is found, we need to authorize the user&lt;/span&gt;
                &lt;span class="n"&gt;accessTokenInfo&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;AuthorizeAndSaveToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;_fatSecretApiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accessTokenInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;todaysFood&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_fatSecretApiClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetWeightDiary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;todaysFood&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TokenInfo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;AuthorizeAndSaveToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;callbackUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//For prototype we could use null.&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;requestTokenInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_fatSecretOAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetRequestTokenAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callbackUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authorizationUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_fatSecretOAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAuthorizationUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;requestTokenInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;callbackUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Please visit: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;authorizationUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\nPaste the verifier code here:"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;verifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;accessTokenInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_fatSecretOAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAccessTokenAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;requestTokenInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;requestTokenInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TokenSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;verifier&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_profileTokenStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveTokenToStorage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accessTokenInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;accessTokenInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the constructor there's nothing extraordinary. We just inject our interfaces (the rules for resolving them will be specified in the Autofac module).&lt;/p&gt;

&lt;p&gt;Speaking of &lt;code&gt;Task&amp;lt;TokenInfo&amp;gt; AuthorizeAndSaveToken()&lt;/code&gt;, inside this method we call &lt;code&gt;_fatSecretOAuth&lt;/code&gt; to execute the 3-legged OAuth logic. We will discuss it in the next chapter where we will talk about real integration with the FatSecret API. But for now it's enough to understand that this method receives an access token for the FatSecret API and stores it (via &lt;code&gt;_profileTokenStorage&lt;/code&gt; abstraction). &lt;/p&gt;

&lt;p&gt;But the real shiny stars of our plugin are these two tiny Functions: GetConsumedFood and GetWeightDiaryForMonth. What's going on inside is very straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Try to find an access token for the FatSecret API in the storage.&lt;/li&gt;
&lt;li&gt;If it's not there, authorize via OAuth dance and store the received token in the storage. Thus, on the upcoming iteration we will save some resources by not requesting OAuth endpoints again and again.&lt;/li&gt;
&lt;li&gt;Invoke the appropriate method of FatSecret API.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A piece of cake, right?&lt;br&gt;
What is interesting here, first, the attributes. These two small guys tell the LLM something important:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;KernelFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"get_consumed_food"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Get all the consumed food (food log) for selected day"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetConsumedFood&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Actually, they provide metadata to LLM.&lt;br&gt;
The &lt;code&gt;KernelFunction&lt;/code&gt; attribute is needed to mark this C# method as a SemanticKernel's function. In other words, that's how we tell the LLM that this method is for it to invoke.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Description&lt;/code&gt; attribute serves to give more context. Let's admit, we're living in the future. Through all these years of evolution of programming languages we learned and learned to speak with computers in a formal, deterministic way, through these programming languages. But now we have to decorate our beautiful C# code with wordy, redundant human language. This is the future — but are we happy?&lt;/p&gt;

&lt;p&gt;Ok, just kidding.&lt;/p&gt;

&lt;p&gt;But I hope you got the idea: with this attribute we can describe the function for the LLM, providing more information — like what this function is supposed to do, or in which situation the LLM might consider running it.&lt;/p&gt;

&lt;p&gt;Unless &lt;code&gt;KernelFunction&lt;/code&gt;, which is required in the general case for Semantic Kernel functions, the &lt;code&gt;Description&lt;/code&gt; attribute is optional. And as &lt;a href="https://learn.microsoft.com/en-us/semantic-kernel/concepts/plugins/?pivots=programming-language-csharp#make-plugins-ai-friendly" rel="noopener noreferrer"&gt;the documentations says&lt;/a&gt;, we should rely more on concise and understandable function names (and parameter names as well), and use the &lt;code&gt;Description&lt;/code&gt; attribute "&lt;strong&gt;only when necessary to minimize token consumption.&lt;/strong&gt;"&lt;/p&gt;
&lt;h4&gt;
  
  
  DI
&lt;/h4&gt;

&lt;p&gt;That's how we register our Semantic Kernel and plugins in the DI container:&lt;/p&gt;

&lt;p&gt;FatAdvisor.Ai/FatSecretAiModule.cs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Autofac&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.DependencyInjection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Logging&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FatSecretAiModule&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Module&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FatSecretAiModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContainerBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"GitHubModels:ApiKey"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"GitHubModels:Endpoint"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;modelId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gpt-4o-mini"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;builder&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;loggerFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resolve&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ILoggerFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kernelBuilder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                    &lt;span class="n"&gt;kernelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loggerFactory&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="n"&gt;kernelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenAIChatCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;modelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;modelId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

                    &lt;span class="c1"&gt;// Register plugins during Kernel construction&lt;/span&gt;
                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;fatSecretPlugin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resolve&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FatSecretProfileDataPlugin&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
                    &lt;span class="n"&gt;kernelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddFromObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fatSecretPlugin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;kernelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Kernel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SingleInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FatSecretProfileDataPlugin&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;AsSelf&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;SingleInstance&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;And that's how we register our stubs:&lt;/p&gt;

&lt;p&gt;FatAdvisor.FatSecretApi/FatSecretApiModule.cs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Autofac&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.FatSecretApi.Stubs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.FatSecretApi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FatSecretApiModule&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Module&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Not used right now, but will be useful later.&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FatSecretApiModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContainerBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FatSecretOAuthStub&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IFatSecretOAuth&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;SingleInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FatSecretApiClientStub&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IFatSecretApiClient&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;SingleInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProfileTokenStorageStub&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IProfileTokenStorage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;SingleInstance&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;h3&gt;
  
  
  Running!
&lt;/h3&gt;

&lt;p&gt;It seems like we are ready to run the app and ask the Fat Advisor some questions. I've modified the &lt;code&gt;ConsoleAppRunner&lt;/code&gt; class to formulate both the system and user messages a bit more concretely.&lt;br&gt;
I won't put the whole code of this class here (you can find it &lt;a href="https://github.com/doctornick42/fat-advisor-for-article/blob/part2/src/FatAdvisor.Console/ConsoleAppRunner.cs" rel="noopener noreferrer"&gt;in the repo&lt;/a&gt;).&lt;br&gt;
Just to highlight the most important parts of the messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;yesterday&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDays&lt;/span&gt;&lt;span class="p"&gt;(-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chatHistory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChatHistory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;chatHistory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSystemMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You are a nutrition and training assistant. "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"When answering the user, always consider user's FatSecret profile data including: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;$"FatSecret food log for the last 2 days (check it for every day in the range of last 2 days until &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;yesterday&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"If available, consider user's weight diary (for the last month) to understand what "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"amount of food should be taken. In your response display weight diary and consumed food diary. "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userMessage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Please review my nutrition habits and give me advice on what I should change to gain muscle without gaining fat."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's run the app, and that's what we see in the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dbug: Microsoft.SemanticKernel.Connectors.OpenAI.OpenAIChatCompletionService[0]
      Function choice behavior configuration: Choice:auto, AutoInvoke:True, AllowConcurrentInvocation:False, AllowParallelCalls:(null) Functions:FatSecretProfileDataPlugin-get_consumed_food, FatSecretProfileDataPlugin-get_weight_diary
info: Microsoft.SemanticKernel.Connectors.OpenAI.OpenAIChatCompletionService[0]
      Prompt tokens: 224. Completion tokens: 116. Total tokens: 340.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, this should look familiar and was discussed in the &lt;a href="https://dev.to/doctornick42/building-fatadvisor-a-net-nutrition-ai-agent-part-1-building-the-foundation-1402"&gt;Part 1&lt;/a&gt;. There's a summary of tokens consumption and the basic configuration.&lt;/p&gt;

&lt;p&gt;Next, we can see the log of Function calls like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;info: Microsoft.SemanticKernel.KernelFunction[0]
      Function FatSecretProfileDataPlugin-get_consumed_food invoking.
info: Microsoft.SemanticKernel.KernelFunction[0]
      Function FatSecretProfileDataPlugin-get_consumed_food succeeded.
info: Microsoft.SemanticKernel.KernelFunction[0]
      Function FatSecretProfileDataPlugin-get_consumed_food completed. Duration: 0.0447523s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see similar logs for every function invocation, which is good and shows that the model correctly selected which functions to call based on the prompt and available plugins.&lt;/p&gt;

&lt;p&gt;And finally, after all these log records, we see the model's response! Here I'll put just some fragments of it, not the whole text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### Your Nutrition and Weight Diary Overview&lt;/span&gt;

&lt;span class="gu"&gt;#### Weight Diary (Last Month)&lt;/span&gt;
| Date       | Weight (kg) |
|------------|-------------|
| 2025-05-03 | 60.7        |
| 2025-05-10 | 60.3        |
| 2025-05-12 | 61.1        |
| 2025-05-22 | 60.8        |
| 2025-05-27 | 61.0        |

&lt;span class="gu"&gt;#### Consumed Food Diary&lt;/span&gt;
&lt;span class="gs"&gt;**June 3, 2025:**&lt;/span&gt;
| Meal      | Food Description                      | Calories | Protein | Carbohydrates | Fat  |
|-----------|--------------------------------------|----------|---------|---------------|------|
| Breakfast | Caramel pastry (50g)                 | 275      | 4.00    | 20.75         | 19.75|
| Breakfast | Bread slice (30g)                    | 64       | 2.19    | 13.32         | 0.24 |
...

&lt;span class="gu"&gt;### Nutrition Advice for Muscle Gain without Fat Gain&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="gs"&gt;**Increase Protein Intake**&lt;/span&gt;: Your protein intake for each day (~49g) is relatively low for muscle gain. Aim for at least &lt;span class="gs"&gt;**1.6 to 2.2 grams of protein per kilogram of body weight**&lt;/span&gt;, which, considering your weight (around 61 kg), should be approximately &lt;span class="gs"&gt;**100g to 130g**&lt;/span&gt; of protein daily.
&lt;span class="p"&gt;
2.&lt;/span&gt; &lt;span class="gs"&gt;**Quality Carbohydrates**&lt;/span&gt;: The carbohydrates in your diet are significant; however, focus on complex carbs (whole grains, oats, sweet potatoes, legumes) rather than sugars and processed foods like the milk chocolate. These will provide sustainable energy for your workouts.

...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, that looks pretty fair! &lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;Today we learned how to introduce some Functions to an AI agent. They are pretty simple and only cover the data retrieval part. We know that AI agents can also perform actions, but we haven't implemented anything like that yet. Maybe later we can add it, at least as an example.&lt;/p&gt;

&lt;p&gt;We taught our agent to receive data about our food intake and weight. The data is still fake, so we kind of lie to the agent —  but it's in the name of research!&lt;/p&gt;

&lt;p&gt;In the next chapter I'm going to make a couple of steps from AI and Semantic Kernel itself and focus on implementing real interaction with the FatSecret API. This part will be more for those who want to play with the FatSecret API on their own, rather than for those who are learning Semantic Kernel. But I think it should be fun. We want to make things real, right?&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>ai</category>
      <category>showdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Dmitry Bogomolov</dc:creator>
      <pubDate>Fri, 17 Oct 2025 08:25:21 +0000</pubDate>
      <link>https://dev.to/doctornick42/-2lj5</link>
      <guid>https://dev.to/doctornick42/-2lj5</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/doctornick42" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F140105%2F34b1ffc6-87e1-4568-b35b-c7b0af2a31fe.jpg" alt="doctornick42"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/doctornick42/building-fatadvisor-a-net-nutrition-ai-agent-part-1-building-the-foundation-1402" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Building FatAdvisor: A .NET Nutrition AI Agent. Part 1: Building the Foundation&lt;/h2&gt;
      &lt;h3&gt;Dmitry Bogomolov ・ Oct 15&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#dotnet&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#ai&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#semantickernel&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>dotnet</category>
      <category>programming</category>
      <category>ai</category>
      <category>semantickernel</category>
    </item>
    <item>
      <title>Building FatAdvisor: A .NET Nutrition AI Agent. Part 1: Building the Foundation</title>
      <dc:creator>Dmitry Bogomolov</dc:creator>
      <pubDate>Wed, 15 Oct 2025 16:23:13 +0000</pubDate>
      <link>https://dev.to/doctornick42/building-fatadvisor-a-net-nutrition-ai-agent-part-1-building-the-foundation-1402</link>
      <guid>https://dev.to/doctornick42/building-fatadvisor-a-net-nutrition-ai-agent-part-1-building-the-foundation-1402</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Intro

&lt;ul&gt;
&lt;li&gt;AI agents&lt;/li&gt;
&lt;li&gt;The project&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

It goes technical

&lt;ul&gt;
&lt;li&gt;Choosing the technologies&lt;/li&gt;
&lt;li&gt;
Solution structure

&lt;ul&gt;
&lt;li&gt;AI model&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Starting coding!

&lt;ul&gt;
&lt;li&gt;DI&lt;/li&gt;
&lt;li&gt;Program.cs&lt;/li&gt;
&lt;li&gt;ConsoleAppRunner&lt;/li&gt;
&lt;li&gt;Running&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;Conclusions&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AI agents
&lt;/h3&gt;

&lt;p&gt;AI is a pretty big deal nowadays, right? Large Language Models (LLMs) help us everyday with various tasks. Popular models are already replacing search engine interfaces. Also, if you're a programmer, you probably already use AI-powered features in your IDEs.&lt;/p&gt;

&lt;p&gt;For a user, an LLM feels a bit like a huge, smart database you can query in natural language. But it's also quite intriguing, how can we make it not only answer our questions, but &lt;strong&gt;do&lt;/strong&gt; things. And that's where AI agents come in.&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%2Fm406dmid0a3wgr8aukpi.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%2Fm406dmid0a3wgr8aukpi.png" alt="AI agent basic scheme" width="499" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are many nice well-written articles and courses about AI agents, so I won't repeat definitions or theory here too much. We're here for some practice, aren't we? The only thing I think is crucial to understand is that a "Tool" can be basically anything that can provide data for an LLM (for example, an external database) or provide the ability to make actions (e.g. a 3rd party API allowing to modify data in an external system).&lt;/p&gt;

&lt;p&gt;What excites me is that an agentic AI can decide by itself whether to use any of the available tools, in what order, and for what purposes. As developers we just provide some "handlebars", but it's up to the LLM how and when to use it.&lt;/p&gt;

&lt;p&gt;Driven by a desire to build an agent by myself in educational purposes, I looked for a personally useful use case... and that's where FatAdvisor appears.&lt;/p&gt;

&lt;h3&gt;
  
  
  The project
&lt;/h3&gt;

&lt;p&gt;Ok, FatAdvisor might sound a bit rude, I admit it. But let me explain! This agent will use the API of the FatSecret app. FatSecret is an amazing app for those who try to track their food intake. I mean, come on — I'm in my mid-30s. I want... no, I &lt;em&gt;have&lt;/em&gt; to care about what I consume!&lt;/p&gt;

&lt;p&gt;In general, it's great to see your calories, fats, carbs and proteins if you have specific goals — whether it’s losing some weight, gaining muscle mass, or just being curious (and nerdy) enough to track your diet no matter what.&lt;/p&gt;

&lt;p&gt;Thus, I've been using the app for quite a while, and I became curious: how could I use this data that’s already being collected there?&lt;/p&gt;

&lt;p&gt;So the idea was to give an AI model the access to my FatSecret profile and ask it for advice about my nutritional habits. And that’s how the name &lt;em&gt;FatAdvisor&lt;/em&gt; appeared.&lt;/p&gt;

&lt;p&gt;The first use case scenario for it would be: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retrieve my food diary for the last couple of days,&lt;/li&gt;
&lt;li&gt;retrieve my weight diary for the same period,&lt;/li&gt;
&lt;li&gt;analyze them and answer my questions like:  “What should I eat for dinner today?” or “What should I change in my habits?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fortunately, FatSecret provides an HTTP REST API that can provide this data.&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%2F3ptoojla0y4yw1zwzrki.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%2F3ptoojla0y4yw1zwzrki.png" alt="Fat Secret API integration" width="540" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It goes technical
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Choosing the technologies
&lt;/h3&gt;

&lt;p&gt;Ok, now let's move on to the real world and choose the technologies for our project.&lt;/p&gt;

&lt;p&gt;I am a .Net developer. I love it so much that writing C# for eight hours a day at work isn’t enough — I still want to keep coding in my personal time!&lt;/p&gt;

&lt;p&gt;But seriously, I just feel like I can focus more on the agentic AI part of my projectif I use a language and framework I’m already comfortable with. Besides, .Net is a very stable and mature stack for building maintainable, production-ready solutions. &lt;/p&gt;

&lt;p&gt;.NET already provides several great tools for integrating AI into applications. For this project, I chose &lt;strong&gt;Semantic Kernel&lt;/strong&gt; — an SDK designed for creating and orchestrating AI agents. Sounds exactly like what we need!&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%2Fx9sa6qa2p2wmsuspl1ec.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%2Fx9sa6qa2p2wmsuspl1ec.png" alt="Adopting Semantic Kernel" width="678" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the help of Semantic Kernel connectors we can use different AI model providers. &lt;br&gt;
Speaking of which, I'm currently playing with &lt;strong&gt;GitHub Models&lt;/strong&gt;. Free usage is available, and that is good for a Proof-of-Concept type of project.&lt;/p&gt;

&lt;p&gt;For prototyping goals I decided not to implement a web UI yet and instead start with a simple console app.&lt;/p&gt;

&lt;p&gt;In this first article, we’ll focus on wiring up Semantic Kernel with GitHub Models in a minimal console application. Later, we’ll expand the solution with a plugin for the FatSecret API.&lt;/p&gt;
&lt;h3&gt;
  
  
  Solution structure
&lt;/h3&gt;

&lt;p&gt;Our system design will be very simple — I don’t want to overcomplicate things at this prototype stage. Let’s create a Visual Studio solution with three projects::&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FatAdvisor.Console&lt;/strong&gt; - a console application that will act as a very basic "UI" for user interaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FatAdvisor.Ai&lt;/strong&gt; - the core project of the solution. It contains all the logic fpr working with Semantic Kernel and other AI-related things.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FatAdvisor.FatSecretApi&lt;/strong&gt; - let's locate all the details of working with FatSecret API inside this project. You know, DTOs for HTTP requests/responses, HTTP clients, well, all the things you do when integrating with a third-party API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's create the solution, add the projects, and set up the references between them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new sln -n FatAdvisor

dotnet new console -o FatAdvisor.Console
dotnet new classlib -o FatAdvisor.Ai
dotnet new classlib -o FatAdvisor.FatSecretApi

dotnet sln FatAdvisor.sln add ./FatAdvisor.Console/FatAdvisor.Console.csproj
dotnet sln FatAdvisor.sln add ./FatAdvisor.Ai/FatAdvisor.Ai.csproj
dotnet sln FatAdvisor.sln add ./FatAdvisor.FatSecretApi/FatAdvisor.FatSecretApi.csproj

dotnet add ./FatAdvisor.Console/FatAdvisor.Console.csproj reference ./FatAdvisor.Ai/FatAdvisor.Ai.csproj
dotnet add ./FatAdvisor.Console/FatAdvisor.Console.csproj reference ./FatAdvisor.FatSecretApi/FatAdvisor.FatSecretApi.csproj
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let’s install the required NuGet packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet add FatAdvisor.Console package Autofac
dotnet add FatAdvisor.Console package Autofac.Extensions.DependencyInjection
dotnet add FatAdvisor.Console package Microsoft.Extensions.Configuration.EnvironmentVariables
dotnet add FatAdvisor.Console package Microsoft.Extensions.Configuration.UserSecrets
dotnet add FatAdvisor.Console package Microsoft.Extensions.Hosting
dotnet add FatAdvisor.Console package Microsoft.Extensions.Logging
dotnet add FatAdvisor.Console package Microsoft.Extensions.Logging.Console
dotnet add FatAdvisor.Console package Microsoft.SemanticKernel

dotnet add FatAdvisor.FatSecretApi package Autofac
dotnet add FatAdvisor.FatSecretApi package Microsoft.Extensions.Configuration.Abstractions
dotnet add FatAdvisor.FatSecretApi package Microsoft.Extensions.Http

dotnet add FatAdvisor.Ai package Autofac
dotnet add FatAdvisor.Ai package Microsoft.Extensions.Configuration.Abstractions
dotnet add FatAdvisor.Ai package Microsoft.SemanticKernel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The solution was tested with the following versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Autofac&lt;/code&gt; – 8.1.0&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Autofac.Extensions.DependencyInjection&lt;/code&gt; – 10.0.0&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Microsoft.Extensions.*&lt;/code&gt; – 9.0.8&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Microsoft.SemanticKernel&lt;/code&gt; – 1.62.0&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  AI model
&lt;/h4&gt;

&lt;p&gt;Now we need to choose what we'll use as the "brain" of our system. Since this project is more about self-education than building a real production-ready app, I was looking for a free, easy-to-use solution — and chose GitHub Models. This platform gives us a chance to play with various LLMs. You need to create one single token, and then you can quickly switch between models whenever you want.&lt;/p&gt;

&lt;p&gt;For more information about GitHub Models, including limits, quick start examples and much more please visit &lt;a href="https://docs.github.com/en/github-models/about-github-models" rel="noopener noreferrer"&gt;GitHub Docs page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First we need to create a token. There are two options: &lt;strong&gt;fine-grained&lt;/strong&gt; tokens and &lt;strong&gt;classic&lt;/strong&gt; tokens.. GitHub recommends to switch to fine-grained tokens when possible. The difference is that a classic token would have access to all your repositories, while for a fine-grained one, you can restrict which repositories it can access, or even grant no repository access at all (which is what we need here).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://github.com/settings/personal-access-tokens" rel="noopener noreferrer"&gt;https://github.com/settings/personal-access-tokens&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;"Fine-grained tokens"&lt;/strong&gt; and click &lt;strong&gt;"Generate new token"&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose any name for your token, set an expiration time, and adjust the settings as you prefer.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;“Permissions”&lt;/strong&gt;, click &lt;strong&gt;“Add permissions”&lt;/strong&gt;, then choose &lt;strong&gt;“Models”&lt;/strong&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%2F6970yrbzu51nd1u1ec3v.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%2F6970yrbzu51nd1u1ec3v.png" alt="Adding permissions to the token" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;“Generate token”&lt;/strong&gt;. After the token is generated, &lt;strong&gt;copy it and store it securely&lt;/strong&gt;, because you won’t be able to view it again later.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally, we need to pick which model to use. Here's the &lt;a href="https://github.com/marketplace/models" rel="noopener noreferrer"&gt;Marketplace&lt;/a&gt; for GitHub Models where you can see what is available. For my project, I'll start with GPT‑4o mini.&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting coding!
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Dependency Injection (DI)
&lt;/h4&gt;

&lt;p&gt;First, let's create an Autofac module in both Ai and Api projects. We use Autofac for dependency injection across our solution. Initially, the DI configuration will be pretty small, but in the next chapters the modules will be useful for registering new components.&lt;/p&gt;

&lt;p&gt;By the way, if you're not familiar with the concept of modules in Autofac — they are classes that help you break down dependency injection configuration into logically isolated files. You can read more about them in the &lt;a href="https://autofac.readthedocs.io/en/latest/configuration/modules.html" rel="noopener noreferrer"&gt;Autofac documentation&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;FatAdvisor.Api/FatSecretApiModule.cs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Autofac&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.FatSecretApi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FatSecretApiModule&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Module&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FatSecretApiModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContainerBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it for now for the Api module. It's empty cause we don't have anything to register yet.&lt;/p&gt;

&lt;p&gt;The Ai module is a bit more interesting:&lt;/p&gt;

&lt;p&gt;FatAdvisor.Ai/FatSecretAiModule.cs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Autofac&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.DependencyInjection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Logging&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FatSecretAiModule&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Module&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FatSecretAiModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContainerBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"GitHubModels:ApiKey"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"GitHubModels:Endpoint"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;modelId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gpt-4o-mini"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;loggerFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resolve&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ILoggerFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kernelBuilder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                &lt;span class="n"&gt;kernelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loggerFactory&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;kernelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenAIChatCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;modelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;modelId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;kernelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Kernel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SingleInstance&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;Here, we use configuration values to locate our &lt;strong&gt;GitHub Models&lt;/strong&gt; settings (&lt;code&gt;ApiKey&lt;/code&gt; and &lt;code&gt;Endpoint&lt;/code&gt;). For now, the model ID is hardcoded to &lt;code&gt;"gpt-4o-mini"&lt;/code&gt;, though we could easily move it to configuration later.&lt;/p&gt;

&lt;p&gt;Next, we register an instance of the Kernel class. This is a core class of SemanticKernel, and we will interact with the AI models through it. Also later we will register our agentic plugins here.&lt;/p&gt;

&lt;h4&gt;
  
  
  Program.cs
&lt;/h4&gt;

&lt;p&gt;Now let's create an entry point for the console app — Program.cs.&lt;br&gt;
I will describe what happens in the code through inline comments&lt;/p&gt;

&lt;p&gt;FatAdvisor.Console/Program.cs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.FatSecretApi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Ai&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.DependencyInjection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Logging&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Autofac.Extensions.DependencyInjection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Autofac&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Hosting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Console&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateDefaultBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="c1"&gt;// Adding Autofac for dependency injection&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseServiceProviderFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AutofacServiceProviderFactory&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; 

                    &lt;span class="c1"&gt;// Configure app settings (User Secrets &lt;/span&gt;
                    &lt;span class="c1"&gt;// + Environment Variables)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAppConfiguration&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddUserSecrets&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
                        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddEnvironmentVariables&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                    &lt;span class="p"&gt;})&lt;/span&gt;

                    &lt;span class="c1"&gt;// We want to log a lot of things&lt;/span&gt;
                    &lt;span class="c1"&gt;// to trace how it actually works&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureLogging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ClearProviders&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddConsole&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetMinimumLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;})&lt;/span&gt;

                    &lt;span class="c1"&gt;// Register Autofac modules and application services&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConfigureContainer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ContainerBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;((&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="c1"&gt;// Register your modules here&lt;/span&gt;
                        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RegisterModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FatSecretAiModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
                        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RegisterModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FatSecretApiModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

                        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ConsoleAppRunner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;AsSelf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                    &lt;span class="p"&gt;})&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="c1"&gt;// Create a scope and run the application&lt;/span&gt;
            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateScope&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceProvider&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ConsoleAppRunner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RunAsync&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;h4&gt;
  
  
  ConsoleAppRunner
&lt;/h4&gt;

&lt;p&gt;Probably, it is the most interesting part of the first draft. Inside this class, we'll actually run our model — providing a system message, simulating user input, and observing the AI’s response through the ChatService.&lt;/p&gt;

&lt;p&gt;FatAdvisor.Console/ConsoleAppRunner.cs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel.ChatCompletion&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel.Connectors.OpenAI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FatAdvisor.Console&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConsoleAppRunner&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Kernel&lt;/span&gt; &lt;span class="n"&gt;_kernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Injection is controled by Autofac&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ConsoleAppRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Kernel&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_kernel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chatHistory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChatHistory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;chatHistory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSystemMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"You are a nutrition and training assistant. "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"Although you don’t have access to any external data, "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"pretend that you’re analyzing the user’s recent food "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"and training habits based on their description. "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"Provide practical, personalized advice."&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userMessage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
                &lt;span class="s"&gt;"Imagine I’ve been eating quite a lot of carbs "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"recently and training hard at the gym. "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"Please evaluate how that could affect my weight "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"and energy levels, and suggest what I could adjust."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;chatHistory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddUserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chatCompletion&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_kernel&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IChatCompletionService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OpenAIPromptExecutionSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;FunctionChoiceBehavior&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FunctionChoiceBehavior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Auto&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;chatCompletion&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetChatMessageContentAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chatHistory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_kernel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kvp&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;kvp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;kvp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&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;In RunAsync(), we:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a chat history&lt;/strong&gt;:&lt;br&gt;
It contains both a &lt;em&gt;system message&lt;/em&gt; (instructions for the assistant’s role and behavior) and a &lt;em&gt;user message&lt;/em&gt; (the question or request). Together, they define the full context the model receives.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resolve the chat completion service&lt;/strong&gt;&lt;br&gt;
From the instance of Kernel, we receive an implementation of &lt;code&gt;IChatCompletionService&lt;/code&gt;. Since we registered &lt;code&gt;OpenAIChatCompletionService&lt;/code&gt; in the &lt;code&gt;FatSecretAiModule&lt;/code&gt;, this interface is automatically resolved to that implementation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure prompt execution behavior&lt;/strong&gt;&lt;br&gt;
In the prompt execution settings we register only one setting, but pretty important one:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OpenAIPromptExecutionSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;FunctionChoiceBehavior&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FunctionChoiceBehavior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Auto&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;What does it mean? We discussed the concept of AI agents in the beginning of this article. And though we haven't created an agentic plugin yet, we can already instruct the model how to behave when plugins are presented. &lt;/p&gt;

&lt;p&gt;The available options are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None – well, our agent won't call any functions but may describe which one it would call (good for testing purposes and for research).&lt;/li&gt;
&lt;li&gt;Auto – the model decides on its own whether to call a function and how to use it.&lt;/li&gt;
&lt;li&gt;Required – with this option we could actually force the agent to call some functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this exercise we prefer to use Auto mode, we will let our model shine and choose its own way to use available functions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Print the results&lt;/strong&gt; &lt;br&gt;
Finally, we output both the model’s text response:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kvp&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;kvp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;kvp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Running
&lt;/h4&gt;

&lt;p&gt;For storing tokens and other sensitive settings, we'll use &lt;code&gt;User Secrets&lt;/code&gt;instead of embedding them into &lt;code&gt;appsettings.json&lt;/code&gt; or environment files. From your terminal navigate to the FatAdvisor.Console folder and run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet user-secrets init
dotnet user-secrets set "GitHubModels:ApiKey" "&amp;lt;your GitHub models token&amp;gt;"
dotnet user-secrets set "GitHubModels:Endpoint" "https://models.inference.ai.azure.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run the console app. Because we set up a pretty verbose log level, we will see some technical information along with the response by AI model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dbug: Microsoft.SemanticKernel.Connectors.OpenAI.OpenAIChatCompletionService[0]

      Function choice behavior configuration: Choice:auto, AutoInvoke:True, AllowConcurrentInvocation:False, AllowParallelCalls:(null) Functions:None (Function calling is disabled)

info: Microsoft.SemanticKernel.Connectors.OpenAI.OpenAIChatCompletionService[0]

      Prompt tokens: 114. Completion tokens: 485. Total tokens: 599.

When you've been consuming a lot of carbohydrates and training hard at the gym, several factors come into play regarding your weight and energy levels:



### Effects on Weight:

1. **Glycogen Storage**: Carbohydrates are stored in your muscles and liver as glycogen. For every gram of glycogen, about 3 grams of water are stored as well. This can cause temporary weight gain as your body increases its glycogen stores.

...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, I think there's no need to copy here the whole answer. We still don't provide any personal information from FatSecret, so the AI output here is mostly a general nutrition explanation.&lt;/p&gt;

&lt;p&gt;Let’s highlight a couple of interesting details from the log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Function choice behavior configuration: 
    Choice:auto,
    AutoInvoke:True,
    AllowConcurrentInvocation:False,
    AllowParallelCalls:(null)
    Functions:None (Function calling is disabled)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we can see that &lt;strong&gt;function calling is configured for “Auto” mode&lt;/strong&gt;, but &lt;strong&gt;no functions are actually registered&lt;/strong&gt; yet — which is expected at this stage of the project.&lt;/p&gt;

&lt;p&gt;And here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prompt tokens: 114. Completion tokens: 485. Total tokens: 599.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we see that we sent 114 input tokens to the model, and received 485 in response (with 599 being a sum of input and output). Tracking these stats will help us later to optimize costs and usage when we integrate more complex prompts or larger models.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;I'd like to stop here not to overload our journey by throwing too much information at once. We have created something that we now can improve and develop. Our system already has some basic structure and AI features.&lt;/p&gt;

&lt;p&gt;In the next chapters we will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a plugin for SemanticKernel containing functions that will allow our AI agent to access food and weight logs,&lt;/li&gt;
&lt;li&gt;implement API integration with FatSecret to retrieve this data — including building an HTTP client, handling authentication, and adding a simple local token storage,&lt;/li&gt;
&lt;li&gt;improve the prompts to make our FatAdvisor smarter and more helpful.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading — and see you in the next part!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>programming</category>
      <category>ai</category>
      <category>semantickernel</category>
    </item>
    <item>
      <title>gosli: a little attempt to bring a bit of LINQ to Golang</title>
      <dc:creator>Dmitry Bogomolov</dc:creator>
      <pubDate>Fri, 17 Apr 2020 21:02:05 +0000</pubDate>
      <link>https://dev.to/doctornick42/gosli-a-little-attempt-to-bring-a-bit-of-linq-to-golang-2949</link>
      <guid>https://dev.to/doctornick42/gosli-a-little-attempt-to-bring-a-bit-of-linq-to-golang-2949</guid>
      <description>&lt;p&gt;This post was originally posted on Medium: &lt;a href="https://medium.com/@dmitrybogomolov/gosli-a-little-attempt-to-bring-a-bit-of-linq-to-golang-1e3fb4acfd04" rel="noopener noreferrer"&gt;https://medium.com/@dmitrybogomolov/gosli-a-little-attempt-to-bring-a-bit-of-linq-to-golang-1e3fb4acfd04&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;First, let me admit that I really like Golang. I think it’s pretty elegant, easy-to-read and very powerful language. But also, I love C#.&lt;/p&gt;

&lt;p&gt;Though I know that every language has its’ best practices and has its’ own way to create good software, there’s something from C# that I definitely miss in Golang. One of those things is LINQ (Language-Integrated Query).&lt;/p&gt;

&lt;p&gt;LINQ allows us to manipulate with collections in C#, modifying, filtering, grouping them using anonymous (lambda) functions. Let’s see a little example how it looks:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;One of the biggest inconveniences I met in Go was the fact that the language doesn’t have some standard way to filter a slice or to find an element of slice by one of its’ fields. I tried to find some way to do it, but everything I found was something like “Well, you have to write a loop for it”.&lt;/p&gt;

&lt;p&gt;Once upon a time, I found myself having multiple loops in my program, and they were almost the same but working with different types. It was something like that.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;It made me think that it should be the way to avoid code copying. One approach is to make common method receiving &lt;code&gt;interface{}&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And there are at least a couple of problems I see in this implementation.&lt;br&gt;
First, a lot of type assertions are there (like &lt;code&gt;x.(B).FieldString…&lt;/code&gt; etc.). It doesn’t look very nice and it makes us create a lot of code to check if assertion can be made.&lt;/p&gt;

&lt;p&gt;Also, it makes us use the &lt;code&gt;reflect&lt;/code&gt; package. A lot of Go apps are made to be fast, I mean, really fast. And you could hear it here and there that &lt;code&gt;reflect&lt;/code&gt; is not a great helper if you’re looking for good performance.&lt;/p&gt;

&lt;p&gt;And another disadvantage is the underlying type returned by our &lt;code&gt;filter&lt;/code&gt; method. Let’s check it with &lt;code&gt;fmt.Printf(“%T”, filteredA)&lt;/code&gt; and it will return us: &lt;code&gt;[]interface {}&lt;/code&gt;. If we want to use this object it wouldn’t be to cool to do. We will need to iterate over it to convert every element’s type to &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, all these problems made me think that we shouldn’t make a pseudo-generic method for all the types. But writing a separated loop for every type (as we did in the first code example) doesn’t look too good as well.&lt;/p&gt;

&lt;p&gt;I supposed that making a code generator to create some general methods that won’t use the &lt;code&gt;reflect&lt;/code&gt; package inside of those methods could make a deal. That’s how we can avoid copying-and-pasting code all the time and also we could have nice and clear methods that receives and returns particular types instead of annoying &lt;code&gt;interface{}&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introducing gosli
&lt;/h2&gt;

&lt;p&gt;These thoughts lead me to make a lib I called &lt;code&gt;gosli&lt;/code&gt;. I didn’t really plan to make a big deal out of it, I just wrote some code that, I guess, could be useful for someone else.&lt;/p&gt;

&lt;p&gt;TL;DR: check the source code and examples of usage here &lt;br&gt;
&lt;a href="https://github.com/doctornick42/gosli" rel="noopener noreferrer"&gt;https://github.com/doctornick42/gosli&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, let’s start. To get it we need to run this command:&lt;br&gt;
&lt;code&gt;go get github.com/doctornick42/gosli&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let’s create a new project with such a structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F273%2F1%2Aqdw5QRxirjx8cRCRxSqDVQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F273%2F1%2Aqdw5QRxirjx8cRCRxSqDVQ.png" alt="Basic project structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;testtypes.go&lt;/code&gt; will contain our types from the previous examples:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After it, we should run this for Linux&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$GOPATH/bin/gosli types/testtypes.go A&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;or this for Windows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;%GOPATH%\bin\gosli.exe types\testtypes.go A&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As you can see, our &lt;code&gt;types&lt;/code&gt; folder has been extended by adding 3 new files:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F272%2F1%2AM2g_51R4DRzPxiJ7-9XL5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F272%2F1%2AM2g_51R4DRzPxiJ7-9XL5w.png" alt="Generated files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only file of them we need to modify manually is &lt;code&gt;a_equal.go&lt;/code&gt;, which is needed for gosli to understand how it can check if two instances of &lt;code&gt;A&lt;/code&gt; are equal. From the scratch the code of this file looks like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let’s append after the &lt;code&gt;//&lt;/code&gt;&lt;code&gt;equal&lt;/code&gt;&lt;code&gt;method has to be implemented manually&lt;/code&gt; comment a new line:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;return r.FieldInt == another.FieldInt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That’s it. Now we can make some code to test the result, let’s just use the code we used in a previous example and put it in our &lt;code&gt;main.go&lt;/code&gt; file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And if we run the program we will see this output: &lt;code&gt;[{“FieldInt”:1},{“FieldInt”:3}]&lt;/code&gt; which is correct.&lt;/p&gt;

&lt;p&gt;The full code of this example &lt;a href="https://github.com/doctornick42/gosli-example" rel="noopener noreferrer"&gt;is here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features of gosli
&lt;/h2&gt;

&lt;p&gt;The library has 2 main approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to provide methods for slice of custom types. This part uses code generation, it has been briefly described in the previous paragraph. The documentation showing all the methods and other details could be &lt;a href="https://github.com/doctornick42/gosli/blob/master/docs/custom.md" rel="noopener noreferrer"&gt;found here&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;gosli also has all these methods for basic Golang types out-of-the box, it’s &lt;a href="https://github.com/doctornick42/gosli/blob/master/docs/primitives.md" rel="noopener noreferrer"&gt;described here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, every method of -Slice types returns such a type too, so the methods could be combined in a chain like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;SomeTypeSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;original&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, thank you for reading. If you would like to check out gosli, feel free to ask me about it or create issues in the repository.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://github.com/doctornick42/gosli/tree/master/experiment" rel="noopener noreferrer"&gt;experiment&lt;/a&gt; folder there are some tests, benchmarks and examples, that I hope will help to understand how to use the library in your apps.&lt;/p&gt;

&lt;p&gt;Also, you can find more awesome gopher images (like one I used in this article) by Egon Elbre under the &lt;a href="https://creativecommons.org/publicdomain/zero/1.0/" rel="noopener noreferrer"&gt;CC0 license&lt;/a&gt; here &lt;a href="https://github.com/egonelbre/gophers" rel="noopener noreferrer"&gt;https://github.com/egonelbre/gophers&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>linq</category>
      <category>codegeneration</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
