<?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>Forem: olav gerritsen</title>
    <description>The latest articles on Forem by olav gerritsen (@ojg).</description>
    <link>https://forem.com/ojg</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%2F2632375%2F63567f9d-7fdc-4679-8ee5-45078264f289.png</url>
      <title>Forem: olav gerritsen</title>
      <link>https://forem.com/ojg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ojg"/>
    <language>en</language>
    <item>
      <title>Why I Swapped the Weather Demo for a Movie‑Night Agent (and How You Can Too)</title>
      <dc:creator>olav gerritsen</dc:creator>
      <pubDate>Mon, 12 May 2025 10:00:39 +0000</pubDate>
      <link>https://forem.com/ojg/why-i-swapped-the-weather-demo-for-a-movie-night-agent-and-how-you-can-too-34fc</link>
      <guid>https://forem.com/ojg/why-i-swapped-the-weather-demo-for-a-movie-night-agent-and-how-you-can-too-34fc</guid>
      <description>&lt;p&gt;&lt;strong&gt;Turning TMDB into a Gen-AI Plugin Playground (and having fun doing it)&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Description
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Semantic Kernel&lt;/strong&gt; agent that chats about movies, remembers what you’ve watched, and serves fresh recommendations.&lt;/li&gt;
&lt;li&gt;Only &lt;strong&gt;seven tiny plugin functions&lt;/strong&gt; (Top-rated, Search, Add / Remove / List Watched, Similar, Recommend) power everything.&lt;/li&gt;
&lt;li&gt;Next steps: genre / year filters, streaming-service info, persistent cloud memory, shiny web UI.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1 Why TMDB + Plugins is a Developer’s Playground
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Why it rocks&lt;/th&gt;
&lt;th&gt;What we get&lt;/th&gt;
&lt;th&gt;How the plugin maps it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rich data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Title, year, genres, poster, vote-average&lt;/td&gt;
&lt;td&gt;One C# function per endpoint returning pre-formatted strings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Open API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No OAuth dance, generous free tier&lt;/td&gt;
&lt;td&gt;Simple &lt;code&gt;HttpClient&lt;/code&gt; calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deterministic endpoints&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/movie/top_rated&lt;/code&gt;, &lt;code&gt;/search/movie&lt;/code&gt;, …&lt;/td&gt;
&lt;td&gt;Predictable plugin surface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Built-in ranking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;TMDB already sorts by popularity + score&lt;/td&gt;
&lt;td&gt;We only need light post-filtering&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  2 Seven Skills That Ship &lt;em&gt;Today&lt;/em&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ask the bot…&lt;/th&gt;
&lt;th&gt;It calls…&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;“Show me the current top 10 movies on TMDB.”&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tmdb.GetTopRatedMoviesAsync(take)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“Find movies with ‘star wars’ in the title.”&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tmdb.SearchMoviesAsync(query)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“Add &lt;em&gt;Interstellar&lt;/em&gt; to my watched list.”&lt;/td&gt;
&lt;td&gt;&lt;code&gt;memory.AddWatchedAsync(title)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“Remove &lt;em&gt;Interstellar&lt;/em&gt; from watched.”&lt;/td&gt;
&lt;td&gt;&lt;code&gt;memory.RemoveWatchedAsync(title)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“What have I watched so far?”&lt;/td&gt;
&lt;td&gt;&lt;code&gt;memory.ListWatchedAsync()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“I loved &lt;em&gt;Dune&lt;/em&gt; — anything similar?”&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;tmdb.SearchMovieIdAsync&lt;/code&gt; → &lt;code&gt;tmdb.GetMovieRecommendationsAsync&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“Give me five highly-rated movies I probably haven’t seen.”&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reco.RecommendMoviesAsync(top)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  3 Architecture in 60 Seconds
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Semantic Kernel&lt;/strong&gt; handles DI and registers plugins.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Stepwise Planner&lt;/strong&gt; inspects your prompt, chooses functions, and iterates until it can answer in natural language.&lt;/li&gt;
&lt;li&gt;Swapping the in-memory store for Redis or SQLite is one interface away.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3.5 Agent or Just Function Calls? 🤔
&lt;/h2&gt;

&lt;p&gt;OpenAI function‑calling is simply the wiring—a structured JSON request that jumps from the LLM to your C# methods.The agent is the loop that keeps asking, “Do I know enough yet?” If not, it picks another plugin, calls it, updates context, and repeats until it can answer you like a human.&lt;/p&gt;

&lt;p&gt;Reasoning – figures out which tool would help.&lt;/p&gt;

&lt;p&gt;Tool‑use – invokes that plugin via function‑call.&lt;/p&gt;

&lt;p&gt;Memory – stores and re‑uses what it learned.&lt;/p&gt;

&lt;p&gt;Autonomy – iterates without any if/else in your code.&lt;/p&gt;

