<?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: Svetozar Radojcin</title>
    <description>The latest articles on DEV Community by Svetozar Radojcin (@java_freepascal_dev).</description>
    <link>https://dev.to/java_freepascal_dev</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%2F3939868%2F5c813347-997d-4067-926d-2f65ec00c552.png</url>
      <title>DEV Community: Svetozar Radojcin</title>
      <link>https://dev.to/java_freepascal_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/java_freepascal_dev"/>
    <language>en</language>
    <item>
      <title>We built a bidirectional context loop between web apps and AI agents</title>
      <dc:creator>Svetozar Radojcin</dc:creator>
      <pubDate>Thu, 25 Jun 2026 13:39:49 +0000</pubDate>
      <link>https://dev.to/java_freepascal_dev/we-built-a-bidirectional-context-loop-between-web-apps-and-ai-agents-2mfg</link>
      <guid>https://dev.to/java_freepascal_dev/we-built-a-bidirectional-context-loop-between-web-apps-and-ai-agents-2mfg</guid>
      <description>&lt;p&gt;Source code: &lt;a href="https://github.com/tabforgeai/tabforge-ai" rel="noopener noreferrer"&gt;Tabforge AI&lt;/a&gt;&lt;br&gt;
Most AI integrations in business apps feel the same:&lt;/p&gt;

&lt;p&gt;You send a prompt → the model returns an answer → you try to glue it into your app.&lt;/p&gt;

&lt;p&gt;It works, but it always feels slightly disconnected from what’s actually happening in the UI.&lt;/p&gt;

&lt;p&gt;The AI doesn’t really know what the user is doing.&lt;/p&gt;

&lt;p&gt;And the app doesn’t really know what the AI just did.&lt;/p&gt;

&lt;p&gt;We ran into that problem while building EasyAI / TabForge, and ended up with something we didn’t originally set out to build:&lt;/p&gt;

&lt;p&gt;a bidirectional context loop between the application and the AI runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; AI in apps is stateless&lt;/p&gt;

&lt;p&gt;Even when you pass “context”, it’s usually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a string&lt;/li&gt;
&lt;li&gt;a JSON blob&lt;/li&gt;
&lt;li&gt;or a manually assembled prompt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the real state lives elsewhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which record is open&lt;/li&gt;
&lt;li&gt;what tab the user is on&lt;/li&gt;
&lt;li&gt;what action just happened&lt;/li&gt;
&lt;li&gt;what step in a workflow the user is in&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you end up doing things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;passing IDs around&lt;/li&gt;
&lt;li&gt;re-sending state on every request&lt;/li&gt;
&lt;li&gt;rebuilding context for every AI call&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It works, but it’s fragile.&lt;br&gt;
**&lt;br&gt;
Ambient Activity Memory (App → AI)**&lt;/p&gt;

&lt;p&gt;The first thing we added was a way for the application to continuously describe what is happening inside it.&lt;/p&gt;

&lt;p&gt;Not as logs.Not as analytics.&lt;br&gt;
But as structured semantic events tied to actual UI actions.&lt;/p&gt;

&lt;p&gt;So instead of:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“here is an order id”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;the system already knows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;user is currently viewing Order #248&lt;/li&gt;
&lt;li&gt;user just switched from payment tab to details tab&lt;/li&gt;
&lt;li&gt;user just triggered refund flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now when the user says:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“cancel this order”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;there is no ambiguity about what “this” refers to. The AI doesn’t guess context.It already has it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EasyAIEvent (AI → App)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the AI started understanding the app state, the next obvious question was:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;what does the AI give back to the application?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not just a final answer, but the execution itself.&lt;/p&gt;

&lt;p&gt;So every agent run can optionally emit a structured event stream:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;started&lt;/li&gt;
&lt;li&gt;planning&lt;/li&gt;
&lt;li&gt;tool calls&lt;/li&gt;
&lt;li&gt;progress updates&lt;/li&gt;
&lt;li&gt;completion
This is exposed via a simple hook:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;.withEventListener(event -&amp;gt; {&lt;br&gt;
    log.info("[{}] {} — {}", event.source(), event.phase(), event.title());&lt;br&gt;
})&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;No framework coupling.No HTTP assumptions.No UI dependencies.&lt;br&gt;
Just a pure event stream that your app can consume however it wants.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What this enables (more interesting part)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you have both directions:&lt;br&gt;
  App → AI&lt;/p&gt;

&lt;p&gt;The system knows what the user is doing.&lt;br&gt;
   AI → App&lt;/p&gt;

&lt;p&gt;The system exposes what the agent is doing. You end up with something simple but powerful:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;a closed loop between UI state and AI execution state&lt;/em&gt;&lt;br&gt;
**&lt;br&gt;
Why this matters in practice**&lt;/p&gt;

&lt;p&gt;This removes a bunch of glue code that usually creeps into AI integrations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;passing IDs back and forth&lt;/li&gt;
&lt;li&gt;manually constructing prompts&lt;/li&gt;
&lt;li&gt;debugging “what did the agent actually do?”&lt;/li&gt;
&lt;li&gt;rebuilding context on every request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the app continuously emits context&lt;/li&gt;
&lt;li&gt;the AI continuously emits execution state&lt;/li&gt;
&lt;li&gt;both stay decoupled, but synchronized&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important design choice&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The event model is intentionally framework-agnostic:&lt;br&gt;
(source, phase, status, title, detail, toolName, sequence, timestamp)&lt;/p&gt;

&lt;p&gt;It does not know anything about:&lt;/p&gt;

&lt;p&gt;HTTP, WebSockets, SSE, UI frameworks&lt;/p&gt;

&lt;p&gt;That part is left to the application.&lt;/p&gt;

&lt;p&gt;We ship a minimal example that maps the event stream to a real-time UI panel using SSE, but it stays outside the core library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where this is going&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The interesting part is not the event system itself. It’s what becomes possible when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the app knows what the user is doing&lt;/li&gt;
&lt;li&gt;the AI knows what it is doing&lt;/li&gt;
&lt;li&gt;and both sides share the same runtime context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You start to move from &lt;em&gt;“AI calls inside an app”&lt;/em&gt; toward something closer to:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI as a participant in application execution, not just a function you call&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you strip everything away&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At its core, this is all we tried to solve:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How do we make AI systems aware of application state without coupling them to the UI?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And the answer turned out to be:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don’t pass state. Stream it in both directions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to explore it:&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=Nm5RPV49Qck" rel="noopener noreferrer"&gt;The AI assistant knows what user doing in the app&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=qNDD9mfFEJk" rel="noopener noreferrer"&gt;AI streams his work details to the app&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/tabforgeai/tabforge-ai" rel="noopener noreferrer"&gt;https://github.com/tabforgeai/tabforge-ai&lt;/a&gt;&lt;br&gt;
Full example: &lt;a href="https://github.com/tabforgeai/tabforge-ai-demo" rel="noopener noreferrer"&gt;https://github.com/tabforgeai/tabforge-ai-demo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
