<?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: NAVYA THOTTEMPUDI</title>
    <description>The latest articles on DEV Community by NAVYA THOTTEMPUDI (@navya_thottempudi).</description>
    <link>https://dev.to/navya_thottempudi</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4150685%2F3905375f-7a0a-49c6-a9e4-9e82bcaa3272.png</url>
      <title>DEV Community: NAVYA THOTTEMPUDI</title>
      <link>https://dev.to/navya_thottempudi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/navya_thottempudi"/>
    <language>en</language>
    <item>
      <title>Why We Stored Typed Events Instead of Embeddings for Our Agent's Memory</title>
      <dc:creator>NAVYA THOTTEMPUDI</dc:creator>
      <pubDate>Tue, 29 Sep 2026 18:19:13 +0000</pubDate>
      <link>https://dev.to/navya_thottempudi/why-we-stored-typed-events-instead-of-embeddings-for-our-agents-memory-dc4</link>
      <guid>https://dev.to/navya_thottempudi/why-we-stored-typed-events-instead-of-embeddings-for-our-agents-memory-dc4</guid>
      <description>&lt;p&gt;Our competitive intelligence pipeline could write a good briefing, but only for one run. Give it a topic and some competitors, and CrewAI agents research the web, analyse the findings, and write a report where every claim has a citation. The next run started from zero. In week 8 it had no idea weeks 1 to 7 existed.&lt;/p&gt;

&lt;p&gt;That made it a lookup with nice formatting. An analyst who sees five moves from one company in a quarter calls it a pattern. Ours could only describe today's news. So we added persistent memory and made it central to the design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The design choice: structure first&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The obvious move is to embed every finding into a vector store and retrieve by similarity. We went the other way and stored &lt;strong&gt;typed events&lt;/strong&gt;. Each finding becomes a &lt;code&gt;CompetitorEvent&lt;/code&gt; (Pydantic) with a competitor, an event type (feature launch, pricing change, hiring, acquisition, funding, partnership, market signal), a date, a title, a description, an impact score, a confidence value, and evidence URLs.&lt;/p&gt;

&lt;p&gt;The reason is the questions strategy work asks: "every pricing change in the last 90 days" or "how many hiring events this quarter". A typed query answers those exactly, with date ordering and no ranking noise.&lt;/p&gt;

&lt;p&gt;The store is a class we wrote, &lt;code&gt;HindsightStore&lt;/code&gt; (&lt;code&gt;memory/hindsight_store.py&lt;/code&gt;). It's plain Python: an append-only &lt;code&gt;events.jsonl&lt;/code&gt;, plus JSON files for profiles, strategies, and predictions. It's thread-safe and reloads from disk on startup. It is our own implementation and not the Vectorize Hindsight library, which is a separate open-source memory system: &lt;a href="https://github.com/vectorize-io/hindsight" rel="noopener noreferrer"&gt;https://github.com/vectorize-io/hindsight&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where memory sits in the pipeline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The crew grew from four agents (Discovery, Research, Analyst, Writer) to seven: Discovery, Research, &lt;strong&gt;Memory&lt;/strong&gt;, Analyst, Strategy Evolution, Prediction, and Writer.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdnljbjv53e105f0txiwf.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdnljbjv53e105f0txiwf.png" alt=" " width="575" height="506"&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Agents share one CrewAI tool, &lt;code&gt;HindsightStoreTool&lt;/code&gt;, with six operations: &lt;code&gt;store_event&lt;/code&gt;, &lt;code&gt;get_history&lt;/code&gt;, &lt;code&gt;get_profile&lt;/code&gt;, &lt;code&gt;search_memory&lt;/code&gt;, &lt;code&gt;get_strategy&lt;/code&gt;, and &lt;code&gt;get_predictions&lt;/code&gt;. The Memory Agent stores each Research finding, then pulls history and a profile per competitor and hands the Analyst a memory-enriched context. The Analyst's task text requires it to use that history. Strategy and Prediction call the tool too, and predictions must cite stored events.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Profiles update on every write&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each &lt;code&gt;store_event&lt;/code&gt; call recomputes a per-competitor profile. There's no batch job. The core logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;hiring_events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_events&lt;/span&gt;
                 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;competitor&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;competitor&lt;/span&gt;
                 &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HIRING&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hiring_events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;prof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hiring_trend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HiringTrend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SURGING&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hiring_events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;prof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hiring_trend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HiringTrend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GROWING&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;prof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hiring_trend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HiringTrend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STABLE&lt;/span&gt;

&lt;span class="n"&gt;prof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confidence_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.98&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_events&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.07&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confidence starts at 0.3, gains 0.07 per event, and caps at 0.98. The Writer is told to hedge for low-confidence competitors, so the briefing's tone follows how much evidence we hold.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before vs. after&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We tried it on a fictional competitor, "NeuraCode AI". The store ships with seeded demo data, and &lt;code&gt;scripts/demo_memory.py&lt;/code&gt; runs the whole sequence with no LLM and no network. These are demo events, not market 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fous64z8gl7y04jrwline.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fous64z8gl7y04jrwline.png" alt=" " width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt; one stored event. The Analyst can only restate it: "NeuraCode launched an AI code review tool."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt; six events (code review tool, 15 ML engineers hired, enterprise tier at $45/seat/month, a $28M analytics acquisition, a security scanner, a JetBrains integration). The profile shows &lt;code&gt;total_events = 6&lt;/code&gt; and 72% confidence, straight from the formula. The Analyst now has product, talent, pricing, M&amp;amp;A, and distribution signals with dates.&lt;/p&gt;

&lt;p&gt;This is a controlled demo, not a benchmark. We haven't measured briefing quality over weeks of live runs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The trade-off we accepted&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Structure cost us semantic search. &lt;code&gt;search_memory&lt;/code&gt; is a keyword scan over titles and descriptions, so a search for "cost reduction" won't find a &lt;code&gt;pricing_change&lt;/code&gt; event unless those words appear in its text. Real semantic retrieval is the clearest gap, and it's why integrating an actual memory system behind the same tool is our next step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What else is unfinished&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Impact scores (0 to 10) are LLM-generated with no rule-based floor, and three events at 8.0 or above flip a competitor to &lt;code&gt;CRITICAL&lt;/code&gt;. That score isn't stable across models.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;update_prediction_status()&lt;/code&gt; exists, but nothing grades predictions automatically.&lt;/li&gt;
&lt;li&gt;Strategy output is parsed with regex in &lt;code&gt;crew.py&lt;/code&gt;, which is brittle.&lt;/li&gt;
&lt;li&gt;A fresh store auto-seeds demo data, which can mislead testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick your memory schema from the questions you'll ask, not from what's fashionable&lt;/li&gt;
&lt;li&gt;Make memory use mandatory in task text.&lt;/li&gt;
&lt;li&gt;Let confidence follow evidence.&lt;/li&gt;
&lt;li&gt;Close the prediction feedback loop early.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://github.com/24wh1a0510/CI---Copilot" rel="noopener noreferrer"&gt;GitHub Repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