&lt;p&gt;Put those four pillars together and you’ve got an agent!&lt;/p&gt;

&lt;h2&gt;
  
  
  4 Bug Diary: When a Space Killed the List 🔪
&lt;/h2&gt;

&lt;p&gt;First test of “Give me five highly-rated movies I probably haven’t seen” spat back:&lt;/p&gt;

&lt;p&gt;8,5&lt;br&gt;
8,4&lt;br&gt;
8,3&lt;br&gt;
8,2&lt;/p&gt;

&lt;p&gt;Only vote-average numbers survived!&lt;br&gt;
Why? Every TMDB plugin glued its bullet lines with a &lt;strong&gt;space&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;return string.Join(" ", lines);      &lt;/p&gt;

&lt;p&gt;The recommender later did:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;list.Split(' ')
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spaces in → spaces out → &lt;em&gt;poof&lt;/em&gt; movie titles lost.&lt;br&gt;
The universal fix was literally &lt;strong&gt;one character&lt;/strong&gt; 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-return string.Join(' ', lines);
&lt;/span&gt;&lt;span class="gi"&gt;+return string.Join('\n', lines);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…and two matching &lt;code&gt;.Split()&lt;/code&gt; calls changed to &lt;code&gt;'\n'&lt;/code&gt;.&lt;br&gt;
Lesson learned: delimiters matter, and tiny plumbing bugs can wreck UX.&lt;/p&gt;




&lt;h2&gt;
  
  
  5 Stepwise Planning in Action 🤖✨
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User ▸ I’ve watched Fight Club and Whiplash — recommend something new.

Planner ▸
  1. memory.AddWatchedAsync("Fight Club")          ✓
  2. memory.AddWatchedAsync("Whiplash")            ✓
  3. reco.RecommendMoviesAsync(top = 20)           → – Parasite (2019) 8.5 …

Bot ▸ – Parasite (2019) 8.5
      – La La Land (2016) 8.0
      – …
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No manual orchestration — &lt;strong&gt;the planner&lt;/strong&gt; chained three plugins on its own.&lt;/p&gt;




&lt;h2&gt;
  
  
  6 Where We Go Next 🚀
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;🚧 Idea&lt;/th&gt;
&lt;th&gt;🧩 How to plug it in&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Year &amp;amp; genre filters&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Add optional parameters to TMDB plugin or a tiny post-filter helper.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;“Where can I stream it?”&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Chain TMDB with JustWatch / Reelgood API; append platform badges.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Persistent memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Swap in-memory list for Redis / SQLite — same &lt;code&gt;IMovieMemory&lt;/code&gt; interface.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web UI shell&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Drop the same kernel into a React + Tailwind front-end.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Persona prompts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Feed chat history (“movie night with kids…”) into a system message before recommending.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Poster images&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;image_gen.text2im&lt;/code&gt; to generate missing posters on the fly.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each is a thin slice — a new plugin or an extra parameter, not a rewrite.&lt;/p&gt;




&lt;h2&gt;
  
  
  7 Takeaway 🎬
&lt;/h2&gt;

&lt;p&gt;Small, sharply-defined plugin functions + OpenAI Function-Calling + Semantic Kernel = &lt;strong&gt;conversation-native apps&lt;/strong&gt; with almost no glue code.&lt;br&gt;
TMDB makes it fun because the data is clean, the API is friendly, and talking movies is instantly relatable.&lt;/p&gt;

&lt;p&gt;Fork the repo, swap TMDB for your favourite domain (books? restaurants?), and watch the same pattern shine.&lt;/p&gt;

&lt;h5&gt;
  
  
  Git Repo: &lt;a href="https://github.com/olavgerritsen98/SemanticKernelAgentsDemo" rel="noopener noreferrer"&gt;https://github.com/olavgerritsen98/SemanticKernelAgentsDemo&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;&lt;strong&gt;Happy coding — and happy watching!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>genai</category>
      <category>semantickernel</category>
      <category>dotnet</category>
      <category>programming</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>olav gerritsen</dc:creator>
      <pubDate>Mon, 30 Dec 2024 08:28:01 +0000</pubDate>
      <link>https://forem.com/ojg/-2j97</link>
      <guid>https://forem.com/ojg/-2j97</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/frankiey" 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%2F2058052%2F4abc3b79-0fd9-4348-9a73-8c9ea764d366.jpeg" alt="frankiey"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/frankiey/run-llms-locally-with-ollama-semantic-kernel-in-net-a-quick-start-4go4" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Run LLMs Locally with Ollama &amp;amp; Semantic Kernel in .NET: A Quick Start&lt;/h2&gt;
      &lt;h3&gt;Frank Noorloos ・ Dec 24 '24&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;#ai&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#semantickernel&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#ollama&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>dotnet</category>
      <category>ai</category>
      <category>learning</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
