<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Codingfreaks]]></title><description><![CDATA[Helping others to learn]]></description><link>https://blogs.codingfreaks.net</link><generator>RSS for Node</generator><lastBuildDate>Wed, 19 Aug 2026 03:27:56 GMT</lastBuildDate><atom:link href="https://blogs.codingfreaks.net/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[AgentGateway Explained: How It Compares to AWS, Azure, and Other AI Gateways]]></title><description><![CDATA[If you've been following along with the AgentGateway series, you've seen the four modes, poked at config.yaml, and wired up a few backends. This one's a detour. Someone asked me last week whether "Azu]]></description><link>https://blogs.codingfreaks.net/agentgateway-explained-how-it-compares-to-aws-azure-and-other-ai-gateways</link><guid isPermaLink="true">https://blogs.codingfreaks.net/agentgateway-explained-how-it-compares-to-aws-azure-and-other-ai-gateways</guid><category><![CDATA[ai, mcp, agents, gateway, comparison]]></category><category><![CDATA[AI]]></category><category><![CDATA[agentgateway]]></category><category><![CDATA[coding]]></category><category><![CDATA[mcp]]></category><category><![CDATA[agentic AI]]></category><category><![CDATA[agents]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Thu, 02 Jul 2026 08:04:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/aeff6bf3-d16d-459c-86dc-1bded8910849.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you've been following along with the AgentGateway series, you've seen the four modes, poked at <code>config.yaml</code>, and wired up a few backends. This one's a detour. Someone asked me last week whether "Azure AgentGateway" was better than the open-source project I keep writing about, and I realized I'd never actually laid out where AgentGateway sits next to the rest of the market. So this post zooms out: what a gateway even is, why the AI-native flavor exists, who else is building one, and an honest look at where AgentGateway wins and where it doesn't.</p>
<p>This one's for the newbie who's never touched any of these tools, and for the pro who already runs Kong or LiteLLM and wants to know what the fuss about "agentic" gateways is actually about.</p>
<blockquote>
<p>I'm looking at AgentGateway v1.3.0 (July 2026) and whatever the competing products looked like as of this writing. This market moves fast enough that some of this will be stale in a quarter. Check the vendor's own docs before you buy anything based on a blog post, including this one.</p>
</blockquote>
<h2>What is a gateway, actually</h2>
<p>Strip away the AI branding and a gateway is an old idea: a single point of entry that traffic passes through on its way from a caller to a backend. Instead of every client talking directly to every server, everything goes through one place that can enforce rules, log what happened, and swap out backends without the callers noticing. Load balancers, reverse proxies, and ingress controllers are all cousins of the same idea.</p>
<p>The value isn't the routing itself, routing is easy. It's that a gateway becomes a natural chokepoint for the things you don't want scattered across a hundred services: auth, rate limits, retries, and observability.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/6997de87-79e2-4240-9158-9ace94d93df2.png" alt="" style="display:block;margin:0 auto" />

<p>Without the gateway, that "enforced once" box gets copy-pasted into every one of the N callers instead, and drifts out of sync the moment one team forgets to update it. That's the whole argument for the pattern, before AI ever enters the picture.</p>
<h2>What is an API gateway</h2>
<p>An API gateway is that same chokepoint idea applied specifically to application APIs, usually REST or gRPC. Kong, Apigee, and AWS API Gateway are the classic names here. They took the generic reverse-proxy pattern and bolted on things API teams actually needed: request transformation, API key management, per-route rate limiting, and a developer portal so other teams could discover what was available. If you've ever put an API behind Kong or Apigee to get consistent auth and throttling without touching the backend code, that's the pattern.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/4207cea4-2e01-433c-8034-8b5299441c4a.png" alt="" style="display:block;margin:0 auto" />

<p>That last dashed box is the whole reason the AI-native gateway category exists. A REST/gRPC API gateway can proxy an LLM call as raw HTTP just fine, rate limit by request count, and log the response, but it has no concept of a token, a model name, or an MCP tool call embedded inside the body. It treats a $40 completion the same as a $0.0001 healthcheck, because to the policy layer above, they're both just bytes on the wire. That gap is what the next section is actually about.</p>
<h2>What is an AgentGateway</h2>
<p>AgentGateway (lowercase agentgateway as a project) is an open-source proxy that extends the gateway pattern to cover four kinds of traffic in one data plane instead of four separate tools: plain HTTP/gRPC service traffic, LLM provider traffic (OpenAI, Anthropic, Gemini, Bedrock, Azure, and others behind one endpoint), MCP traffic (agents calling tools and data sources), and A2A traffic (agents talking to other agents). It started life at Solo.io, who built it after evaluating Envoy and deciding the AI traffic pattern needed a proxy designed for it from scratch rather than bolted onto an existing one. It's now hosted by the Agentic AI Foundation under the Linux Foundation.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/6c6b6332-e0c3-4fdb-9ad4-75aab4a0de89.png" alt="" style="display:block;margin:0 auto" />

<hr />
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/0e3ec38f-d194-4784-a8dc-f2651d753167.png" alt="" style="display:block;margin:0 auto" />

<p><strong>The pro bridge:</strong> if you've run Kong or an ingress controller for your services and separately bolted on LiteLLM or a custom proxy for your LLM calls, AgentGateway is what it looks like when someone designs both of those into the same binary instead of stitching them together.</p>
<table>
<thead>
<tr>
<th>Term</th>
<th>What it means</th>
</tr>
</thead>
<tbody><tr>
<td>Gateway</td>
<td>Any single chokepoint traffic passes through</td>
</tr>
<tr>
<td>API gateway</td>
<td>A gateway specialized for REST/gRPC application traffic</td>
</tr>
<tr>
<td>AI gateway / LLM gateway</td>
<td>A gateway that understands model requests, tokens, and provider routing</td>
</tr>
<tr>
<td>MCP gateway</td>
<td>A gateway that understands MCP's tool-discovery and tool-call traffic</td>
</tr>
<tr>
<td>AgentGateway</td>
<td>An open-source project unifying all of the above (plus A2A) in one proxy</td>
</tr>
</tbody></table>
<h2>Why we need it</h2>
<p>Without something like this, teams end up running separate infrastructure for each traffic type: an API gateway for services, an LLM proxy for model calls, custom code for MCP auth, and nothing at all for agent-to-agent traffic until it becomes a security incident. Each of those has its own auth model, its own logging format, and its own on-call rotation. Multiply that by every team building an agent, and platform engineering ends up governing four things that all do roughly the same job of "sit between a caller and a backend and enforce policy."</p>
<p>The other driver is cost and governance. Token spend is real money now, and without a gateway layer, the only way to see who's burning budget on which model is to instrument every client separately, or find out from the bill.</p>
<h2>The market players</h2>
<p>This category filled up fast in 2025 and 2026, and it's already consolidating. A rough map of who's building what:</p>
<ul>
<li><p><strong>LiteLLM</strong> is the most widely adopted open-source option for LLM-only routing: a self-hosted, OpenAI-compatible proxy in front of 100+ providers, with virtual keys and budgets. It doesn't touch MCP orchestration, A2A, or plain API traffic the way AgentGateway does, and it took a real hit to its reputation when a March 2026 supply-chain compromise shipped malicious code through two PyPI releases.</p>
</li>
<li><p><strong>Portkey</strong> leans into governance, guardrails, and observability on top of multi-provider routing, with a managed platform. It agreed to be acquired by Palo Alto Networks in April 2026, which is worth watching if you're picking a vendor for the long haul rather than a project you can fork.</p>
</li>
<li><p><strong>Kong AI Gateway</strong> extends Kong's established API-management platform with LLM plugins. It's the natural pick if Kong is already your API gateway standard, less so if you're starting from zero on AI-only infrastructure.</p>
</li>
<li><p><strong>Cloudflare AI Gateway</strong> is the managed, edge-native option: caching and basic routing baked into Cloudflare's network, minimal ops, but shallow governance compared to the others.</p>
</li>
<li><p><strong>Envoy AI Gateway</strong> (and Tetrate's commercial layer on top of it) takes the opposite approach from AgentGateway: build the AI routing as an extension of Envoy rather than a new proxy, which suits teams already deep in Envoy/Istio.</p>
</li>
<li><p><strong>Amazon Bedrock AgentCore Gateway</strong> is AWS's fully managed answer, not literally called "AWS AgentGateway" but functionally the closest thing. Per AWS's own developer guide, it has three target categories: MCP targets (it converts OpenAPI specs, Smithy models, and Lambda functions into MCP-compatible tools and aggregates them into one virtual MCP server), HTTP passthrough targets (which explicitly cover fronting other agents, including A2A traffic, without protocol translation), and inference targets (unified, model-based routing across providers). Inbound auth supports OAuth/JWT or IAM (SigV4); observability runs through CloudWatch metrics, logs, and OTEL-compliant spans, invocations, latency, duration, and error rates, though AWS's docs don't describe a dedicated dollar-cost dashboard the way Azure and AgentGateway have.</p>
</li>
<li><p><strong>Azure's</strong> answer isn't a single product either. Per Microsoft Learn, the AI gateway capabilities live inside <strong>Azure API Management</strong> and explicitly "extend API Management's existing API gateway; it's not a separate offering." It covers OpenAI-compatible and Anthropic-compatible LLM APIs, exposing REST APIs as MCP servers, importing A2A agent APIs, token rate limiting, semantic caching, and load balancing/circuit breakers across backends, plus an optional integration into Microsoft Foundry for governing models, agents, and tools from one place. Separately, and confirmed on Azure's own AKS engineering blog, Azure Kubernetes Service runs the actual open-source agentgateway project itself, as a data plane behind its AKS Application Network add-on. So depending on which "Azure AgentGateway" someone means, they're either talking about API Management's AI gateway (a distinct Microsoft product) or about the open-source agentgateway project running on Azure infrastructure, and those are not the same thing.</p>
</li>
</ul>
<h2>AgentGateway vs the field</h2>
<table>
<thead>
<tr>
<th></th>
<th>AgentGateway</th>
<th>LiteLLM</th>
<th>Portkey</th>
<th>Kong AI Gateway</th>
<th>Cloudflare AI Gateway</th>
<th>AWS Bedrock AgentCore</th>
<th>Azure APIM AI gateway</th>
</tr>
</thead>
<tbody><tr>
<td>License / model</td>
<td>Open source (Apache 2.0, Linux Foundation)</td>
<td>Open source (MIT) + managed tier</td>
<td>Open-source core + managed platform</td>
<td>Commercial, open-source plugins</td>
<td>Managed, usage-based</td>
<td>Fully managed AWS service</td>
<td>Managed Azure service</td>
</tr>
<tr>
<td>Non-AI HTTP/gRPC traffic</td>
<td>Yes, native</td>
<td>No</td>
<td>No</td>
<td>Yes (its origin)</td>
<td>Limited</td>
<td>No</td>
<td>Yes (its origin)</td>
</tr>
<tr>
<td>MCP gateway</td>
<td>Yes, native</td>
<td>Partial</td>
<td>Yes</td>
<td>Partial</td>
<td>No</td>
<td>Yes, native</td>
<td>Partial</td>
</tr>
<tr>
<td>A2A support</td>
<td>Yes, native</td>
<td>No</td>
<td>No</td>
<td>No</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Self-hosted / your infra</td>
<td>Yes</td>
<td>Yes</td>
<td>Limited</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>Cost/token analytics</td>
<td>Yes, built-in $ + token cost (v1.3+)</td>
<td>Yes</td>
<td>Yes, strong</td>
<td>Yes</td>
<td>Basic</td>
<td>CloudWatch usage/latency metrics; no dedicated $ dashboard</td>
<td>Yes, token metrics + $ cost policies</td>
</tr>
<tr>
<td>Best fit</td>
<td>Teams wanting one proxy for services + AI + agents, self-hosted</td>
<td>Teams wanting a lightweight, self-hosted LLM-only proxy</td>
<td>Teams wanting managed governance without running infra</td>
<td>Existing Kong shops</td>
<td>Cloudflare-native apps wanting zero ops</td>
<td>AWS-committed shops wanting a managed service</td>
<td>Azure-committed shops already on APIM</td>
</tr>
</tbody></table>
<p>Treat this table as a starting point, not gospel. Every vendor comparison you'll find online, including some of the sources I used here, is published by a competitor to at least one row in it. Test the fit against your own workload.</p>
<h2>Advantages of AgentGateway</h2>
<p>The single-proxy scope is the headline advantage: one data plane for services, LLM, MCP, and A2A means one auth model, one observability pipeline, and one team that owns it, instead of four. It's genuinely open source under a vendor-neutral foundation rather than open-core with the good parts held back, which matters if you've been burned by a project changing its license later. Being Rust-based gives it a real performance edge over Python-based alternatives like LiteLLM, which run into GIL and garbage-collection limits under heavy concurrent load. And because it grew out of Envoy and Istio Ambient experience, its policy engine (CEL expressions, OPA-style RBAC) is more expressive than most AI-only gateways bother building.</p>
<h2>Disadvantages of AgentGateway</h2>
<p>It's young. The project was created in March 2025, hit v1.0 roughly a year later, and ships on a monthly cadence, which is exciting for velocity but means breaking changes between minors are a real risk you need to plan config migrations around. Its ecosystem of integrations, guides, and third-party tooling is smaller than Kong's or LiteLLM's simply because those have had years longer to accumulate community content. If your organization is already fully committed to AWS or Azure and wants a single-vendor support relationship rather than an open-source project you operate yourself, a managed service like AgentCore Gateway or Azure APIM's AI gateway removes operational burden that AgentGateway asks you to own. And because it's self-hosted by default, you're responsible for scaling, patching, and securing it, the same tradeoff LiteLLM users accept and the same one that bit LiteLLM's users when a malicious release shipped through their own package manager.</p>
<h2>Latest updates and where it's headed</h2>
<p>The most recent minor, v1.3.0, rebuilt the LLM experience around a purpose-built UI with three native views (LLM, MCP, and traffic), added first-class token and dollar cost tracking attributed by model, provider, user, and team, introduced virtual models for weighted/failover/conditional routing, and added 13 new LLM providers along with an Azure provider covering both Azure OpenAI and Azure AI Foundry resources. The project has crossed roughly 2,000 GitHub stars and a million container image pulls in a single recent quarter, and it joined the Agentic AI Foundation as a hosted project, which is meant to keep it vendor-neutral as adoption grows.</p>
<p>Forward-looking work the maintainers have flagged publicly includes finer-grained authorization scoped to individual MCP tools rather than whole servers, progressive disclosure so agents can discover MCP capabilities dynamically instead of relying on static config, and code-execution modes meant to cut down the back-and-forth between agents and tools. None of that is shipped yet, so treat it as direction, not a commitment.</p>
<h2>Where this leaves you</h2>
<p>You've now got the ladder: gateway, API gateway, AI-native gateway, and a clearer sense of where AgentGateway sits against AWS, Azure, and the open-source alternatives. It's not the only option, and it's not automatically the right one for every team, but it's the only one on this list that treats plain services, LLM traffic, MCP, and A2A as one problem instead of four. Back to the regular series next: we'll pick up the build-and-ship rhythm again with the next numbered post.</p>
<hr />
<p><strong>Handy links</strong></p>
<p>Primary sources for the AWS/Azure claims in this post:</p>
<ul>
<li><p><a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html">Amazon Bedrock AgentCore Gateway developer guide</a> (official AWS docs)</p>
</li>
<li><p><a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-core-concepts.html">Core concepts for AgentCore Gateway</a> (target types, incl. A2A via HTTP targets)</p>
</li>
<li><p><a href="https://learn.microsoft.com/en-us/azure/api-management/genai-gateway-capabilities">AI gateway capabilities in Azure API Management</a> (official Microsoft Learn docs)</p>
</li>
<li><p><a href="https://blog.aks.azure.com/2026/04/17/appnet-agentgateway">Control AI spend with Application Network and agentgateway</a> (official AKS Engineering Blog, confirms agentgateway running on AKS)</p>
</li>
</ul>
<p>AgentGateway project sources:</p>
<ul>
<li><p><a href="https://agentgateway.dev/">agentgateway.dev</a> (project home)</p>
</li>
<li><p><a href="https://github.com/agentgateway/agentgateway">agentgateway on GitHub</a> (source, releases, roadmap discussion)</p>
</li>
<li><p><a href="https://agentgateway.dev/blog/2026-06-17-agentgateway-v1.3.0/">AgentGateway v1.3.0 release notes</a></p>
</li>
<li><p><a href="https://aaif.io/projects/agentgateway/">agentgateway at the Agentic AI Foundation</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[What's New in AgentGateway 1.3: An LLM-First UI, Real Cost Tracking, and Virtual Models]]></title><description><![CDATA[In the earlier posts we did things the manual way: grab the Windows binary, run it, and hand-write config.yaml line by line so you could see every bind, listener, route, and backend. That groundwork s]]></description><link>https://blogs.codingfreaks.net/whats-new-agentgateway-1-3</link><guid isPermaLink="true">https://blogs.codingfreaks.net/whats-new-agentgateway-1-3</guid><category><![CDATA[ai, mcp, agents, gateway, aiagentgateway,]]></category><category><![CDATA[AI]]></category><category><![CDATA[agentgateway]]></category><category><![CDATA[#codingfreaks]]></category><category><![CDATA[mcp]]></category><category><![CDATA[aiagentgateway]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Sun, 28 Jun 2026 15:46:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/9c14e321-7098-4790-80dd-504d210fc8c9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the earlier posts we did things the manual way: grab the Windows binary, run it, and hand-write <code>config.yaml</code> line by line so you could see every bind, listener, route, and backend. That groundwork still matters. But AgentGateway 1.3 changes how much of it you'd actually do by hand, especially on the LLM side, so this post steps off the roadmap for one release special to catch up.</p>
<p>If you're new here, you'll walk away knowing what an AI-native gateway's UI gives you and why "cost" and "routing" now live in the gateway instead of your code. If you already route LLM traffic through something, this is the post where you see which of your custom bits just became built-in.</p>
<blockquote>
<p>I'm on AgentGateway v1.3.1 (June 2026). One honest note up front: the headline features below all landed in v1.3.0. v1.3.1 is a small patch on top (a few bug fixes), so I'm treating 1.3 as the feature line and pinning 1.3.1 as the exact build.</p>
</blockquote>
<h2>The new UI, rebuilt around how you consume LLMs</h2>
<p>Before 1.3, the UI was mostly a window into Gateway-API style config. The 1.3 UI reorganizes everything into three native views, and the split tells you a lot about how the project sees the world now:</p>
<ul>
<li><p><strong>LLM</strong> holds models, providers, policies, guardrails, costs, and virtual API keys.</p>
</li>
<li><p><strong>MCP</strong> holds servers, tools, resources, and auth.</p>
</li>
<li><p><strong>Traffic</strong> is the classic HTTP/gRPC Gateway-API experience you already know.</p>
</li>
</ul>
<p>On first launch you pick the capabilities you want and start there, instead of being dropped into a generic config tree. Onboarding a model is now "point an incoming model match at a provider and save," and the same screen lets you add provider-backed models or virtual models. Policies like CORS, API keys, JWT, OIDC, external authz, and rate limiting are configurable per model and visible at a glance, and guardrails (built-in detectors, regex, webhooks, OpenAI moderation, Bedrock Guardrails, Google Model Armor) attach from the same panel.</p>
<p>If you're a pro: if you've ever run a separate admin console for your proxy and a second tool for your model config, this is those two things collapsed into one layer.</p>
<p><strong>Old UI:</strong></p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/f9b9d48a-be3d-477c-9fa5-937bb2dfd316.png" alt="" style="display:block;margin:0 auto" />

  
<p><strong>New UI:</strong></p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/aa0394f2-27a7-4019-82b2-72b1ce241da0.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/42103842-ced4-41a8-88e6-cd3b3d3032c2.png" alt="" style="display:block;margin:0 auto" />

<h2>AI Cost &amp; Analysis: every token and dollar, attributed</h2>
<p>This is the feature I'd lead with if you only read one section. AgentGateway 1.3 turns every request into a measured, attributed, exportable data point. You configure cost rates per model or import the official provider tables, and from then on each request carries its exact input/output/total token counts and a dollar figure, surfaced in logs, traces, metrics, the UI, and <code>agctl</code>.</p>
<p>The real unlock is attribution. The Analytics view slices usage by tokens or by dollars across the dimensions that actually come up in a budget meeting: per user, per team, per model, per provider, and per coding tool or agent (so Claude Code, Cursor, GitHub Copilot, and your own agents show up as separate line items). "How much did the support team spend on Claude through Cursor this week?" becomes a two-filter question instead of a data-engineering project. Because LLM, MCP, and A2A traffic all flow through the same gateway, the same view covers your whole agentic stack, not just chat completions.</p>
<p>For the newcomer: this is the thing finance always asks for and nobody can ever produce, generated automatically because the gateway sees every call.</p>
<p>For the pro: if you've ever scraped provider dashboards into a spreadsheet to do chargeback, this is that job, done at the proxy, with the attribution already attached. And since cost data lives next to your auth and rate-limit policies, you can act on it: set budgets, alert on spend, or route a cost-sensitive caller to a cheaper model with the same policy engine.</p>
<h2>Virtual models: route smarter without client changes</h2>
<p>Real routing is rarely "send everything to one model." You want to A/B a new release against the incumbent, fall back when your primary is throttled, or send long-context requests somewhere with a bigger window. That logic used to live in every client, or in a custom proxy nobody wanted to maintain.</p>
<p>A virtual model is a synthetic model: it has a normal-looking name, but instead of pointing at one backend it applies a routing strategy across several real models. The client just sends the virtual name in the request body, and the gateway decides where each request goes.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/41503f22-7e48-4c19-820e-c5c7ba32bd44.png" alt="" style="display:block;margin:0 auto" />

<p>Three strategies ship in 1.3. Weighted splits traffic by percentage, so you can send most requests to production and a slice to a candidate and compare quality or cost before committing. Failover orders models by preference and retries the next one when the primary errors or gets rate-limited, so a provider hiccup degrades gracefully. Conditional branches on the request itself using CEL, routing by user tier, prompt length, headers, or anything the gateway can see.</p>
<p>The payoff is decoupling. Routing policy lives in one place owned by the platform team, and flipping an A/B split or adding a fallback takes effect everywhere at once, with no client changes.</p>
<p>Pro bridge: if you've baked retry-and-fallback logic into your SDK wrapper, this is that, lifted out of your code and into config.</p>
<h2>Reuse, and a provider explosion</h2>
<p>A few changes that make managing many models less painful. Providers and guardrails are now reusable: define one once and reference it across many models, which matters the moment you're juggling dozens of OpenAI-compatible endpoints. Guardrails can be declared once as a shared top-level resource instead of repeated on every route, and they now apply to streaming responses too, with a <code>failureMode</code> on webhook guards so you choose fail-open or fail-closed. There's a proper custom-provider path for anything without first-class support, which replaces the old "OpenAI provider plus a custom base URL" hack. And 1.3 adds 13 new first-class providers: Mistral, Hugging Face, Cohere, Groq, Fireworks, DeepSeek, xAI, Together AI, OpenRouter, Cerebras, DeepInfra, Baseten, and Ollama.</p>
<h2>The stuff that actually bit me</h2>
<p>A few sharp edges that come specifically from being on 1.3.1 rather than reading the 1.3.0 announcement:</p>
<ul>
<li><p><strong>The</strong> <code>agctl</code> <strong>CLI got reorganized, and it's a breaking change.</strong> Inspection and tracing commands now live under a <code>proxy</code> parent. <code>agctl config all ...</code> is now <code>agctl proxy config all ...</code>, and <code>agctl trace ...</code> is now <code>agctl proxy trace ...</code>. If you have scripts or docs from an older build, they break silently with a "command not found" style error until you update them. There are new <code>agctl version</code> and <code>agctl proxy log</code> / <code>agctl controller log</code> commands too.</p>
</li>
<li><p><strong>"Share one port for MCP and LLM" is in the 1.3 release notes, but it was reverted in 1.3.1.</strong> If you read the feature list and try to serve both on a single listener port on 1.3.1, it won't work. Run them on separate ports, or check the GitHub releases for the version where it lands again. This is exactly why pinning the patch version matters.</p>
</li>
<li><p><strong>The cost numbers depend on a catalog you have to supply.</strong> Dollar figures aren't magic. You either configure rates per model or import the provider tables (<code>agctl costs import</code> can generate one). Skip that and your token counts will be right but your dollars will be empty or wrong.</p>
</li>
<li><p><strong>New providers use</strong> <code>baseUrl</code><strong>, not the old host/path override fields.</strong> If you copy a pre-1.3 snippet for a custom or OpenAI-compatible endpoint, expect it to not validate until you switch to <code>baseUrl</code>.</p>
</li>
</ul>
<h2>Where this leaves you</h2>
<p>You now know what the 1.3 line actually moved into the gateway: a UI organized around LLM, MCP, and Traffic; real per-token and per-dollar cost with attribution you can hand to finance; virtual models that let you A/B, fail over, and branch on requests without client changes; and reusable providers and guardrails across a much bigger provider list. Even on a "no build" read like this one, the mental model is the thing to keep: caller sends a model name, the gateway decides the backend, and every concern (cost, auth, guardrails) attaches at that layer.</p>
<p>Next post we get back on the roadmap and go hands-on: multiplexing several real MCP servers behind one URL, now with the new MCP view to watch the federation happen.</p>
<hr />
<p><strong>Setup I used:</strong> AgentGateway v1.3.1 (binary), Windows 11 with WSL2 (Ubuntu), Node LTS for npx-based MCP servers.</p>
<p><strong>Handy links</strong></p>
<ul>
<li><p>Release blog: <a href="https://agentgateway.dev/blog/2026-06-17-agentgateway-v1.3.0/">https://agentgateway.dev/blog/2026-06-17-agentgateway-v1.3.0/</a></p>
</li>
<li><p>Standalone release notes: <a href="https://agentgateway.dev/docs/standalone/latest/reference/release-notes/">https://agentgateway.dev/docs/standalone/latest/reference/release-notes/</a></p>
</li>
<li><p>Virtual models: <a href="https://agentgateway.dev/docs/standalone/latest/llm/virtual-models/">https://agentgateway.dev/docs/standalone/latest/llm/virtual-models/</a></p>
</li>
<li><p>Model costs: <a href="https://agentgateway.dev/docs/standalone/latest/llm/costs/">https://agentgateway.dev/docs/standalone/latest/llm/costs/</a></p>
</li>
<li><p>LLM providers: <a href="https://agentgateway.dev/docs/standalone/latest/llm/providers/">https://agentgateway.dev/docs/standalone/latest/llm/providers/</a></p>
</li>
<li><p>GitHub releases: <a href="https://github.com/agentgateway/agentgateway/releases">https://github.com/agentgateway/agentgateway/releases</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Reading AgentGateway's config.yaml (From Scary First Line to Writing Your Own)]]></title><description><![CDATA[In Post 2 we grabbed the Windows binary, dropped a config.yaml next to it, and watched a real MCP tool server show up in the browser. It worked. But if I'm honest, we never actually read that file. We]]></description><link>https://blogs.codingfreaks.net/reading-agentgateway-s-config-yaml-from-scary-first-line-to-writing-your-own</link><guid isPermaLink="true">https://blogs.codingfreaks.net/reading-agentgateway-s-config-yaml-from-scary-first-line-to-writing-your-own</guid><category><![CDATA[AI]]></category><category><![CDATA[mcp]]></category><category><![CDATA[AIForTomorrow]]></category><category><![CDATA[agentgateway]]></category><category><![CDATA[#codingfreaks]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Wed, 17 Jun 2026 09:19:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/1d870847-9090-47aa-ab5a-56a83d9d1aca.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In <a href="https://blogs.codingfreaks.net/run-agentgateway-windows-binary-no-build">Post 2</a> we grabbed the Windows binary, dropped a <code>config.yaml</code> next to it, and watched a real MCP tool server show up in the browser. It worked. But if I'm honest, we never actually <em>read</em> that file. We pasted it, ran it, and moved on.</p>
<p>This post fixes that. Every single thing you'll do with AgentGateway from here on — multiplexing tools, fronting OpenAI and Claude, bolting on auth — is just edits to this one file. So if you can read <code>config.yaml</code>, you can read every AgentGateway tutorial on the internet, including the rest of this series. By the end you'll understand each section, know which parts actually matter, and be able to write a config from a blank file instead of copy-pasting one and praying.</p>
<p>If you're brand new, you'll walk away with the mental model. And if you've been lifting configs from the docs without really reading them, this is the post where it clicks.</p>
<p>A quick honesty note about the version, same as last time: I'm on AgentGateway v1.2.1 (current as of June 2026). Pin whatever v1.x you downloaded and write it down, because config schemas shift between majors and you want your notes to stay reproducible.</p>
<h2>Line 1: that scary <code>$schema</code> comment</h2>
<p>Open almost any AgentGateway example and the very first line is this:</p>
<pre><code class="language-yaml"># yaml-language-server: $schema=https://agentgateway.dev/schema/config
</code></pre>
<p>It looks important. It isn't — at least not to AgentGateway. It's a <strong>comment</strong>, and the gateway ignores it completely at runtime. Delete it and your config still runs exactly the same.</p>
<p>What it <em>does</em> do is make your <strong>editor</strong> smart. I touched on this in Post 2, but here's the full story: with the YAML extension installed in VS Code, that line says "validate this file against AgentGateway's schema." Now you get autocomplete on field names, red squiggles the moment you typo <code>backends</code> as <code>backeds</code>, and docs on hover. It's the highest-value line in the file for not wasting an afternoon on a misspelled key — so keep it, even though the gateway never reads it.</p>
<p>That's the whole trick: <strong>it's developer experience, not configuration.</strong> Good thing to know before it confuses you.</p>
<h2>The one mental model that explains everything</h2>
<p>Here's the entire file in a single sentence:</p>
<blockquote>
<p>A request arrives on a <strong>bind</strong>, is accepted by a <strong>listener</strong>, is matched by a <strong>route</strong>, has <strong>policies</strong> applied, and is forwarded to a <strong>backend</strong>.</p>
</blockquote>
<p>Four layers, nested top to bottom:</p>
<pre><code class="language-yaml"># yaml-language-server: $schema=https://agentgateway.dev/schema/config
binds:
- port: 3000              # 1. the PORT requests come in on
  listeners:
  - protocol: HTTP        # 2. WHAT you accept (HTTP — or TCP)
    routes:
    - matches:            # 3. MATCH a request...
      - path:
          pathPrefix: /chat
      policies:           #    ...apply rules (auth, CORS, rate limits)...
        cors:
          allowOrigins: ["*"]
      backends:           # 4. ...and send it WHERE it should go
      - ai:
          name: openai
          provider:
            openAI:
              model: gpt-4o
</code></pre>
<p>Read it as a funnel: <strong>port → protocol → matching rules → destination.</strong> Once you see that shape, every config file looks the same, no matter how big it grows. A 200-line enterprise config is just this skeleton, repeated. Let's take the four layers one at a time.</p>
<h3><code>binds</code> — the port</h3>
<p>A bind is simply a port AgentGateway listens on. Most setups have one (<code>port: 3000</code>). Bigger setups have several — one per port or domain. Everything else lives <em>inside</em> a bind.</p>
<h3><code>listeners</code> — what you accept on that port</h3>
<p>A listener sets the protocol. Use <code>protocol: HTTP</code> for nearly everything — MCP, LLM, A2A, and ordinary web traffic all ride on HTTP. There's also <code>protocol: TCP</code> for raw TCP services (think a database passthrough), with one wrinkle: <strong>TCP listeners use</strong> <code>tcpRoutes</code> <strong>instead of</strong> <code>routes</code>, and those are simpler — no path or header matching, because there's no HTTP to match on.</p>
<h3><code>routes</code> — match first, then decide</h3>
<p>This is the brain of the file. A route does two jobs:</p>
<ol>
<li><p><code>matches</code> decides which requests this route handles — by <code>path</code> (e.g. <code>pathPrefix: /openai</code>), <code>headers</code>, method, or query. A route with <strong>no</strong> <code>matches</code> <strong>block is the catch-all</strong>: it handles anything the earlier routes didn't. That's how you build a default.</p>
</li>
<li><p><code>policies</code> are the rules applied to matched requests — <code>cors</code>, <code>jwtAuth</code>, <code>rateLimit</code>, <code>backendAuth</code>, AI guards, and more. This is where most of your real configuration ends up, and almost every later post in this series adds a block right here.</p>
</li>
</ol>
<h3><code>backends</code> — where the request actually goes</h3>
<p>A backend is the destination, and it comes in <strong>three flavors</strong>. This is the "aha" that unlocks the whole product:</p>
<pre><code class="language-yaml">backends:
- host: example.com:8080          # a plain HTTP/TCP service
# or
- mcp:                            # an MCP tool server
    targets:
    - name: everything
      stdio:
        cmd: npx
        args: ["@modelcontextprotocol/server-everything"]
# or
- ai:                             # an LLM provider
    name: openai
    provider:
      openAI:
        model: gpt-4o
</code></pre>
<p>Same skeleton, three jobs. <code>host:</code> makes AgentGateway a normal reverse proxy. <code>mcp:</code> makes it an MCP gateway. <code>ai:</code> makes it an LLM gateway. You can even mix them in one file.</p>
<h2>The config from Post 2, now readable</h2>
<p>Remember the file we ran last time? Here it is again — except now you can read every line:</p>
<pre><code class="language-yaml"># yaml-language-server: $schema=https://agentgateway.dev/schema/config
binds:
- port: 3000
  listeners:
  - routes:
    - policies:
        cors:
          allowOrigins: ["*"]
          allowHeaders:
          - mcp-protocol-version
          - content-type
          - cache-control
          exposeHeaders:
          - "Mcp-Session-Id"
      backends:
      - mcp:
          targets:
          - name: everything
            stdio:
              cmd: npx
              args: ["@modelcontextprotocol/server-everything"]
</code></pre>
<p>A bind on port 3000, one listener, one catch-all route (no <code>matches</code>, so it takes everything), a CORS policy on that route, and a single <code>mcp</code> backend that AgentGateway launches itself over stdio. Run it the same way:</p>
<pre><code class="language-powershell">.\agentgateway.exe -f config.yaml
</code></pre>
<p>Want an LLM gateway instead of an MCP one? Keep the exact same skeleton and swap the backend block:</p>
<pre><code class="language-yaml">      backends:
      - ai:
          name: openai
          provider:
            openAI:
              model: gpt-4o
      policies:
        backendAuth:
          key: "$OPENAI_API_KEY"   # pulled from an env var — never hardcode
</code></pre>
<p>Notice <code>"$OPENAI_API_KEY"</code>: AgentGateway substitutes environment variables, so your secrets stay <strong>out</strong> of the file and the file stays safe to commit.</p>
<h2>The shortcut the docs kind of bury</h2>
<p>You don't always need the full <code>binds → listeners → routes → backends</code> tree. For simple cases there are two top-level shortcuts:</p>
<ul>
<li><p><code>mcp:</code> connects to MCP servers without the full routing structure.</p>
</li>
<li><p><code>llm:</code> is a model-centric way to route to LLM providers.</p>
</li>
</ul>
<p>Start with these while you're learning, and graduate to the full <code>binds</code> model the moment you need path-based routing, multiple ports, or fine-grained policies. Knowing both styles exist saves you from staring at two tutorials that look completely different — they're just using different levels of the same system.</p>
<h2>The stuff that actually bit me</h2>
<ul>
<li><p><strong>The UI silently ate my comments.</strong> If you edit config through the admin UI on port 15000, it <strong>overwrites the file and wipes every comment</strong> — including that <code>$schema</code> line. Keep a backup, or treat the file as the source of truth and use the UI read-only.</p>
</li>
<li><p><strong>I edited the top-level</strong> <code>config:</code> <strong>section and nothing happened.</strong> Most edits hot-reload while the gateway runs. The exception is the top-level <code>config:</code> block (logging and other startup settings) — that one needs a restart. I sat there reloading the page for a minute before the penny dropped.</p>
</li>
<li><p><strong>I hardcoded a key.</strong> Don't. Use <code>key: "$MY_SECRET"</code> and export the variable. Now your config can live in Git without leaking anything.</p>
</li>
<li><p><strong>My catch-all swallowed everything.</strong> A route with no <code>matches</code> matches <em>all</em> requests, so put your specific routes first and the catch-all last, or the catch-all wins before the others get a look in.</p>
</li>
<li><p><strong>A trimmed config broke CORS.</strong> Same trap as Post 2: if you copy a slimmed-down config and lose <code>mcp-protocol-version</code> from <code>allowHeaders</code>, the browser inspector connects and instantly drops. The headers in that CORS block aren't decoration.</p>
</li>
</ul>
<blockquote>
<p>Small reminder from Post 2: JSON works too. AgentGateway accepts JSON or YAML, so if your team prefers JSON, nothing's stopping you.</p>
</blockquote>
<h2>Where this leaves you</h2>
<p>You can now read any AgentGateway config you'll meet. Port, protocol, match, destination — with policies clipped onto the routes. Every example from here on is a variation on that funnel, and you know exactly where each new block goes.</p>
<p>Next post: instead of one demo server, we point AgentGateway at two or three real MCP servers at once and expose them through a single endpoint, so your IDE or agent gets every tool from one URL. That's where the "gateway" part really starts earning its name — and now that you can read the file, the multiplexing config will read like plain English.</p>
<hr />
<p><strong>Setup I used:</strong> AgentGateway v1.2.1 (binary), Windows 11, Node.js 20 LTS.</p>
<p><strong>Handy links</strong></p>
<ul>
<li><p>Configuration overview: <a href="https://agentgateway.dev/docs/standalone/latest/configuration/overview/">https://agentgateway.dev/docs/standalone/latest/configuration/overview/</a></p>
</li>
<li><p>Routes: <a href="https://agentgateway.dev/docs/standalone/latest/configuration/routes/">https://agentgateway.dev/docs/standalone/latest/configuration/routes/</a></p>
</li>
<li><p>Backends: <a href="https://agentgateway.dev/docs/standalone/latest/configuration/backends/">https://agentgateway.dev/docs/standalone/latest/configuration/backends/</a></p>
</li>
<li><p>LLM configuration modes: <a href="https://agentgateway.dev/docs/standalone/latest/llm/configuration-modes/">https://agentgateway.dev/docs/standalone/latest/llm/configuration-modes/</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Run AgentGateway on Windows in 10 Minutes (Binary, No Build)]]></title><description><![CDATA[In Post 1 I went through what AgentGateway actually is: one Rust binary that can act as an LLM gateway, an MCP gateway, an A2A gateway, or a plain HTTP/gRPC proxy, with the auth and observability the ]]></description><link>https://blogs.codingfreaks.net/run-agentgateway-on-windows-in-10-minutes-binary-no-build</link><guid isPermaLink="true">https://blogs.codingfreaks.net/run-agentgateway-on-windows-in-10-minutes-binary-no-build</guid><category><![CDATA[agentgateway]]></category><category><![CDATA[#codingfreaks]]></category><category><![CDATA[llm]]></category><category><![CDATA[mcp]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Tue, 16 Jun 2026 15:49:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/110b6160-8ca1-4d3d-b40e-0db67ef091e9.svg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In <a href="https://blogs.codingfreaks.net/what-is-agentgateway-the-ai-native-gateway-explained-for-newbies-and-pros">Post 1</a> I went through what AgentGateway actually is: one Rust binary that can act as an LLM gateway, an MCP gateway, an A2A gateway, or a plain HTTP/gRPC proxy, with the auth and observability the raw protocols leave out. That post was all concepts and diagrams. This one is the opposite. We're going to get it running on a Windows machine and prove it works, and we're doing it the lazy way: download the prebuilt binary and go. No <code>cargo build</code>, no Docker image, no WSL required.</p>
<p>By the end you'll have AgentGateway sitting on port 3000, fronting a small MCP "everything" server, and you'll be able to browse its tools in your browser. That's a genuine first win you can build everything else on top of.</p>
<h2>What you need first</h2>
<p>Honestly, not much:</p>
<ul>
<li><p>Windows 10 or 11.</p>
</li>
<li><p>Node.js installed, because the example tool server runs through <code>npx</code>. If <code>node --version</code> prints something in PowerShell, you're set. If not, grab the LTS from nodejs.org and reopen your terminal.</p>
</li>
<li><p>A browser.</p>
</li>
</ul>
<p>That's the whole list. You do <strong>not</strong> need Rust, and you do <strong>not</strong> need Docker for this. The "10 minutes" assumes Node is already there. If you're installing Node from scratch, add a few minutes for that.</p>
<p>A quick honesty note about the version: I'm using AgentGateway v1.2.1, the current release at the time of writing (June 2026). Pin to whatever v1.x you actually download and write the version down somewhere, because config schemas do shift between majors and you want your notes to stay reproducible.</p>
<h2>Step 1: Grab the Windows binary</h2>
<p>Head to the releases page:</p>
<pre><code class="language-plaintext">https://github.com/agentgateway/agentgateway/releases
</code></pre>
<p>Open the latest release and look at the assets list. You want the file that has <code>windows</code> in its name and matches your CPU. In our case, I prefer to use the latest stable release of v1.2.1 (agentgateway-windows-amd64.exe).</p>
<p>You might see the bash one-liner from the docs floating around:</p>
<pre><code class="language-bash">curl https://raw.githubusercontent.com/agentgateway/agentgateway/refs/heads/main/common/scripts/get-agentgateway | bash
</code></pre>
<p>That works great in WSL, Git Bash, macOS, or Linux. It does not run in plain PowerShell or CMD, since it's a shell script. We're going native Windows here, so we're skipping it and just downloading the asset by hand.</p>
<p>If you'd rather not click through the browser, PowerShell can pull a release asset directly. Open the release in your browser once to copy the exact asset URL, then:</p>
<pre><code class="language-powershell"># Example only - paste the actual asset URL you copied from the releases page based on the latest version. 
Invoke-WebRequest -Uri "https://github.com/agentgateway/agentgateway/releases/download/v1.2.1/agentgateway-windows-amd64.exe" -OutFile agentgateway.exe
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/0ed44fa0-195a-476b-957c-a6e69b20d34c.png" alt="" style="display:block;margin:0 auto" />

<p>However you get it, you should end up with <code>agentgateway.exe</code> in a folder. I dropped mine in <code>D:\agentgateway\</code> and ran everything from there. You can add that folder to your PATH later if you want to call it from anywhere, but for a first run it's fine to just <code>cd</code> into it.</p>
<h2>Step 2: Confirm it actually runs</h2>
<p>Before writing any config, make sure the binary starts. From the folder with the exe:</p>
<pre><code class="language-powershell">.\agentgateway.exe
</code></pre>
<p>With no config file, AgentGateway boots with an empty configuration and brings up only its admin interface. Open this in your browser:</p>
<pre><code class="language-plaintext">http://localhost:15000/ui
</code></pre>
<p>If you see the admin UI, the binary is healthy and we can move on. Port 15000 is the admin port and it's separate from whatever port your actual proxy traffic will use. Keep that distinction in your head, it saves confusion later. Stop the process with <code>Ctrl+C</code>.</p>
<p>If you're seeing the output like in the browser UI, do not panic and it is expected. It says, there is no valid configuration found and we will resolve this issue shortly.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/a7305593-fcb9-451a-bf7c-e4c4bfa3a0f1.png" alt="" style="display:block;margin:0 auto" />

<h2>Step 3: Write the config</h2>
<p>Make a file called <code>config.yaml</code> in the same folder. This is the project's basic MCP example, more or less verbatim:</p>
<pre><code class="language-yaml"># yaml-language-server: $schema=https://agentgateway.dev/schema/config
binds:
- port: 3000
  listeners:
  - routes:
    - policies:
        cors:
          allowOrigins:
          - "*"
          allowHeaders:
          - mcp-protocol-version
          - content-type
          - cache-control
          - mcp-session-id
          exposeHeaders:
          - "Mcp-Session-Id"
      backends:
      - mcp:
          targets:
          - name: everything
            stdio:
              cmd: npx
              args: ["@modelcontextprotocol/server-everything"]
</code></pre>
<p>Reading it top to bottom: <code>binds</code> is the port we listen on (3000). Inside it a single <code>listener</code> holds one <code>route</code>, the route carries a CORS policy, and the route points at a <code>backend</code> of type <code>mcp</code>. That backend has one target named <code>everything</code>, which AgentGateway launches by running <code>npx @modelcontextprotocol/server-everything</code> over stdio. So the gateway doesn't connect to some remote server, it spawns the tool server itself the moment a client shows up. I unpacked binds/listeners/routes/backends properly in Post 1 if you want the longer version.</p>
<p>Two things worth pointing at. First, that schema comment on line one is doing real work: if you've got the YAML extension in VS Code, you get autocomplete and red squiggles when you typo a field. Worth having. Second, the CORS block isn't decoration. The browser-based inspector we're about to use won't connect without those MCP headers allowed, and a missing <code>mcp-protocol-version</code> is one of the most common "why won't it connect" issues people hit.</p>
<p>If you don't have <code>npx</code> for some reason and you do have Docker, the same target can run the container instead:</p>
<pre><code class="language-yaml">stdio:
  cmd: docker
  args: ["run", "--rm", "-i", "mcp/everything"]
</code></pre>
<h2>Step 4: Run it for real</h2>
<pre><code class="language-powershell">.\agentgateway.exe -f config.yaml
</code></pre>
<p>The <code>-f</code> flag points it at your config. You'll see startup logging scroll past: it binds on <code>:3000</code>, the admin UI stays on <code>:15000</code>, and the <code>everything</code> target gets registered. Leave this terminal running. That's your gateway.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/baa4e910-5e4d-4855-8982-f9defbeb95cf.png" alt="" style="display:block;margin:0 auto" />

<h2>Step 5: See the tools</h2>
<p>Two easy ways to confirm it's working, and neither one is pasting <code>localhost:3000</code> into a browser.</p>
<p>The no-install option is the gateway's own admin UI at <code>http://localhost:15000/ui</code>. It has a built-in <strong>Playground</strong> that connects to your MCP server and lists its tools right in the browser. Open it, pick your route, click Connect, and the <code>everything</code> tools appear. Honestly this is the fastest path, and I tour the rest of that UI further down.</p>
<p>The other option is the MCP Inspector, worth knowing because it's the standard client every MCP tutorial reaches for. In a second terminal:</p>
<pre><code class="language-powershell">npx @modelcontextprotocol/inspector
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/a07b80c0-3329-41ec-a99e-2163a153f975.png" alt="" style="display:block;margin:0 auto" />

<p>It'll print a local URL and open in your browser. Point it at your gateway's streamable HTTP endpoint:</p>
<pre><code class="language-plaintext">http://localhost:3000/mcp
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/80913d0f-8ba4-4b24-84f4-f5a4050c9795.png" alt="" style="display:block;margin:0 auto" />

<pre><code class="language-plaintext">http://localhost:3000/sse
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/268587ea-4f6c-4278-b643-5483b50816da.png" alt="" style="display:block;margin:0 auto" />

<h2>Wait, why does <code>/mcp</code> look broken in my browser?</h2>
<p>Here's the part that confused me for a solid few minutes, and I suspect it'll catch you too. The natural instinct after starting the gateway is to paste <code>http://localhost:3000/mcp</code> straight into the address bar to "see it." Don't expect a page. You'll get this instead, both on screen and in your gateway logs:</p>
<pre><code class="language-plaintext">http.path=/mcp  http.status=406  protocol=mcp  error="mcp: client must accept text/event-stream"  reason=MCP
</code></pre>
<p>A 406 with <code>client must accept text/event-stream</code> reads like a failure, but it's the gateway working correctly. <code>/mcp</code> isn't a web page, it's a protocol endpoint that speaks the Model Context Protocol over HTTP. The streamable HTTP transport requires the caller to send an <code>Accept: text/event-stream</code> header. Your browser, asking for a normal page, sends <code>Accept: text/html</code> instead, so the gateway politely refuses with a 406. You'll also see a second 406 for <code>/favicon.ico</code> right after, because the browser auto-requests the favicon and it hits the same route. Both are expected.</p>
<p>Now try <code>http://localhost:3000/sse</code> in the browser and you get the opposite experience, the page just hangs with something like:</p>
<pre><code class="language-plaintext">event: endpoint
data: /sse?sessionId=dbaef4fe-a37b-4b9c-8d9f-424891e375e2
</code></pre>
<p>That one renders because SSE <em>is</em> <code>text/event-stream</code>, which browsers understand, so the connection stays open and shows you the first handshake event. It's still not a UI. It's the older SSE transport handing a client the session-specific URL it should post messages to. Interesting to look at once, then close the tab.</p>
<p>So the rule to remember: port 3000 is machine-to-machine, not for eyeballs. Reach it through a client (the Inspector, Claude Desktop, Cursor) that sends <code>Accept: text/event-stream</code> for you. The thing you actually look at in a browser is the admin UI on port 15000. The Inspector connects to the exact same <code>/mcp</code> URL your browser choked on, and it works, because it speaks MCP and your browser doesn't.</p>
<h2>A quick tour of the admin UI</h2>
<p>Open <code>http://localhost:15000/ui</code> and you get a left sidebar with seven sections. Here's what each one is for, in plain terms. The little number next to a few of them is just how many of that thing your config defined, so right now Listeners, Routes, and Backends each show 1.</p>
<ul>
<li><p><strong>Home</strong> is the dashboard. A glance at what's running: your port bindings and the listeners you've configured.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/e5cce14e-6a53-476d-83df-bc29eed2541c.png" alt="" style="display:block;margin:0 auto" />
</li>
<li><p><strong>Listeners</strong> are your entry points. Each one is a port and protocol the gateway accepts traffic on. Yours is the single bind on port 3000.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/15fd20b8-85a0-4223-b103-1c762cc78bd0.png" alt="" style="display:block;margin:0 auto" />
</li>
<li><p><strong>Routes</strong> are the matching rules. A route decides which incoming requests it handles and forwards them to a backend. You've got one catch-all route from the config.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/8259aa49-d707-48b7-bd81-4b4a1bbf4065.png" alt="" style="display:block;margin:0 auto" />
</li>
<li><p><strong>Backends</strong> are the destinations. Where matched traffic actually goes. Yours is that one <code>everything</code> MCP server.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/c5af87a1-33bb-4698-aca0-6ab5bc1df067.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/c90835de-c861-4913-8710-b4f04d7d51c2.png" alt="" style="display:block;margin:0 auto" />
</li>
<li><p><strong>Policies</strong> are the rules layered onto routes and listeners: CORS, authentication, rate limits, header transforms, and the like. The CORS block you wrote earlier shows up here.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/e84e7e05-4426-4459-a4ce-55af428afb84.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/9d46ee06-7bdc-4e53-8b37-c45af7fff318.png" alt="" style="display:block;margin:0 auto" />
</li>
<li><p><strong>Playground</strong> is the built-in test client, and probably the thing you were hunting for when you opened <code>/mcp</code> and got nothing. Select your route, hit Connect, and it lists the live tools straight from your MCP server so you can call them in the browser. No external tooling.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/f0ec83ee-147c-46d8-94d8-587f61caab9b.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/de4c81fc-e8d2-4daa-9337-a0c5a957e806.png" alt="" style="display:block;margin:0 auto" />
</li>
<li><p><strong>CEL Playground</strong> is a scratchpad for CEL expressions. CEL is the little expression language AgentGateway uses inside policies. You type an expression, paste some sample input, click Evaluate, and see the result against the gateway's real CEL runtime before you trust it in a config.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/af369091-a8b0-4d3b-b8d8-d65a81863469.png" alt="" style="display:block;margin:0 auto" /></li>
</ul>
<p>That's enough to find your way around. The first five sections are mostly there to show and edit what's in your <code>config.yaml</code>. The two Playgrounds are the interactive ones, and they're rich enough that I'm giving them their own post later in the series, with real expressions and a proper test workflow rather than a one-liner each.</p>
<h2>The stuff that actually bit me</h2>
<ul>
<li><p><strong>Configuration Error</strong> : When I saw this at first, I got scared that something went wrong and later realized there is no valid configuration file found.</p>
</li>
<li><p><code>406</code> <strong>/ "client must accept text/event-stream" when I open the URL.</strong> You opened <code>/mcp</code> in a browser. That endpoint isn't a web page, it's MCP over HTTP, and it needs an <code>Accept: text/event-stream</code> header your browser doesn't send. Not a bug. Use the Inspector for <code>/mcp</code>, and use port 15000 for anything you want to view in a browser. There's a full breakdown of these logs above.</p>
</li>
<li><p><code>npx</code> <strong>not found.</strong> Node isn't installed, or it's installed but the terminal you opened predates the install. Close the terminal, open a fresh one, retry. PATH only updates for new shells.</p>
</li>
<li><p><strong>Inspector connects then immediately drops.</strong> Almost always CORS. Make sure the <code>allowHeaders</code> list in your config includes <code>mcp-protocol-version</code>. People copy a trimmed config and lose that line.</p>
</li>
<li><p><strong>"Port 3000 is already in use."</strong> Something else grabbed it (a dev server, usually). Change <code>port: 3000</code> to <code>3001</code> in the config and use the new port in the inspector URL.</p>
</li>
<li><p><strong>SmartScreen won't let the exe run.</strong> Covered above: "More info" then "Run anyway," or unblock it in the file's Properties dialog.</p>
</li>
<li><p><strong>The bash install one-liner does nothing in PowerShell.</strong> Right, it's a shell script. Either download the asset manually (what we did) or run that command inside Git Bash or WSL.</p>
</li>
</ul>
<h2>Where this leaves you</h2>
<p>You now have a working AgentGateway on Windows that you set up without compiling a thing, and you've watched it broker a real MCP session. Everything else in this series builds on exactly this setup: same binary, same <code>config.yaml</code>, just more interesting backends and policies.</p>
<p>Next post: instead of one demo server, we point AgentGateway at two or three real MCP servers at once and expose them through a single endpoint, so your IDE or agent gets every tool from one URL. That's where the "gateway" part starts earning its name.</p>
<hr />
<p><strong>Setup I used:</strong> AgentGateway v1.2.1 (binary), Windows 11, Node.js 20 LTS, MCP Inspector via <code>npx</code>.</p>
<p><strong>Handy links</strong></p>
<ul>
<li><p>Quickstart: <a href="https://agentgateway.dev/docs/standalone/latest/quickstart/">https://agentgateway.dev/docs/standalone/latest/quickstart/</a></p>
</li>
<li><p>Connect to MCP servers (Streamable HTTP): <a href="https://agentgateway.dev/docs/standalone/latest/mcp/connect/http/">https://agentgateway.dev/docs/standalone/latest/mcp/connect/http/</a></p>
</li>
<li><p>Releases (binaries): <a href="https://github.com/agentgateway/agentgateway/releases">https://github.com/agentgateway/agentgateway/releases</a></p>
</li>
<li><p>MCP Inspector: <a href="https://github.com/modelcontextprotocol/inspector">https://github.com/modelcontextprotocol/inspector</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[What Is AgentGateway? The AI-Native Gateway, Explained for Newbies and Pros]]></title><description><![CDATA[Spend a week building with AI agents and you hit the same wall I did. The moment there's more than one agent, model, or tool in play, nothing is actually in charge of the traffic moving between them.
]]></description><link>https://blogs.codingfreaks.net/what-is-agentgateway-the-ai-native-gateway-explained-for-newbies-and-pros</link><guid isPermaLink="true">https://blogs.codingfreaks.net/what-is-agentgateway-the-ai-native-gateway-explained-for-newbies-and-pros</guid><category><![CDATA[agentgateway]]></category><category><![CDATA[mcp]]></category><category><![CDATA[#codingfreaks]]></category><category><![CDATA[llm]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Sun, 14 Jun 2026 05:37:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/c0fd0ba8-9741-4f79-986b-29f98c8b62ec.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Spend a week building with AI agents and you hit the same wall I did. The moment there's more than one agent, model, or tool in play, nothing is actually in charge of the traffic moving between them.</p>
<p>Two protocols took a swing at the chaos. <strong>MCP</strong> (<strong>M</strong>odel <strong>C</strong>ontext <strong>P</strong>rotocol) standardizes how an agent talks to tools; think of it as a USB-C port for tools. <strong>A2A</strong> (<strong>A</strong>gent-to-<strong>A</strong>gent) standardizes how agents hand work off to each other. Both are genuinely useful. The problem is that they only describe how the messages are <em>shaped</em>. They say nothing about who's allowed to call what, what it costs you, or how you'd debug any of it in production. No authentication, no authorization, no spend control, no audit trail.</p>
<p><strong>AgentGateway</strong> is the layer that fills that gap. This is Post 1 of the series, so I'll keep it grounded: what AgentGateway actually is, the four modes it runs in, and the two bits of jargon you'll trip over everywhere else, data plane and control plane.</p>
<hr />
<h2>The short version</h2>
<blockquote>
<p>AgentGateway is an open-source, Rust-based proxy that sits between your apps and everything they talk to (LLMs, tools, and other agents) and adds the security, governance, and observability the raw protocols leave out.</p>
</blockquote>
<p>A few things worth knowing before we go deeper:</p>
<ul>
<li><p>It's open source under <strong>Apache 2.0</strong>, and it's written in Rust, which matters here because a lot of agent traffic rides on long-lived connections that a slower proxy would choke on.</p>
</li>
<li><p>It's hosted by the <strong>Linux Foundation</strong> and recently joined the Agentic AI Foundation (<strong>AAIF</strong>).</p>
</li>
<li><p>It speaks <strong>MCP</strong> and <strong>A2A</strong> natively, but it also handles ordinary <strong>HTTP</strong> and <strong>gRPC</strong>. So it isn't a bolt-on "AI sidebar" living next to your real infrastructure.</p>
</li>
</ul>
<p>That last point is really the whole pitch. One gateway for your AI traffic and your normal API traffic, instead of running and securing two separate things.</p>
<hr />
<h2>The four modes</h2>
<p>I find the easiest way to hold AgentGateway in your head is "<em>three agentic patterns</em>, plus the <em>boring traditional one</em>." But before the picture of it working, look at the picture of life without it.</p>
<p>With no gateway, every app wires straight to every backend. Each one carries its own API keys, its own auth, its own retry logic, its own logging, all of it duplicated, and nothing anywhere has a full view of what's calling what. With <em>N</em> apps and <em>M</em> backends, you've built yourself an <em><strong>N × M</strong></em> tangle:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/e09a8fab-e21d-4502-8439-8021770158a4.png" alt="" style="display:block;margin:0 auto" />

<p><strong>AgentGateway</strong> collapses that mesh down to a single governed front door. Same proxy, same policies, four kinds of backend behind it:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/ee7d04dd-de57-4f66-bd73-0516ad574d77.png" alt="" style="display:block;margin:0 auto" />

<h3>1. LLM mode (agent to LLM)</h3>
<p>This is the mode most teams reach for first. You point your apps at one OpenAI-compatible endpoint, and AgentGateway deals with the mess behind it: spreading requests across OpenAI, Anthropic, Gemini, Bedrock, or whatever model you're self-hosting, and failing over when one of them falls down.</p>
<p>The load balancing is smarter than round-robin. It uses <strong>Power of Two Choices (P2C)</strong>: it samples two providers and sends the request to whichever looks healthier on latency and pending load, so a struggling provider quietly sheds traffic on its own. On top of that you get token-based rate limits per user, team, or key. That's your guard against what folks have started calling "denial-of-wallet," a runaway agent loop chewing through your budget while you sleep.</p>
<p>Here's a minimal two-provider config, OpenAI and Gemini behind a single route:</p>
<pre><code class="language-yaml"># yaml-language-server: $schema=https://agentgateway.dev/schema/config
binds:
- port: 3000
  listeners:
  - routes:
    - backends:
      - ai:
          groups:
          - providers:
            - name: openai
              provider:
                openAI:
                  model: gpt-3.5-turbo        # optional; overrides the model in requests
              backendAuth:
                key: "$OPENAI_API_KEY"
            - name: gemini
              provider:
                gemini:
                  model: gemini-1.5-flash-latest
              backendAuth:
                key: "$GEMINI_API_KEY"
</code></pre>
<p>Your app code never changes. It keeps calling a normal <code>/chat/completions</code> endpoint, and the failover, key handling, and cost attribution all happen at the gateway.</p>
<h3>2. MCP mode (agent to tool)</h3>
<p>Picture an agent that needs GitHub, a database, and a search API. The obvious move is to wire it directly to all three MCP servers. AgentGateway lets it talk to one MCP endpoint instead, and federates the servers behind that.</p>
<p>The security payoff is per-session tool filtering. A given client only ever sees the tools it's allowed to use, which is where RBAC and defenses against tool-poisoning attacks come into play.</p>
<pre><code class="language-yaml"># yaml-language-server: $schema=https://agentgateway.dev/schema/config
binds:
- port: 3000
  listeners:
  - routes:
    - policies:
        cors:
          allowOrigins: ["*"]
          allowHeaders: ["*"]
          exposeHeaders:
            - "Mcp-Session-Id"   # required so sessions persist across calls
      backends:
      - mcp:
          targets:
          - name: mcp
            mcp:
              host: http://localhost:3005/mcp/
</code></pre>
<p>Worth a note for anyone who's run gateways before, because this is exactly where the older ones fall over. MCP is stateful. A client and server hold a long-lived session, messages travel both directions, and one "list tools" call can fan out to several backends and come back aggregated. AgentGateway pins each session to a backend and packs the session state into the <code>Mcp-Session-Id</code> (encrypted with AES-256-GCM), so every follow-up call lands back on the same server. A gateway designed around stateless request/response simply can't model that, which is why so many of them buckle the first time you point real MCP traffic at them.</p>
<h3>3. A2A mode (agent to agent)</h3>
<p>Agent A hands a long-running task to Agent B. A2A defines the shape of that handoff, but not the governance around it: who's allowed to delegate to whom, and how you trace the thing once it's running. Put AgentGateway in the middle and you get authentication, authorization, and end-to-end tracing across that boundary. Those happen to be the parts A2A leaves entirely up to you.</p>
<h3>4. HTTP/gRPC mode (the unified part)</h3>
<p>This is the mode people forget, and it's arguably the reason adopting AgentGateway pays off at all. Your plain REST and microservice traffic runs through the same gateway, with the same load balancing, timeouts, retries, TLS, and authorization you've configured everywhere else. You can even take an existing REST API and expose it as an MCP tool. No standing up a separate "AI gateway" beside your "real" one. It's one proxy and one policy set covering both.</p>
<hr />
<h2>Data plane vs. control plane</h2>
<p>These two terms turn up in every gateway and service-mesh doc going, and they reliably trip people up. Here's the version that finally stuck for me.</p>
<p><strong>Picture a restaurant:</strong></p>
<ul>
<li><p>The data plane is the floor staff and the kitchen. They take every order and carry every plate, handling each table (each request) in real time.</p>
</li>
<li><p>The control plane is the manager in the back office. They never serve a table themselves. They write the menu, set the rules, decide which section each server covers, update the specials, then push all that out to the floor.</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/6482134aa6fc6c91eaf86366/07b14c4a-5b21-40c1-bfd3-7365c1ab3eaa.png" alt="" style="display:block;margin:0 auto" />

<p><strong>Mapped onto the product</strong>: AgentGateway itself is the data plane, the Rust proxy doing the real-time work on every request, from routing to auth to rate limiting to tracing. The control plane is whatever configures those proxies. AgentGateway accepts config dynamically over an xDS interface with no downtime, and it conforms to the Kubernetes Gateway API. On Kubernetes, the recommended control plane for spinning up and managing AgentGateway proxies is kgateway.</p>
<p>If you remember one sentence, make it this: the data plane handles and secures every request in real time, and the control plane decides the rules and pushes them down. You can run <strong>AgentGateway</strong> standalone with a static <code>config.yaml</code> (the snippets above are exactly that) or let a control plane drive it inside Kubernetes. Same proxy underneath, either way.</p>
<hr />
<h2>Key terms, in one place</h2>
<table>
<thead>
<tr>
<th>Term</th>
<th>What it means here</th>
</tr>
</thead>
<tbody><tr>
<td><strong>MCP</strong></td>
<td>Model Context Protocol. How agents call tools and data. Stateful, JSON-RPC.</td>
</tr>
<tr>
<td><strong>A2A</strong></td>
<td>Agent-to-Agent. How agents delegate tasks to each other.</td>
</tr>
<tr>
<td><strong>Data plane</strong></td>
<td>The proxy that moves and inspects every request. AgentGateway itself.</td>
</tr>
<tr>
<td><strong>Control plane</strong></td>
<td>The component that configures the proxies, e.g. kgateway on Kubernetes.</td>
</tr>
<tr>
<td><strong>xDS</strong></td>
<td>The interface for pushing config to the proxy live, with no restart.</td>
</tr>
<tr>
<td><strong>P2C</strong></td>
<td>Power of Two Choices. The load-balancing strategy across LLM providers.</td>
</tr>
<tr>
<td><strong>Tool federation</strong></td>
<td>Exposing many MCP servers through one endpoint, filtered per client.</td>
</tr>
<tr>
<td><strong>Denial-of-wallet</strong></td>
<td>A cost attack via runaway token usage. Stopped with token rate limits.</td>
</tr>
</tbody></table>
<hr />
<h2>Where this is going</h2>
<p>So that's the idea. AgentGateway gives your agents, models, tools, and ordinary APIs one governed front door, running in four modes (LLM, MCP, A2A, HTTP/gRPC), with a clean split between the proxy that does the work and the control plane that sets the rules.</p>
<p>Next time I'll get hands-on: install the binary, run the LLM config from above, and actually watch failover and spend limits kick in. Bring a couple of API keys.</p>
<hr />
<h3>Further reading</h3>
<ul>
<li><p><strong>AgentGateway docs, Introduction</strong>: <a href="https://agentgateway.dev/docs/standalone/main/about/introduction/">https://agentgateway.dev/docs/standalone/main/about/introduction/</a></p>
</li>
<li><p><strong>Multiple LLM providers (P2C load balancing)</strong>: <a href="https://agentgateway.dev/docs/standalone/main/llm/providers/multiple-llms/">https://agentgateway.dev/docs/standalone/main/llm/providers/multiple-llms/</a></p>
</li>
<li><p><strong>Connect to MCP servers (Streamable HTTP)</strong>: <a href="https://agentgateway.dev/docs/standalone/main/mcp/connect/http/">https://agentgateway.dev/docs/standalone/main/mcp/connect/http/</a></p>
</li>
<li><p><strong>GitHub</strong>: <a href="https://github.com/agentgateway/agentgateway">https://github.com/agentgateway/agentgateway</a></p>
</li>
<li><p><strong>Linux Foundation announcement</strong>: <a href="https://www.linuxfoundation.org/press/linux-foundation-welcomes-agentgateway-project-to-accelerate-ai-agent-adoption-while-maintaining-security-observability-and-governance">https://www.linuxfoundation.org/press/linux-foundation-welcomes-agentgateway-project-to-accelerate-ai-agent-adoption-while-maintaining-security-observability-and-governance</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Agent Anatomy 101: Brain, Tools, and Memory]]></title><description><![CDATA[In the previous posts, we explored what AI agents are and how quickly you can get started building them using C# and Azure AI Foundry. By now, one thing should already be clear: AI agents are not just]]></description><link>https://blogs.codingfreaks.net/agent-anatomy-101-brain-tools-and-memory</link><guid isPermaLink="true">https://blogs.codingfreaks.net/agent-anatomy-101-brain-tools-and-memory</guid><category><![CDATA[agentic AI]]></category><category><![CDATA[ai agents]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[c sharp]]></category><category><![CDATA[llm]]></category><category><![CDATA[AI Engineering]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Fri, 20 Feb 2026 05:00:00 GMT</pubDate><content:encoded><![CDATA[<p>In the previous posts, we explored what AI agents are and how quickly you can get started building them using C# and Azure AI Foundry. By now, one thing should already be clear: <em>AI agents are not just another chatbot</em> wrapper around an LLM.</p>
<p><strong>They are systems.</strong></p>
<p>And like every well-designed system, AI agents are built from multiple moving parts working together toward a goal.</p>
<p>One of the biggest mistakes I see developers make early is treating the LLM as the entire agent. That assumption usually works for demos. But the moment you attempt to build something practical — an internal assistant, a customer support workflow, an approval system, or an enterprise automation pipeline — the architecture starts becoming much more important than the prompt itself.</p>
<p>To build reliable agents, you need to understand their anatomy.</p>
<p>At the center of almost every modern AI agent are three core components:</p>
<ul>
<li><p>The Brain</p>
</li>
<li><p>The Tools</p>
</li>
<li><p>The Memory</p>
</li>
</ul>
<p>Once you understand how these pieces interact, designing AI agents becomes significantly easier. More importantly, you start thinking like an AI engineer instead of someone simply calling an API.</p>
<p>Let’s break this down properly.</p>
<hr />
<h3>The Brain — The Decision-Making Engine</h3>
<p>The “brain” of an AI agent is the reasoning layer. In most modern architectures, this is your Large Language Model (LLM).</p>
<p>This could be:</p>
<ul>
<li><p>OpenAI GPT models</p>
</li>
<li><p>Anthropic Claude models</p>
</li>
<li><p>Google Gemini models</p>
</li>
<li><p>Meta Llama models</p>
</li>
</ul>
<p>The brain is responsible for understanding user intent, reasoning through tasks, deciding what action to take, and generating responses.</p>
<p>But there is an important distinction developers need to understand early:</p>
<blockquote>
<p>The LLM is not the agent.</p>
</blockquote>
<p>It is only one part of the agent.</p>
<p>A standalone model has no idea about:</p>
<ul>
<li><p>Your APIs</p>
</li>
<li><p>Your ERP system</p>
</li>
<li><p>Your SQL database</p>
</li>
<li><p>Your documents</p>
</li>
<li><p>Your emails</p>
</li>
<li><p>Your business rules</p>
</li>
<li><p>Your production environment</p>
</li>
</ul>
<p>Without external connections, the model can only generate responses based on what it learned during training.</p>
<p>That’s why the real power of agents comes from combining reasoning with execution capabilities.</p>
<p>And that execution layer comes through tools.</p>
<hr />
<h3>Why the Brain Alone Is Not Enough</h3>
<p>Let’s imagine you build a warehouse support assistant.</p>
<p>A user asks:</p>
<blockquote>
<p>“How many units of Product X are currently available?”</p>
</blockquote>
<p>A plain LLM cannot answer that accurately.</p>
<p>It may attempt to generate a response.<br />It may even sound convincing.<br />But it does not have access to your live inventory system.</p>
<p>This is where many beginners encounter the difference between:</p>
<ul>
<li><p>AI demos and</p>
</li>
<li><p>AI systems</p>
</li>
</ul>
<p>Real business systems require live data, authenticated access, and operational workflows.</p>
<p>The model needs a way to interact with the outside world.</p>
<p>That interaction happens through tools.</p>
<hr />
<h3>Tools — The Execution Layer</h3>
<p>If the brain decides what to do, tools are how the work actually gets done.</p>
<p>Tools allow agents to interact with external systems.</p>
<p>In practical terms, tools can be:</p>
<ul>
<li><p>REST APIs</p>
</li>
<li><p>SQL queries</p>
</li>
<li><p>File readers</p>
</li>
<li><p>Web searches</p>
</li>
<li><p>Email services</p>
</li>
<li><p>Calendar integrations</p>
</li>
<li><p>Payment systems</p>
</li>
<li><p>Internal microservices</p>
</li>
<li><p>Business workflows</p>
</li>
</ul>
<p>Think of tools as the hands of the AI agent.</p>
<p>The LLM <em>reasons</em>.<br />The tools <em>execute</em>.</p>
<p>This distinction becomes incredibly important when designing enterprise-grade agents.</p>
<hr />
<h3>A Simple Real-World Flow</h3>
<p>Suppose you are building a customer support agent for an e-commerce platform.</p>
<p>A user types:</p>
<blockquote>
<p>“Where is my order?”</p>
</blockquote>
<p>Internally, the workflow may look something like this:</p>
<p><strong>Step 1 — Understand Intent</strong></p>
<p>The LLM identifies:</p>
<ul>
<li><p>The user is asking about shipment tracking</p>
</li>
<li><p>An order lookup is required</p>
</li>
</ul>
<p><strong>Step 2 — Select the Correct Tool</strong></p>
<p>The agent decides:</p>
<ul>
<li>“I should call the order tracking service.”</li>
</ul>
<p><strong>Step 3 — Execute the Tool</strong></p>
<p>The API returns:</p>
<ul>
<li><p>Shipment status</p>
</li>
<li><p>Courier information</p>
</li>
<li><p>Expected delivery date</p>
</li>
</ul>
<p><strong>Step 4 — Generate the Response</strong></p>
<p>The LLM converts technical data into natural language:</p>
<blockquote>
<p>“Your order was shipped yesterday and is expected to arrive on Friday.”</p>
</blockquote>
<p>This is the moment where AI starts becoming useful in real systems.</p>
<p>Not because the model memorized information.</p>
<p>But because the agent can interact with operational systems dynamically.</p>
<hr />
<h3>The Architecture Still Matters</h3>
<p>One misconception floating around the industry right now is the idea that AI agents somehow replace software architecture.</p>
<p>In reality, they amplify the importance of good architecture.</p>
<p>Your:</p>
<ul>
<li><p>APIs</p>
</li>
<li><p>Logging</p>
</li>
<li><p>Security</p>
</li>
<li><p>Dependency Injection</p>
</li>
<li><p>Exception handling</p>
</li>
<li><p>Retry mechanisms</p>
</li>
<li><p>Observability</p>
</li>
<li><p>Authorization boundaries</p>
</li>
</ul>
<p>…still matter.</p>
<p>In fact, they matter even more.</p>
<p>Because now you are allowing an intelligent system to orchestrate actions across your applications.</p>
<p>A badly designed backend combined with AI simply becomes an intelligent way to create larger problems faster.</p>
<p>That’s why experienced backend engineers and architects have a huge advantage in the AI space right now.</p>
<hr />
<h3>Designing Better Tools in C#</h3>
<p>One thing I strongly recommend when building AI agents in .NET is keeping tools focused and intentional.</p>
<p>For example, avoid creating tools like this:</p>
<p><code>ExecuteBusinessOperation()</code></p>
<p>That tells the model almost nothing.</p>
<p>Instead, create smaller and clearly scoped tools:</p>
<p><code>GetCustomerOrders()</code><br /><code>GetInventoryStatus()</code><br /><code>CreateSupportTicket()</code><br /><code>SendInvoiceEmail()</code></p>
<p>This approach provides several advantages:</p>
<ul>
<li><p>Easier debugging</p>
</li>
<li><p>Better observability</p>
</li>
<li><p>Improved security</p>
</li>
<li><p>Cleaner permissions</p>
</li>
<li><p>Simpler testing</p>
</li>
<li><p>Better reasoning accuracy for the LLM</p>
</li>
</ul>
<p>Interestingly, many classic software engineering principles map directly into AI agent design.</p>
<p>SOLID principles still matter. Separation of concerns still matters. Clean architecture still matters.</p>
<p>The technologies evolved. The engineering fundamentals did not.</p>
<h3>Memory — The Part That Makes Agents Feel Intelligent</h3>
<p>Now we arrive at the component that changes AI interactions from temporary conversations into persistent experiences.</p>
<p>Memory.</p>
<p>Without memory, every interaction starts from zero.</p>
<p><strong>The agent forgets:</strong></p>
<ul>
<li><p>Previous conversations</p>
</li>
<li><p>User preferences</p>
</li>
<li><p>Prior decisions</p>
</li>
<li><p>Ongoing workflows</p>
</li>
<li><p>Business context</p>
</li>
</ul>
<p>This is how basic chatbot systems behave.</p>
<p>But real AI agents need continuity.</p>
<p>They need to remember enough context to operate intelligently over time.</p>
<h3>Short-Term Memory</h3>
<p>Short-term memory usually contains temporary working context.</p>
<p>Examples include:</p>
<ul>
<li><p>Active conversation history</p>
</li>
<li><p>Current task state</p>
</li>
<li><p>Temporary reasoning chains</p>
</li>
<li><p>Session-level information</p>
</li>
</ul>
<p>Imagine a user discussing an invoice issue.</p>
<p>The agent remembers:</p>
<ul>
<li><p>Invoice number</p>
</li>
<li><p>Customer details</p>
</li>
<li><p>Current troubleshooting steps</p>
</li>
</ul>
<p>This information helps maintain continuity during the session.</p>
<p>But it may disappear once the interaction ends.</p>
<h3>Long-Term Memory</h3>
<p>Long-term memory persists across sessions.</p>
<p>This is where agents start feeling significantly more personalized and useful.</p>
<p><strong>Examples include:</strong></p>
<ul>
<li><p>Customer preferences</p>
</li>
<li><p>Frequently used workflows</p>
</li>
<li><p>Historical interactions</p>
</li>
<li><p>Learned patterns</p>
</li>
<li><p>Organizational context</p>
</li>
</ul>
<p><strong>For example:</strong></p>
<p>“This customer always prefers email communication.”</p>
<p>Now the agent can adapt future interactions automatically.</p>
<p>This is also where production-grade AI systems become much more complex.</p>
<p>Because storing memory introduces real engineering challenges.</p>
<hr />
<h3>Memory Is Harder Than It Looks</h3>
<p><em>At first glance, memory sounds simple.</em></p>
<p>Just store conversation history, right?</p>
<p>Not exactly.</p>
<p>Once you start building production systems, difficult questions appear quickly:</p>
<ul>
<li><p>What information should be stored?</p>
</li>
<li><p>What information should expire?</p>
</li>
<li><p>How long should memory persist?</p>
</li>
<li><p>Should memory be searchable?</p>
</li>
<li><p>How do we prevent stale memory?</p>
</li>
<li><p>How do we secure sensitive data?</p>
</li>
<li><p>How do we avoid hallucinated memory retrieval?</p>
</li>
</ul>
<p>This is where AI engineering starts overlapping heavily with distributed systems engineering.</p>
<p>Because now you are dealing with:</p>
<ul>
<li><p>State management</p>
</li>
<li><p>Retrieval systems</p>
</li>
<li><p>Data persistence</p>
</li>
<li><p>Context optimization</p>
</li>
<li><p>Token limitations</p>
</li>
<li><p>Security controls</p>
</li>
</ul>
<p>And suddenly the architecture becomes far more important than prompt engineering alone.</p>
<hr />
<h3>Memory Is More Than Chat History</h3>
<p>Another common misconception is assuming memory simply means storing conversations.</p>
<p>Modern AI memory systems are much broader.</p>
<p>Depending on the architecture, memory may involve:</p>
<ul>
<li><p>Vector databases</p>
</li>
<li><p>Semantic retrieval systems</p>
</li>
<li><p>Knowledge graphs</p>
</li>
<li><p>Search indexes</p>
</li>
<li><p>Event streams</p>
</li>
<li><p>Structured state stores</p>
</li>
</ul>
<p>Technologies often used include:</p>
<ul>
<li><p>PostgreSQL</p>
</li>
<li><p>Redis</p>
</li>
<li><p>MongoDB</p>
</li>
<li><p>Azure AI Search</p>
</li>
<li><p>Pinecone</p>
</li>
<li><p>Weaviate</p>
</li>
</ul>
<p>The memory layer effectively becomes the knowledge infrastructure for the agent.</p>
<p>And this is one area where enterprise-grade architecture decisions matter enormously.</p>
<hr />
<h3>The Agent Loop</h3>
<p>Once the brain, tools, and memory work together, the agent operates in a continuous execution cycle.</p>
<p>A simplified version looks like this:</p>
<ol>
<li><p>Receive user request</p>
</li>
<li><p>Analyze intent</p>
</li>
<li><p>Retrieve relevant memory</p>
</li>
<li><p>Decide next action</p>
</li>
<li><p>Execute tool</p>
</li>
<li><p>Observe results</p>
</li>
<li><p>Update memory</p>
</li>
<li><p>Respond to user</p>
</li>
</ol>
<p>This loop is the foundation behind most modern AI agents.</p>
<p>The sophistication of this cycle determines how autonomous and capable the agent becomes.</p>
<hr />
<h3>Where Many Early AI Agents Fail</h3>
<p>Interestingly, many first-generation AI agent projects fail for architectural reasons rather than model limitations.</p>
<p><strong>Common issues include:</strong></p>
<ul>
<li><p>Poor tool design</p>
</li>
<li><p>Excessive context size</p>
</li>
<li><p>Weak permission boundaries</p>
</li>
<li><p>No retry handling</p>
</li>
<li><p>Lack of observability</p>
</li>
<li><p>No memory strategy</p>
</li>
<li><p>Overloaded prompts</p>
</li>
<li><p>Unclear execution workflows</p>
</li>
</ul>
<p>The industry often focuses heavily on models while underestimating system design.</p>
<p>But production AI systems are fundamentally software systems.</p>
<p><em>And software engineering discipline still wins.</em></p>
<hr />
<h3>The Mental Model Shift</h3>
<p>One of the biggest mindset changes developers need to make is this:</p>
<p>AI agents are not replacing applications.</p>
<p>They are becoming intelligent orchestration layers across applications.</p>
<p><em>That distinction matters.</em></p>
<p>Your ERP still exists.<br />Your APIs still exist.<br />Your databases still exist.</p>
<p>The agent sits above them, coordinating actions intelligently.</p>
<p>That’s why AI engineering feels surprisingly familiar to experienced architects.</p>
<p>You are still designing:</p>
<ul>
<li><p>Services</p>
</li>
<li><p>Interfaces</p>
</li>
<li><p>Workflows</p>
</li>
<li><p>State management</p>
</li>
<li><p>Security boundaries</p>
</li>
<li><p>Communication layers</p>
</li>
</ul>
<p>The difference is that now one component in the system can reason dynamically.</p>
<hr />
<h3>Final Thoughts</h3>
<p>If there’s one key takeaway from this post, it’s this:</p>
<blockquote>
<p><em>An AI agent is not just a model call.</em></p>
</blockquote>
<p>It is a coordinated system made up of:</p>
<ul>
<li><p>Reasoning</p>
</li>
<li><p>Execution</p>
</li>
<li><p>Context</p>
</li>
<li><p>Persistence</p>
</li>
<li><p>Orchestration</p>
</li>
</ul>
<p>The real challenge is rarely invoking the LLM.</p>
<p>The real challenge is designing everything around it correctly.</p>
<p>And honestly, this is where experienced C# developers have a major advantage.</p>
<p>Because many of the skills you already possess:</p>
<ul>
<li><p>Architecture design</p>
</li>
<li><p>Dependency Injection</p>
</li>
<li><p>Distributed systems</p>
</li>
<li><p>API design</p>
</li>
<li><p>Logging</p>
</li>
<li><p>State management</p>
</li>
<li><p>Security Testing</p>
</li>
</ul>
<p>…directly apply to AI agent engineering.</p>
<p>The tools may be new.</p>
<p><em>But the engineering mindset remains timeless.</em></p>
<p>But the engineering mindset remains timeless.</p>
<hr />
<h3>What’s Next</h3>
<p>Now that we understand how agents are structured internally, the next logical question becomes:</p>
<blockquote>
<p>“Which model should I choose as the brain?”</p>
</blockquote>
<p>And that’s exactly what we’ll explore next.</p>
<p>In the next post, we’ll break down:</p>
<ul>
<li><p>GPT vs open-source models</p>
</li>
<li><p>Cost vs performance tradeoffs</p>
</li>
<li><p>Latency considerations</p>
</li>
<li><p>Context windows</p>
</li>
<li><p>Hosting strategies</p>
</li>
<li><p>Enterprise deployment decisions</p>
</li>
</ul>
<p>Because choosing the wrong model early can create architectural and financial problems later.</p>
<p>Next up:</p>
<h3>Post 4 — Choosing Your Agent’s Brain: Models Made Simple</h3>
]]></content:encoded></item><item><title><![CDATA[Improving Security in Agent-to-Agent Communication]]></title><description><![CDATA[Introduction
In my earlier blogpost, we built a Coordinator/Dispatcher Agent that routes tasks to specialized workers. We also read about how agent patterns mirror microservice patterns—API Gateways, Sagas, and Domain-Driven Design. But there's one c...]]></description><link>https://blogs.codingfreaks.net/improving-security-in-agent-to-agent-communication</link><guid isPermaLink="true">https://blogs.codingfreaks.net/improving-security-in-agent-to-agent-communication</guid><category><![CDATA[agents-security]]></category><category><![CDATA[#a2a security]]></category><category><![CDATA[agentic AI]]></category><category><![CDATA[A2A]]></category><category><![CDATA[#codingfreaks]]></category><category><![CDATA[ai agents]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Sun, 15 Feb 2026 05:32:22 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>In my earlier blogpost, we built a <a target="_blank" href="https://blogs.codingfreaks.net/agent-patterns-and-microservice-patterns"><strong>Coordinator/Dispatcher Agent</strong></a> that routes tasks to specialized workers. We also read about how agent patterns mirror microservice patterns—API Gateways, Sagas, and Domain-Driven Design. But there's one critical piece we haven't touched: <strong>Security</strong>.</p>
<ul>
<li><p>When Agent A asks Agent B for customer data, how does Agent B know that Agent A is authorized?</p>
</li>
<li><p>Can Agent C impersonate Agent A?</p>
</li>
<li><p>What if a compromised agent starts asking for sensitive information?</p>
</li>
</ul>
<h2 id="heading-common-misunderstanding"><strong>Common misunderstanding:</strong></h2>
<p>If we treat agent-to-agent (<strong>A2A</strong>) communication as just another API call, we miss the unique challenges of autonomous systems:</p>
<ul>
<li><p>Agents can be <strong>compromised</strong> and used to launch attacks.</p>
</li>
<li><p>Agents can have <strong>dynamic identities</strong> (they spawn and die).</p>
</li>
<li><p>Agents may need <strong>fine-grained permissions</strong> (e.g., "read:customer" but not "write:customer").</p>
</li>
<li><p>We need <strong>audit trails</strong> that prove which agent did what.</p>
</li>
</ul>
<p>In this post, we'll build a practical, production-ready security layer for A2A communication. We'll use <strong>JWT tokens with claims</strong>, an <strong>agent registry</strong>, and <strong>permission-based authorization</strong>. By the end, you'll have a reusable library that secures any agent‑to‑agent call in your system.</p>
<hr />
<h2 id="heading-part-1-basics-why-a2a-security-is-different">Part 1: Basics – Why A2A Security Is Different</h2>
<h3 id="heading-the-microservice-analogy-and-why-it-falls-short">The Microservice Analogy (and Why It Falls Short)</h3>
<p>In microservices, we secure communication with:</p>
<ul>
<li><p><strong>Service-to-service authentication</strong> (mTLS, API keys)</p>
</li>
<li><p><strong>Authorization</strong> (OAuth2 scopes, RBAC)</p>
</li>
<li><p><strong>Audit logging</strong></p>
</li>
</ul>
<p>Agents introduce new complexities:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Aspect</td><td>Microservice</td><td>AI Agent</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Identity</strong></td><td>Fixed service account</td><td>Ephemeral agent instances, may change per request</td></tr>
<tr>
<td><strong>Authorization</strong></td><td>Based on caller role</td><td>Based on agent's <strong>intent</strong> and <strong>capabilities</strong></td></tr>
<tr>
<td><strong>Threat model</strong></td><td>External attackers</td><td>Also <strong>compromised agents</strong> that were once trusted</td></tr>
<tr>
<td><strong>Audit</strong></td><td>Log which service called</td><td>Log <strong>why</strong> the agent called (the user's original request)</td></tr>
</tbody>
</table>
</div><h3 id="heading-core-principles-for-a2a-security">Core Principles for A2A Security</h3>
<ol>
<li><p><strong>Authenticate every request</strong> – The receiving agent must cryptographically verify the caller's identity.</p>
</li>
<li><p><strong>Authorize based on permissions</strong> – Each agent should have a set of permissions (e.g., "read:orders", "write:customers"). The caller's token must contain the required permission for the endpoint.</p>
</li>
<li><p><strong>Use short-lived tokens</strong> – If a token is stolen, it expires quickly.</p>
</li>
<li><p><strong>Maintain an agent registry</strong> – A central place to register agents, their public keys (if using asymmetric signatures), and their permissions.</p>
</li>
<li><p><strong>Audit everything</strong> – Log every A2A call, including the caller, endpoint, and result.</p>
</li>
</ol>
<h3 id="heading-my-approach-jwt-agent-registry">My Approach: JWT + Agent Registry</h3>
<p>We'll use <strong>JSON Web Tokens (JWT)</strong> because they are stateless, widely supported, and can carry custom claims (like permissions). Each agent will:</p>
<ul>
<li><p>Obtain a token from a central <strong>Token Service</strong> (or generate its own using a shared secret/asymmetric key).</p>
</li>
<li><p>Include that token in the <code>Authorization</code> header of every HTTP request to another agent.</p>
</li>
<li><p>The receiving agent will validate the token (signature, expiry, audience) and check if the token's permissions include the required action.</p>
</li>
</ul>
<p>We'll also build an <strong>Agent Registry</strong> that stores:</p>
<ul>
<li><p>Agent ID</p>
</li>
<li><p>Permissions (as a list of strings)</p>
</li>
<li><p>Public key (if using RSA; otherwise, we use a shared symmetric key for simplicity)</p>
</li>
</ul>
<p>For this tutorial, we'll use symmetric signing (HMAC-SHA256) for simplicity.<br /><em>Note :</em>In production, consider asymmetric keys (RSA/ECDSA) so agents don't need to share a secret.</p>
<hr />
<h2 id="heading-part-2-architecture-overview">Part 2: Architecture Overview</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771133113942/5974abcc-a137-4055-b877-86094c5dd44f.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Agent Registry</strong> stores agent metadata.</p>
</li>
<li><p><strong>Token Service</strong> issues JWTs for agents based on their identity.</p>
</li>
<li><p><strong>Agent A</strong> requests a token (or generates its own) and includes it in the request to Agent B.</p>
</li>
<li><p><strong>Agent B</strong> validates the token and checks permissions before executing the request.</p>
</li>
<li><p><strong>Audit logs</strong> are written at both ends.</p>
</li>
</ol>
<hr />
<h2 id="heading-part-3-practical-implementation-step-by-step">Part 3: Practical Implementation – Step by Step</h2>
<p>We'll assume you have a .NET 8 solution with two agent projects: <code>AgentA</code> and <code>AgentB</code>. They communicate via HTTP (<a target="_blank" href="https://asp.net/">ASP.NET</a> Core minimal APIs or controllers). We'll also create a shared class library <code>AgentSecurity</code> for common code.</p>
<h3 id="heading-step-1-define-agent-identity-and-registry">Step 1: Define Agent Identity and Registry</h3>
<p>First, we need a way to represent an agent and its permissions. The registry can be as simple as an in‑memory dictionary for demo purposes, but in production you'd use a database.</p>
<p><strong>AgentSecurity/AgentIdentity.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">AgentSecurity</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AgentIdentity</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> AgentId { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span>[] Permissions { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = Array.Empty&lt;<span class="hljs-keyword">string</span>&gt;();
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span>? PublicKey { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } 
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IAgentRegistry</span>
{
    Task&lt;AgentIdentity?&gt; GetAgentAsync(<span class="hljs-keyword">string</span> agentId);
    <span class="hljs-function">Task&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">HasPermissionAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> agentId, <span class="hljs-keyword">string</span> requiredPermission</span>)</span>;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">InMemoryAgentRegistry</span> : <span class="hljs-title">IAgentRegistry</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> Dictionary&lt;<span class="hljs-keyword">string</span>, AgentIdentity&gt; _agents = <span class="hljs-keyword">new</span>();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">InMemoryAgentRegistry</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-comment">// Pre‑register some agents for demo</span>
        _agents[<span class="hljs-string">"agent-customer-reader"</span>] = <span class="hljs-keyword">new</span> AgentIdentity
        {
            AgentId = <span class="hljs-string">"agent-customer-reader"</span>,
            Permissions = <span class="hljs-keyword">new</span>[] { <span class="hljs-string">"read:customer"</span> }
        };
        _agents[<span class="hljs-string">"agent-order-writer"</span>] = <span class="hljs-keyword">new</span> AgentIdentity
        {
            AgentId = <span class="hljs-string">"agent-order-writer"</span>,
            Permissions = <span class="hljs-keyword">new</span>[] { <span class="hljs-string">"write:order"</span>, <span class="hljs-string">"read:order"</span> }
        };
    }

    <span class="hljs-keyword">public</span> Task&lt;AgentIdentity?&gt; GetAgentAsync(<span class="hljs-keyword">string</span> agentId)
        =&gt; Task.FromResult(_agents.TryGetValue(agentId, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> agent) ? agent : <span class="hljs-literal">null</span>);

    <span class="hljs-function"><span class="hljs-keyword">public</span> Task&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">HasPermissionAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> agentId, <span class="hljs-keyword">string</span> requiredPermission</span>)</span>
    {
        <span class="hljs-keyword">if</span> (_agents.TryGetValue(agentId, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> agent))
        {
            <span class="hljs-keyword">return</span> Task.FromResult(agent.Permissions.Contains(requiredPermission));
        }
        <span class="hljs-keyword">return</span> Task.FromResult(<span class="hljs-literal">false</span>);
    }
}
</code></pre>
<h3 id="heading-step-2-token-service-issue-and-validate-jwts">Step 2: Token Service – Issue and Validate JWTs</h3>
<p>We'll use the <code>System.IdentityModel.Tokens.Jwt</code> package. Install it in the shared project.</p>
<p><strong>AgentSecurity/TokenService.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.IdentityModel.Tokens;
<span class="hljs-keyword">using</span> System.IdentityModel.Tokens.Jwt;
<span class="hljs-keyword">using</span> System.Security.Claims;
<span class="hljs-keyword">using</span> System.Text;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">AgentSecurity</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">ITokenService</span>
{
    <span class="hljs-function"><span class="hljs-keyword">string</span> <span class="hljs-title">GenerateToken</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> agentId, <span class="hljs-keyword">string</span>[] permissions, TimeSpan expiry</span>)</span>;
    Task&lt;ClaimsPrincipal?&gt; ValidateTokenAsync(<span class="hljs-keyword">string</span> token);
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">JwtTokenService</span> : <span class="hljs-title">ITokenService</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> SymmetricSecurityKey _key;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span> _issuer;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span> _audience;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IAgentRegistry _registry;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">JwtTokenService</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> secretKey, <span class="hljs-keyword">string</span> issuer, <span class="hljs-keyword">string</span> audience, IAgentRegistry registry</span>)</span>
    {
        _key = <span class="hljs-keyword">new</span> SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
        _issuer = issuer;
        _audience = audience;
        _registry = registry;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">GenerateToken</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> agentId, <span class="hljs-keyword">string</span>[] permissions, TimeSpan expiry</span>)</span>
    {
        <span class="hljs-keyword">var</span> claims = <span class="hljs-keyword">new</span> List&lt;Claim&gt;
        {
            <span class="hljs-keyword">new</span> Claim(JwtRegisteredClaimNames.Sub, agentId),
            <span class="hljs-keyword">new</span> Claim(<span class="hljs-string">"agent_id"</span>, agentId),
            <span class="hljs-keyword">new</span> Claim(<span class="hljs-string">"permissions"</span>, <span class="hljs-keyword">string</span>.Join(<span class="hljs-string">","</span>, permissions))
        };

        <span class="hljs-keyword">var</span> creds = <span class="hljs-keyword">new</span> SigningCredentials(_key, SecurityAlgorithms.HmacSha256);

        <span class="hljs-keyword">var</span> token = <span class="hljs-keyword">new</span> JwtSecurityToken(
            issuer: _issuer,
            audience: _audience,
            claims: claims,
            expires: DateTime.UtcNow.Add(expiry),
            signingCredentials: creds
        );

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> JwtSecurityTokenHandler().WriteToken(token);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;ClaimsPrincipal?&gt; ValidateTokenAsync(<span class="hljs-keyword">string</span> token)
    {
        <span class="hljs-keyword">var</span> handler = <span class="hljs-keyword">new</span> JwtSecurityTokenHandler();
        <span class="hljs-keyword">try</span>
        {
            <span class="hljs-keyword">var</span> principal = handler.ValidateToken(token, <span class="hljs-keyword">new</span> TokenValidationParameters
            {
                ValidateIssuer = <span class="hljs-literal">true</span>,
                ValidIssuer = _issuer,
                ValidateAudience = <span class="hljs-literal">true</span>,
                ValidAudience = _audience,
                ValidateIssuerSigningKey = <span class="hljs-literal">true</span>,
                IssuerSigningKey = _key,
                ValidateLifetime = <span class="hljs-literal">true</span>,
                ClockSkew = TimeSpan.Zero
            }, <span class="hljs-keyword">out</span> _);

            <span class="hljs-comment">// Optionally, check that the agent still exists and hasn't been revoked</span>
            <span class="hljs-keyword">var</span> agentId = principal.FindFirstValue(<span class="hljs-string">"agent_id"</span>);
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">string</span>.IsNullOrEmpty(agentId) || <span class="hljs-keyword">await</span> _registry.GetAgentAsync(agentId) == <span class="hljs-literal">null</span>)
            {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
            }

            <span class="hljs-keyword">return</span> principal;
        }
        <span class="hljs-keyword">catch</span>
        {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
        }
    }
}
</code></pre>
<h3 id="heading-step-3-authenticated-http-client-for-caller-agent">Step 3: Authenticated HTTP Client for Caller Agent</h3>
<p>Agent A needs an HTTP client that automatically attaches a token. We'll create a typed client.</p>
<p><strong>AgentSecurity/AuthenticatedAgentClient.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Net.Http.Headers;
<span class="hljs-keyword">using</span> System.Text.Json;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">AgentSecurity</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IAuthenticatedAgentClient</span>
{
    Task&lt;TResponse?&gt; PostAsync&lt;TRequest, TResponse&gt;(<span class="hljs-keyword">string</span> url, TRequest request, <span class="hljs-keyword">string</span> requiredPermission);
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticatedAgentClient</span> : <span class="hljs-title">IAuthenticatedAgentClient</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> HttpClient _httpClient;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ITokenService _tokenService;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span> _callerAgentId;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span>[] _callerPermissions;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AuthenticatedAgentClient</span>(<span class="hljs-params">
        HttpClient httpClient,
        ITokenService tokenService,
        <span class="hljs-keyword">string</span> callerAgentId,
        <span class="hljs-keyword">string</span>[] callerPermissions</span>)</span>
    {
        _httpClient = httpClient;
        _tokenService = tokenService;
        _callerAgentId = callerAgentId;
        _callerPermissions = callerPermissions;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> <span class="hljs-title">Task</span>&lt;<span class="hljs-title">TResponse</span>?&gt; <span class="hljs-title">PostAsync</span>&lt;<span class="hljs-title">TRequest</span>, <span class="hljs-title">TResponse</span>&gt;(<span class="hljs-params">
        <span class="hljs-keyword">string</span> url,
        TRequest request,
        <span class="hljs-keyword">string</span> requiredPermission</span>)</span>
    {
        <span class="hljs-comment">// Ensure caller has the required permission (early check and early exit)</span>
        <span class="hljs-keyword">if</span> (!_callerPermissions.Contains(requiredPermission))
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedAccessException(<span class="hljs-string">$"Agent <span class="hljs-subst">{_callerAgentId}</span> lacks permission <span class="hljs-subst">{requiredPermission}</span>"</span>);
        }

        <span class="hljs-comment">// Generate a short‑lived token for this request</span>
        <span class="hljs-keyword">var</span> token = _tokenService.GenerateToken(_callerAgentId, _callerPermissions, TimeSpan.FromMinutes(<span class="hljs-number">5</span>));

        <span class="hljs-keyword">var</span> httpRequest = <span class="hljs-keyword">new</span> HttpRequestMessage(HttpMethod.Post, url);
        httpRequest.Headers.Authorization = <span class="hljs-keyword">new</span> AuthenticationHeaderValue(<span class="hljs-string">"Bearer"</span>, token);
        httpRequest.Content = JsonContent.Create(request);

        <span class="hljs-keyword">var</span> response = <span class="hljs-keyword">await</span> _httpClient.SendAsync(httpRequest);
        response.EnsureSuccessStatusCode();

        <span class="hljs-keyword">var</span> json = <span class="hljs-keyword">await</span> response.Content.ReadAsStringAsync();
        <span class="hljs-keyword">return</span> JsonSerializer.Deserialize&lt;TResponse&gt;(json, <span class="hljs-keyword">new</span> JsonSerializerOptions { PropertyNameCaseInsensitive = <span class="hljs-literal">true</span> });
    }
}
</code></pre>
<h3 id="heading-step-4-serverside-middleware-for-authenticationauthorization">Step 4: Server‑Side Middleware for Authentication/Authorization</h3>
<p>On the receiving agent (Agent B), we need middleware that validates the token and checks permissions before the request reaches the endpoint.</p>
<p>Create an <a target="_blank" href="https://asp.net/">ASP.NET</a> Core minimal API with authentication and authorization.</p>
<p><strong>AgentB/Program.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> AgentSecurity;
<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Authentication.JwtBearer;
<span class="hljs-keyword">using</span> Microsoft.IdentityModel.Tokens;
<span class="hljs-keyword">using</span> System.Text;

<span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);

<span class="hljs-comment">// Configuration</span>
<span class="hljs-keyword">var</span> secretKey = builder.Configuration[<span class="hljs-string">"Jwt:SecretKey"</span>] ?? <span class="hljs-string">"your-256-bit-secret-key-here"</span>;
<span class="hljs-keyword">var</span> issuer = builder.Configuration[<span class="hljs-string">"Jwt:Issuer"</span>] ?? <span class="hljs-string">"agent-system"</span>;
<span class="hljs-keyword">var</span> audience = builder.Configuration[<span class="hljs-string">"Jwt:Audience"</span>] ?? <span class="hljs-string">"agent-audience"</span>;

<span class="hljs-comment">// Register services</span>
builder.Services.AddSingleton&lt;IAgentRegistry, InMemoryAgentRegistry&gt;();
builder.Services.AddSingleton&lt;ITokenService&gt;(sp =&gt;
    <span class="hljs-keyword">new</span> JwtTokenService(secretKey, issuer, audience, sp.GetRequiredService&lt;IAgentRegistry&gt;()));

<span class="hljs-comment">// Add authentication</span>
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =&gt;
    {
        options.TokenValidationParameters = <span class="hljs-keyword">new</span> TokenValidationParameters
        {
            ValidateIssuer = <span class="hljs-literal">true</span>,
            ValidIssuer = issuer,
            ValidateAudience = <span class="hljs-literal">true</span>,
            ValidAudience = audience,
            ValidateIssuerSigningKey = <span class="hljs-literal">true</span>,
            IssuerSigningKey = <span class="hljs-keyword">new</span> SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)),
            ValidateLifetime = <span class="hljs-literal">true</span>,
            ClockSkew = TimeSpan.Zero
        };
    });

builder.Services.AddAuthorization();

<span class="hljs-comment">// Add permission-based authorization handler (optional but convenient)</span>
builder.Services.AddSingleton&lt;IAuthorizationHandler, PermissionHandler&gt;();

builder.Services.AddControllers(); <span class="hljs-comment">// or minimal APIs, we'll use controllers for clarity</span>

<span class="hljs-keyword">var</span> app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();
</code></pre>
<p>Create a custom authorization handler that checks for a required permission claim.</p>
<p><strong>AgentSecurity/PermissionHandler.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Authorization;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PermissionHandler</span> : <span class="hljs-title">AuthorizationHandler</span>&lt;<span class="hljs-title">PermissionRequirement</span>&gt;
{
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> Task <span class="hljs-title">HandleRequirementAsync</span>(<span class="hljs-params">AuthorizationHandlerContext context, PermissionRequirement requirement</span>)</span>
    {
        <span class="hljs-keyword">var</span> permissionsClaim = context.User.FindFirst(<span class="hljs-string">"permissions"</span>)?.Value;
        <span class="hljs-keyword">if</span> (permissionsClaim != <span class="hljs-literal">null</span>)
        {
            <span class="hljs-keyword">var</span> permissions = permissionsClaim.Split(<span class="hljs-string">','</span>, StringSplitOptions.RemoveEmptyEntries);
            <span class="hljs-keyword">if</span> (permissions.Contains(requirement.Permission))
            {
                context.Succeed(requirement);
            }
        }
        <span class="hljs-keyword">return</span> Task.CompletedTask;
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PermissionRequirement</span> : <span class="hljs-title">IAuthorizationRequirement</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Permission { <span class="hljs-keyword">get</span>; }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PermissionRequirement</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> permission</span>)</span> =&gt; Permission = permission;
}

<span class="hljs-comment">// Extension method to easily add [HasPermission("read:customer")]</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AuthorizationPolicyBuilderExtensions</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> AuthorizationPolicyBuilder <span class="hljs-title">RequirePermission</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> AuthorizationPolicyBuilder builder, <span class="hljs-keyword">string</span> permission</span>)</span>
    {
        builder.Requirements.Add(<span class="hljs-keyword">new</span> PermissionRequirement(permission));
        <span class="hljs-keyword">return</span> builder;
    }
}
</code></pre>
<p>Now create a controller in AgentB that requires a specific permission.</p>
<p><strong>AgentB/Controllers/CustomerController.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Authorization;
<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;

[<span class="hljs-meta">ApiController</span>]
[<span class="hljs-meta">Route(<span class="hljs-meta-string">"api/customer"</span>)</span>]
[<span class="hljs-meta">Authorize</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomerController</span> : <span class="hljs-title">ControllerBase</span>
{
    [<span class="hljs-meta">HttpGet(<span class="hljs-meta-string">"{id}"</span>)</span>]
    [<span class="hljs-meta">Authorize(Policy = <span class="hljs-meta-string">"ReadCustomer"</span>)</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">GetCustomer</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> id</span>)</span>
    {
        <span class="hljs-comment">// This would normally fetch from a database, for demo purpuse it is predefined here</span>
        <span class="hljs-keyword">var</span> customer = <span class="hljs-keyword">new</span> { Id = id, Name = <span class="hljs-string">"John Doe"</span>, Email = <span class="hljs-string">"john@example.com"</span> };
        <span class="hljs-keyword">return</span> Ok(customer);
    }

    [<span class="hljs-meta">HttpPost</span>]
    [<span class="hljs-meta">Authorize(Policy = <span class="hljs-meta-string">"WriteCustomer"</span>)</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">CreateCustomer</span>(<span class="hljs-params">[FromBody] CreateCustomerRequest request</span>)</span>
    {
        <span class="hljs-comment">// create customer</span>
        <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { Id = <span class="hljs-number">123</span> });
    }
}
</code></pre>
<p>Register the policies in Program.cs:</p>
<pre><code class="lang-csharp">builder.Services.AddAuthorization(options =&gt;
{
    options.AddPolicy(<span class="hljs-string">"ReadCustomer"</span>, policy =&gt;
        policy.Requirements.Add(<span class="hljs-keyword">new</span> PermissionRequirement(<span class="hljs-string">"read:customer"</span>)));
    options.AddPolicy(<span class="hljs-string">"WriteCustomer"</span>, policy =&gt;
        policy.Requirements.Add(<span class="hljs-keyword">new</span> PermissionRequirement(<span class="hljs-string">"write:customer"</span>)));
});
</code></pre>
<h3 id="heading-step-5-calling-from-agent-a">Step 5: Calling from Agent A</h3>
<p>Now, in Agent A, we'll use the <code>AuthenticatedAgentClient</code> to call Agent B.</p>
<p><strong>AgentA/Program.cs (excerpt)</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> AgentSecurity;

<span class="hljs-comment">// Setup</span>
<span class="hljs-keyword">var</span> registry = <span class="hljs-keyword">new</span> InMemoryAgentRegistry();
<span class="hljs-keyword">var</span> tokenService = <span class="hljs-keyword">new</span> JwtTokenService(<span class="hljs-string">"your-256-bit-secret-key-here"</span>, <span class="hljs-string">"agent-system"</span>, <span class="hljs-string">"agent-audience"</span>, registry);

<span class="hljs-comment">// Assume Agent A's identity is "agent-customer-reader" (permissions: read:customer)</span>
<span class="hljs-keyword">var</span> client = <span class="hljs-keyword">new</span> AuthenticatedAgentClient(
    <span class="hljs-keyword">new</span> HttpClient { BaseAddress = <span class="hljs-keyword">new</span> Uri(<span class="hljs-string">"http://localhost:5001/"</span>) }, <span class="hljs-comment">// Agent B's URL</span>
    tokenService,
    callerAgentId: <span class="hljs-string">"agent-customer-reader"</span>,
    callerPermissions: <span class="hljs-keyword">new</span>[] { <span class="hljs-string">"read:customer"</span> }
);

<span class="hljs-comment">// Call Agent B to get customer 42</span>
<span class="hljs-keyword">try</span>
{
    <span class="hljs-keyword">var</span> customer = <span class="hljs-keyword">await</span> client.PostAsync&lt;<span class="hljs-keyword">object</span>, CustomerResponse&gt;(
        <span class="hljs-string">"api/customer/42"</span>,   <span class="hljs-comment">// Note: using GET would be better, but we use POST for demo</span>
        <span class="hljs-literal">null</span>,                <span class="hljs-comment">// no request body for GET</span>
        requiredPermission: <span class="hljs-string">"read:customer"</span>
    );
    Console.WriteLine(<span class="hljs-string">$"Got customer: <span class="hljs-subst">{customer.Name}</span>"</span>);
}
<span class="hljs-keyword">catch</span> (UnauthorizedAccessException ex)
{
    Console.WriteLine(<span class="hljs-string">$"Permission denied: <span class="hljs-subst">{ex.Message}</span>"</span>);
}
<span class="hljs-keyword">catch</span> (HttpRequestException ex)
{
    Console.WriteLine(<span class="hljs-string">$"Request failed: <span class="hljs-subst">{ex.Message}</span>"</span>);
}
</code></pre>
<p>For a GET request, we'd need a different method. You can extend the client accordingly.</p>
<h3 id="heading-step-6-add-audit-logging">Step 6: Add Audit Logging</h3>
<p>We should log every A2A call. Add an <code>IAuditLogger</code> interface and a simple console implementation.</p>
<p><strong>AgentSecurity/IAuditLogger.cs</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IAuditLogger</span>
{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">LogCall</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> callerAgentId, <span class="hljs-keyword">string</span> targetUrl, <span class="hljs-keyword">string</span> requiredPermission, <span class="hljs-keyword">bool</span> success, <span class="hljs-keyword">string</span>? error = <span class="hljs-literal">null</span></span>)</span>;
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ConsoleAuditLogger</span> : <span class="hljs-title">IAuditLogger</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">LogCall</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> callerAgentId, <span class="hljs-keyword">string</span> targetUrl, <span class="hljs-keyword">string</span> requiredPermission, <span class="hljs-keyword">bool</span> success, <span class="hljs-keyword">string</span>? error = <span class="hljs-literal">null</span></span>)</span>
    {
        Console.WriteLine(<span class="hljs-string">$"[AUDIT] <span class="hljs-subst">{DateTime.UtcNow:O}</span> | Caller: <span class="hljs-subst">{callerAgentId}</span> | URL: <span class="hljs-subst">{targetUrl}</span> | Required: <span class="hljs-subst">{requiredPermission}</span> | Success: <span class="hljs-subst">{success}</span> | Error: <span class="hljs-subst">{error}</span>"</span>);
    }
}
</code></pre>
<p>Inject this into <code>AuthenticatedAgentClient</code> and log after each call. Also log on the server side (in middleware or action filter) to capture the request before validation.</p>
<h3 id="heading-step-7-testing-the-flow">Step 7: Testing the Flow</h3>
<ol>
<li><p>Run Agent B (port 5001).</p>
</li>
<li><p>Run Agent A (console app) and try to call <code>api/customer/42</code>. It should succeed because Agent A has "read:customer".</p>
</li>
<li><p>Modify Agent A's permissions to remove "read:customer" and run again. The client will throw <code>UnauthorizedAccessException</code> before even sending the request (due to the early check). If you bypass the early check, the server will return 403 Forbidden because the token won't contain the required permission.</p>
</li>
<li><p>Try calling a write endpoint (e.g., POST to <code>api/customer</code>). The client will fail the early permission check because Agent A lacks "write:customer".</p>
</li>
</ol>
<h3 id="heading-step-8-advanced-mutual-tls-mtls-for-transport-security">Step 8: Advanced: Mutual TLS (mTLS) for Transport Security</h3>
<p>While JWT handles authentication and authorization, you still need transport security (HTTPS). For higher security, consider <strong>mutual TLS</strong>, where both sides present certificates. This ensures that even if a token is stolen, the attacker cannot connect without the correct client certificate. Many cloud environments (like Azure App Service with TLS mutual authentication) support this.</p>
<p>You can combine mTLS + JWT for defense in depth: the TLS connection verifies the agent's machine identity, while the JWT carries the agent's logical identity and permissions.</p>
<hr />
<h2 id="heading-part-4-conclusion-amp-next-steps">Part 4: Conclusion &amp; Next Steps</h2>
<p>We've built a complete security layer for agent-to-agent communication:</p>
<ul>
<li><p><strong>Authentication</strong> with JWT tokens signed by a central service.</p>
</li>
<li><p><strong>Authorization</strong> with permission claims checked both client‑side and server‑side.</p>
</li>
<li><p><strong>Audit logging</strong> to track who called what.</p>
</li>
<li><p><strong>Integration</strong> with <a target="_blank" href="https://asp.net/">ASP.NET</a> Core's authentication and authorization pipeline.</p>
</li>
</ul>
<p>This pattern mirrors the <a target="_blank" href="https://blogs.codingfreaks.net/agent-patterns-and-microservice-patterns">API Gateway / Coordinator pattern</a> we explored earlier—now with security baked in.</p>
<h3 id="heading-key-takeaways">Key Takeaways</h3>
<ul>
<li><p><strong>Never trust agent identity from the network layer alone</strong> – always include authentication in the application layer.</p>
</li>
<li><p><strong>Use short‑lived tokens</strong> to limit the impact of token theft.</p>
</li>
<li><p><strong>Define fine‑grained permissions</strong> per agent, aligned with the capabilities they expose.</p>
</li>
<li><p><strong>Audit everything</strong> – you'll need it for compliance and debugging.</p>
</li>
<li><p><strong>Consider mTLS</strong> for high‑security environments.</p>
</li>
</ul>
<hr />
]]></content:encoded></item><item><title><![CDATA[Building an Agentic SOC: Monitoring and Observability for Autonomous Agents]]></title><description><![CDATA[Introduction
You've built an AI agent. It can answer questions, call tools, and even make decisions autonomously. It feels like magic. But then a question keeps you up at night: What is it actually doing when I'm not looking?
Unlike a traditional mic...]]></description><link>https://blogs.codingfreaks.net/building-an-agentic-soc-monitoring</link><guid isPermaLink="true">https://blogs.codingfreaks.net/building-an-agentic-soc-monitoring</guid><category><![CDATA[ai agents]]></category><category><![CDATA[#codingfreaks]]></category><category><![CDATA[agentic AI]]></category><category><![CDATA[SOC]]></category><category><![CDATA[ai security]]></category><category><![CDATA[AI Governance]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Sat, 14 Feb 2026 16:11:09 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>You've built an AI agent. It can answer questions, call tools, and even make decisions autonomously. It feels like magic. But then a question keeps you up at night: <strong>What is it actually doing when I'm not looking?</strong></p>
<p>Unlike a traditional microservice, which follows a fixed code path, an agent chooses its own tools, plans its own steps, and generates its own reasoning. This autonomy is powerful—but it also creates a new class of operational risk.</p>
<ul>
<li><p>Did your customer support agent suddenly decide to <strong>email the CEO</strong>?</p>
</li>
<li><p>Did your research agent start pulling <strong>sensitive internal documents</strong>?</p>
</li>
<li><p>Is your agent being slowly manipulated by a <strong>prompt injection attack</strong>?</p>
</li>
</ul>
<p>The only way to answer these questions is to build what I call an <strong>Agentic SOC</strong>—a <strong>S</strong>ecurity <strong>O</strong>perations <strong>C</strong>enter tailored for autonomous agents.</p>
<p>In this post, we'll build one from scratch: a monitoring and observability stack that logs every agent action, detects anomalies in real time, and gives you a dashboard to sleep peacefully at night.</p>
<hr />
<h2 id="heading-part-1-basics-what-is-an-agentic-soc">Part 1: Basics – What Is an Agentic SOC?</h2>
<p>An <strong>Agentic SOC</strong> is a set of practices and tools that provide visibility into the behavior of autonomous AI agents. It adapts the traditional SOC pillars—<strong>logging, metrics, tracing, and alerting</strong>—to the unique challenges of agentic systems.</p>
<h3 id="heading-why-cant-we-just-use-traditional-logging">Why can't we just use traditional logging?</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Traditional Microservice</td><td>AI Agent</td></tr>
</thead>
<tbody>
<tr>
<td>Predictable code paths</td><td>Unpredictable tool choices</td></tr>
<tr>
<td>Structured API calls</td><td>Free‑form natural language</td></tr>
<tr>
<td>Fixed business logic</td><td>Dynamic planning</td></tr>
<tr>
<td>Easy to trace with request IDs</td><td>Hard to trace intent</td></tr>
</tbody>
</table>
</div><p>An agent's "execution" is not a linear sequence of function calls. It's a conversation with itself—an internal chain of thought, tool invocations, and decisions based on past outputs. To truly observe an agent, we need to capture:</p>
<ul>
<li><p><strong>The input prompt</strong> (what the user asked)</p>
</li>
<li><p><strong>The agent's internal reasoning</strong> (if the model exposes it)</p>
</li>
<li><p><strong>Every tool call made</strong> – which tool, with what parameters, and what result</p>
</li>
<li><p><strong>The final output</strong> (what the user sees)</p>
</li>
<li><p><strong>Latency</strong> – how long each step took</p>
</li>
<li><p><strong>Anomalies</strong> – inputs or outputs that deviate from normal patterns</p>
</li>
</ul>
<h3 id="heading-the-four-pillars-of-agentic-observability">The Four Pillars of Agentic Observability</h3>
<ol>
<li><p><strong>Logging</strong> – Record every significant event in a structured, searchable format.</p>
</li>
<li><p><strong>Metrics</strong> – Measure aggregate behavior: request rate, error rate, average latency, tool usage frequency.</p>
</li>
<li><p><strong>Tracing</strong> – Follow a single user request through the agent's entire decision chain.</p>
</li>
<li><p><strong>Alerting</strong> – Get notified when something suspicious happens (e.g., 100 tool calls in one minute, an agent trying to access a forbidden API).</p>
</li>
</ol>
<p>In this tutorial, we'll build a foundation that covers all four.</p>
<hr />
<h2 id="heading-part-2-architecture-overview">Part 2: Architecture Overview</h2>
<p>Here's the high‑level flow we'll implement:</p>
<p>The proposed flow outlines an integrated system for monitoring user input through an agent with middleware, which logs every step and captures telemetry data. This system utilizes an anomaly detection mechanism to identify suspicious patterns in the input, while providing real-time insights via a dashboard powered by Kusto Query Language (KQL). The architecture ensures efficient data flow and robust monitoring capabilities, enhancing overall system reliability and performance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771082532503/5faa2bcc-3930-48d0-925f-b3141a3cfd48.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>The system begins with user input directed to an agent with custom middleware.</p>
</li>
<li><p>Middleware logs actions, measures durations, and captures tool calls for telemetry purposes.</p>
</li>
<li><p>Telemetry data is sent to Azure Application Insights or other sinks for monitoring.</p>
</li>
<li><p>Anomaly detection is performed using either simple heuristics or machine learning models.</p>
</li>
<li><p>Detected anomalies trigger alerts or further actions based on predefined criteria.</p>
</li>
<li><p>Data is queried using KQL to facilitate real-time insights and reporting.</p>
</li>
<li><p>A dashboard displays relevant metrics, insights, and alerts for user interaction.</p>
</li>
</ul>
<hr />
<h2 id="heading-part-3-practical-implementation-step-by-step">Part 3: Practical Implementation – Step by Step</h2>
<p>Let's get our hands dirty. We'll assume you have a .NET 8 project with the <code>Microsoft.AgentFramework</code> package installed.</p>
<h3 id="heading-step-1-create-the-observability-middleware">Step 1: Create the Observability Middleware</h3>
<p>The middleware will wrap every agent invocation. We'll log:</p>
<ul>
<li><p>When the agent starts and finishes</p>
</li>
<li><p>The input (sanitized – never log PII!)</p>
</li>
<li><p>All tool calls</p>
</li>
<li><p>The duration</p>
</li>
<li><p>Any errors</p>
</li>
<li><p>Create a new class <code>ObservabilityMiddleware</code> that implements <code>IAgentMiddleware</code>.</p>
<pre><code class="lang-csharp">  <span class="hljs-keyword">using</span> Microsoft.AgentFramework;
  <span class="hljs-keyword">using</span> Microsoft.AgentFramework.Abstractions;
  <span class="hljs-keyword">using</span> Microsoft.Extensions.Logging;
  <span class="hljs-keyword">using</span> System.Diagnostics;
  <span class="hljs-keyword">using</span> System.Text;

  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ObservabilityMiddleware</span> : <span class="hljs-title">IAgentMiddleware</span>
  {
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;ObservabilityMiddleware&gt; _logger;
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ITelemetryService _telemetry;
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IAnomalyDetector _anomalyDetector;

      <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ObservabilityMiddleware</span>(<span class="hljs-params">
          ILogger&lt;ObservabilityMiddleware&gt; logger,
          ITelemetryService telemetry,
          IAnomalyDetector anomalyDetector</span>)</span>
      {
          _logger = logger;
          _telemetry = telemetry;
          _anomalyDetector = anomalyDetector;
      }

      <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">InvokeAsync</span>(<span class="hljs-params">AgentContext context, Func&lt;Task&gt; next</span>)</span>
      {
          <span class="hljs-keyword">var</span> stopwatch = Stopwatch.StartNew();
          <span class="hljs-keyword">var</span> agentName = context.Agent?.Name ?? <span class="hljs-string">"Unknown"</span>;
          <span class="hljs-keyword">var</span> input = context.Input ?? <span class="hljs-string">""</span>;
          <span class="hljs-keyword">var</span> inputHash = ComputeSha256Hash(input); <span class="hljs-comment">// store hash, not raw PII</span>

          <span class="hljs-comment">// 1. Anomaly detection on input</span>
          <span class="hljs-keyword">var</span> isAnomalous = <span class="hljs-keyword">await</span> _anomalyDetector.CheckInputAsync(input);
          <span class="hljs-keyword">if</span> (isAnomalous)
          {
              _logger.LogWarning(<span class="hljs-string">"Anomalous input detected for agent {AgentName}. Hash: {InputHash}"</span>,
                  agentName, inputHash);
              <span class="hljs-comment">// You could also block here, but we'll just log for now</span>
          }

          <span class="hljs-comment">// 2. Intercept tool calls</span>
          <span class="hljs-keyword">var</span> toolInterceptor = <span class="hljs-keyword">new</span> ToolCallInterceptor();
          <span class="hljs-keyword">var</span> originalToolHandler = context.ToolCallHandler;
          context.ToolCallHandler = <span class="hljs-keyword">async</span> (toolCall, ct) =&gt;
          {
              _logger.LogDebug(<span class="hljs-string">"Agent {AgentName} calling tool {ToolName} with args {Args}"</span>,
                  agentName, toolCall.Name, toolCall.Arguments);
              toolInterceptor.AddCall(toolCall.Name, toolCall.Arguments);

              <span class="hljs-comment">// Let the original handler execute</span>
              <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> originalToolHandler(toolCall, ct);

              _logger.LogDebug(<span class="hljs-string">"Tool {ToolName} returned: {Result}"</span>, toolCall.Name, result);
              <span class="hljs-keyword">return</span> result;
          };

          <span class="hljs-keyword">try</span>
          {
              <span class="hljs-comment">// 3. Execute the agent</span>
              <span class="hljs-keyword">await</span> next();

              <span class="hljs-comment">// 4. Collect results</span>
              <span class="hljs-keyword">var</span> duration = stopwatch.Elapsed;
              <span class="hljs-keyword">var</span> toolsCalled = toolInterceptor.GetCalls();

              _logger.LogInformation(
                  <span class="hljs-string">"Agent {AgentName} completed in {DurationMs}ms. Tools: {ToolCount}"</span>,
                  agentName, duration.TotalMilliseconds, toolsCalled.Count);

              <span class="hljs-comment">// 5. Send telemetry</span>
              _telemetry.TrackAgentExecution(<span class="hljs-keyword">new</span> AgentTelemetry
              {
                  AgentName = agentName,
                  Duration = duration,
                  InputHash = inputHash,
                  ToolCalls = toolsCalled,
                  Success = <span class="hljs-literal">true</span>
              });
          }
          <span class="hljs-keyword">catch</span> (Exception ex)
          {
              _logger.LogError(ex, <span class="hljs-string">"Agent {AgentName} failed after {ElapsedMs}ms"</span>,
                  agentName, stopwatch.Elapsed.TotalMilliseconds);

              _telemetry.TrackAgentExecution(<span class="hljs-keyword">new</span> AgentTelemetry
              {
                  AgentName = agentName,
                  Duration = stopwatch.Elapsed,
                  InputHash = inputHash,
                  Success = <span class="hljs-literal">false</span>,
                  Error = ex.Message
              });

              <span class="hljs-keyword">throw</span>; <span class="hljs-comment">// rethrow after logging</span>
          }
      }

      <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">string</span> <span class="hljs-title">ComputeSha256Hash</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> rawData</span>)</span>
      {
          <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> sha256 = System.Security.Cryptography.SHA256.Create();
          <span class="hljs-keyword">var</span> bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(rawData));
          <span class="hljs-keyword">return</span> Convert.ToBase64String(bytes);
      }
  }

  <span class="hljs-comment">// Helper to track tool calls</span>
  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ToolCallInterceptor</span>
  {
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> List&lt;ToolCallInfo&gt; _calls = <span class="hljs-keyword">new</span>();

      <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddCall</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> name, <span class="hljs-keyword">string</span> arguments</span>)</span>
          =&gt; _calls.Add(<span class="hljs-keyword">new</span> ToolCallInfo(name, arguments, DateTime.UtcNow));

      <span class="hljs-function"><span class="hljs-keyword">public</span> IReadOnlyList&lt;ToolCallInfo&gt; <span class="hljs-title">GetCalls</span>(<span class="hljs-params"></span>)</span> =&gt; _calls.AsReadOnly();
  }

  <span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">ToolCallInfo</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> Name, <span class="hljs-keyword">string</span> Arguments, DateTime Timestamp</span>)</span>;
</code></pre>
<h3 id="heading-step-2-define-telemetry-service-and-anomaly-detector">Step 2: Define Telemetry Service and Anomaly Detector</h3>
<p>  We'll create simple interfaces. For production, you'd implement these with Application Insights and a proper ML service.</p>
<pre><code class="lang-csharp">  <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">ITelemetryService</span>
  {
      <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">TrackAgentExecution</span>(<span class="hljs-params">AgentTelemetry telemetry</span>)</span>;
  }

  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AgentTelemetry</span>
  {
      <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> AgentName { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
      <span class="hljs-keyword">public</span> TimeSpan Duration { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
      <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> InputHash { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
      <span class="hljs-keyword">public</span> IReadOnlyList&lt;ToolCallInfo&gt; ToolCalls { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
      <span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> Success { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
      <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Error { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
  }

  <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IAnomalyDetector</span>
  {
      <span class="hljs-function">Task&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">CheckInputAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> input</span>)</span>;
  }

  <span class="hljs-comment">// A simple heuristic-based detector for demo purposes</span>
  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">SimpleAnomalyDetector</span> : <span class="hljs-title">IAnomalyDetector</span>
  {
      <span class="hljs-function"><span class="hljs-keyword">public</span> Task&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">CheckInputAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> input</span>)</span>
      {
          <span class="hljs-comment">// Rule 1: Extremely long input</span>
          <span class="hljs-keyword">if</span> (input.Length &gt; <span class="hljs-number">5000</span>)
              <span class="hljs-keyword">return</span> Task.FromResult(<span class="hljs-literal">true</span>);

          <span class="hljs-comment">// Rule 2: Contains known jailbreak phrases</span>
          <span class="hljs-keyword">var</span> jailbreakPhrases = <span class="hljs-keyword">new</span>[]
          {
              <span class="hljs-string">"ignore previous instructions"</span>,
              <span class="hljs-string">"ignore all instructions"</span>,
              <span class="hljs-string">"you are now"</span>,
              <span class="hljs-string">"DAN"</span>,
              <span class="hljs-string">"do anything now"</span>
          };
          <span class="hljs-keyword">if</span> (jailbreakPhrases.Any(p =&gt; input.Contains(p, StringComparison.OrdinalIgnoreCase)))
              <span class="hljs-keyword">return</span> Task.FromResult(<span class="hljs-literal">true</span>);

          <span class="hljs-comment">// Rule 3: Contains suspicious XML/JSON that might be Policy Puppetry</span>
          <span class="hljs-keyword">if</span> (input.Contains(<span class="hljs-string">"&lt;SystemPolicy&gt;"</span>) || input.Contains(<span class="hljs-string">"\"role\": \"system\""</span>))
              <span class="hljs-keyword">return</span> Task.FromResult(<span class="hljs-literal">true</span>);

          <span class="hljs-keyword">return</span> Task.FromResult(<span class="hljs-literal">false</span>);
      }
  }
</code></pre>
<h3 id="heading-step-3-implement-telemetry-with-application-insights">Step 3: Implement Telemetry with Application Insights</h3>
<p>  Install the NuGet package: <code>Microsoft.ApplicationInsights.WorkerService</code></p>
<pre><code class="lang-csharp">  <span class="hljs-keyword">using</span> Microsoft.ApplicationInsights;
  <span class="hljs-keyword">using</span> Microsoft.ApplicationInsights.DataContracts;
  <span class="hljs-keyword">using</span> Microsoft.ApplicationInsights.Extensibility;

  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AppInsightsTelemetryService</span> : <span class="hljs-title">ITelemetryService</span>
  {
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> TelemetryClient _telemetryClient;

      <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AppInsightsTelemetryService</span>(<span class="hljs-params">TelemetryConfiguration telemetryConfig</span>)</span>
      {
          _telemetryClient = <span class="hljs-keyword">new</span> TelemetryClient(telemetryConfig);
      }

      <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">TrackAgentExecution</span>(<span class="hljs-params">AgentTelemetry telemetry</span>)</span>
      {
          <span class="hljs-keyword">var</span> evt = <span class="hljs-keyword">new</span> EventTelemetry(<span class="hljs-string">"AgentExecution"</span>);
          evt.Properties[<span class="hljs-string">"AgentName"</span>] = telemetry.AgentName;
          evt.Properties[<span class="hljs-string">"InputHash"</span>] = telemetry.InputHash;
          evt.Properties[<span class="hljs-string">"Success"</span>] = telemetry.Success.ToString();
          evt.Properties[<span class="hljs-string">"ToolCount"</span>] = telemetry.ToolCalls?.Count.ToString() ?? <span class="hljs-string">"0"</span>;
          evt.Properties[<span class="hljs-string">"DurationMs"</span>] = telemetry.Duration.TotalMilliseconds.ToString(<span class="hljs-string">"F2"</span>);
          <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">string</span>.IsNullOrEmpty(telemetry.Error))
              evt.Properties[<span class="hljs-string">"Error"</span>] = telemetry.Error;

          <span class="hljs-comment">// Log each tool call as a separate dependency? For simplicity, we'll add a comma-separated list.</span>
          <span class="hljs-keyword">if</span> (telemetry.ToolCalls?.Any() == <span class="hljs-literal">true</span>)
          {
              evt.Properties[<span class="hljs-string">"Tools"</span>] = <span class="hljs-keyword">string</span>.Join(<span class="hljs-string">","</span>, telemetry.ToolCalls.Select(t =&gt; t.Name));
          }

          _telemetryClient.TrackEvent(evt);
      }
  }
</code></pre>
<h3 id="heading-step-4-register-everything-in-dependency-injection">Step 4: Register Everything in Dependency Injection</h3>
<p>  In your <code>Program.cs</code> (or wherever you build the host), add the services.</p>
<pre><code class="lang-csharp">  <span class="hljs-keyword">using</span> Microsoft.ApplicationInsights.Extensibility;
  <span class="hljs-keyword">using</span> Microsoft.AgentFramework;
  <span class="hljs-keyword">using</span> Microsoft.Extensions.DependencyInjection;
  <span class="hljs-keyword">using</span> Microsoft.Extensions.Hosting;
  <span class="hljs-keyword">using</span> Microsoft.Extensions.Logging;

  <span class="hljs-keyword">var</span> builder = Host.CreateApplicationBuilder(args);

  <span class="hljs-comment">// Add Application Insights</span>
  builder.Services.AddApplicationInsightsTelemetryWorkerService(options =&gt;
  {
      options.ConnectionString = <span class="hljs-string">"InstrumentationKey=...;IngestionEndpoint=..."</span>;
  });

  <span class="hljs-comment">// Register our custom services</span>
  builder.Services.AddSingleton&lt;ITelemetryService, AppInsightsTelemetryService&gt;();
  builder.Services.AddSingleton&lt;IAnomalyDetector, SimpleAnomalyDetector&gt;();

  <span class="hljs-comment">// Add the agent framework and register the middleware</span>
  builder.Services.AddAgentFramework()
      .AddAgent&lt;MyAgent&gt;()
      .UseMiddleware&lt;ObservabilityMiddleware&gt;(); <span class="hljs-comment">// 👈 critical</span>

  builder.Services.AddHostedService&lt;AgentHostedService&gt;(); <span class="hljs-comment">// if you have a long-running agent</span>

  <span class="hljs-keyword">var</span> host = builder.Build();
  <span class="hljs-keyword">await</span> host.RunAsync();
</code></pre>
<h3 id="heading-step-5-create-a-sample-agent-that-uses-tools">Step 5: Create a Sample Agent That Uses Tools</h3>
<p>  Let's create a simple agent with a calculator tool to see the middleware in action.</p>
<pre><code class="lang-csharp">  <span class="hljs-keyword">using</span> Microsoft.AgentFramework;
  <span class="hljs-keyword">using</span> Microsoft.AgentFramework.Abstractions;
  <span class="hljs-keyword">using</span> System.ComponentModel;

  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyAgent</span> : <span class="hljs-title">IAgent</span>
  {
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IChatModel _model;
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IToolRegistry _toolRegistry;

      <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyAgent</span>(<span class="hljs-params">IChatModel model, IToolRegistry toolRegistry</span>)</span>
      {
          _model = model;
          _toolRegistry = toolRegistry;
          <span class="hljs-comment">// Register a calculator tool</span>
          _toolRegistry.RegisterTool(CalculatorTool.Add);
      }

      <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">RunAsync</span>(<span class="hljs-params">CancellationToken cancellationToken</span>)</span>
      {
          Console.WriteLine(<span class="hljs-string">"Agent is ready. Ask something like 'What is 23+19?'"</span>);
          <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>)
          {
              <span class="hljs-keyword">var</span> input = Console.ReadLine();
              <span class="hljs-keyword">if</span> (input == <span class="hljs-string">"exit"</span>) <span class="hljs-keyword">break</span>;

              <span class="hljs-keyword">var</span> response = <span class="hljs-keyword">await</span> _model.GenerateAsync(input, cancellationToken);
              Console.WriteLine(response);
          }
      }
  }

  <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CalculatorTool</span>
  {
      [<span class="hljs-meta">Tool(<span class="hljs-meta-string">"Adds two numbers"</span>)</span>]
      <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">Add</span>(<span class="hljs-params">
          [ToolParameter(<span class="hljs-string">"First number"</span></span>)] <span class="hljs-keyword">int</span> a,
          [<span class="hljs-title">ToolParameter</span>(<span class="hljs-params"><span class="hljs-string">"Second number"</span></span>)] <span class="hljs-keyword">int</span> b)</span> =&gt; a + b;
  }
</code></pre>
<h3 id="heading-step-6-run-and-verify-telemetry-in-application-insights">Step 6: Run and Verify Telemetry in Application Insights</h3>
<p>  After running the agent and making a few queries, go to your Application Insights resource. Navigate to <strong>Logs</strong> and try these KQL queries:</p>
<h4 id="heading-query-1-agent-execution-summary-over-time">Query 1: Agent execution summary over time</h4>
<pre><code class="lang-sql">  customEvents
  | where name == "AgentExecution"
  | project timestamp, 
      agentName = customDimensions.AgentName,
      success = customDimensions.Success,
      durationMs = todouble(customDimensions.DurationMs),
      tools = customDimensions.Tools
  | summarize avg(durationMs) by agentName, bin(timestamp, 1h)
  | render timechart
</code></pre>
<h4 id="heading-query-2-most-active-agents-by-request-count">Query 2: Most active agents by request count</h4>
<pre><code class="lang-sql">  customEvents
  | where name == "AgentExecution"
  | summarize RequestCount = count() by AgentName = customDimensions.AgentName
  | top 10 by RequestCount desc
</code></pre>
<h4 id="heading-query-3-detect-anomalies-high-error-rates">Query 3: Detect anomalies – high error rates</h4>
<pre><code class="lang-sql">  customEvents
  | where name == "AgentExecution"
  | summarize Failures = countif(customDimensions.Success == "False"), 
              Total = count() 
              by bin(timestamp, 5m)
  | extend FailureRate = todouble(Failures) / todouble(Total) * 100
  | where FailureRate &gt; 20
  | project timestamp, FailureRate
</code></pre>
<h4 id="heading-query-4-tool-usage-frequency">Query 4: Tool usage frequency</h4>
<pre><code class="lang-sql">  customEvents
  | where name == "AgentExecution"
  | where isnotempty(customDimensions.Tools)
  | extend tools = split(customDimensions.Tools, ",")
  | mv-expand tools
  | summarize ToolCount = count() by tostring(tools)
  | render piechart
</code></pre>
<h3 id="heading-step-7-build-a-real-time-dashboard">Step 7: Build a Real-Time Dashboard</h3>
<p>  In Application Insights, you can create a <strong>Workbook</strong> that combines these queries into a single view. Include:</p>
<ul>
<li><p>A time chart of agent requests and latencies</p>
</li>
<li><p>A table of recent anomalous inputs (by input hash)</p>
</li>
<li><p>A pie chart of tool usage</p>
</li>
<li><p>An alert rule that triggers when error rate exceeds a threshold</p>
</li>
</ul>
</li>
</ul>
<p>    You can set up an alert using Azure Monitor:</p>
<pre><code class="lang-sql">    customEvents
    | where name == "AgentExecution"
    | where customDimensions.Success == "False"
    | summarize Count = count() by bin(timestamp, 5m)
    | where Count &gt; 10
</code></pre>
<hr />
<h2 id="heading-part-4-conclusion-amp-next-steps">Part 4: Conclusion &amp; Next Steps</h2>
<p>    Now you have a working <strong>Agentic SOC</strong> for your autonomous agents. Every decision, every tool call, every latency spike is captured and queryable. You can:</p>
<ul>
<li><p><strong>Audit</strong> what your agents did last Tuesday at 3 PM.</p>
</li>
<li><p><strong>Detect</strong> anomalous behavior before it becomes a crisis.</p>
</li>
<li><p><strong>Optimize</strong> performance by spotting slow tools or frequent errors.</p>
</li>
<li><p><strong>Sleep better</strong> knowing you have visibility.</p>
</li>
</ul>
<p>    But this is just the beginning. In the coming weeks, we'll extend this foundation:</p>
<ul>
<li><p>Securing agent-to-agent communication with JWT and mTLS.</p>
</li>
<li><p>Building practical defenses against prompt injection.</p>
</li>
<li><p>Preventing data leakage in RAG‑enabled agents.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[From Text Generation to Reasoning in AI]]></title><description><![CDATA[Large Language Models (LLMs) such as ChatGPT, Claude and Gemini have moved quickly from research labs into everyday use. They write emails, summarize documents, and hold conversations well enough that]]></description><link>https://blogs.codingfreaks.net/from-text-generation-to-reasoning-in-ai</link><guid isPermaLink="true">https://blogs.codingfreaks.net/from-text-generation-to-reasoning-in-ai</guid><category><![CDATA[llm]]></category><category><![CDATA[LLM-Retrieval ]]></category><category><![CDATA[LRM ]]></category><category><![CDATA[agentic AI]]></category><category><![CDATA[#codingfreaks]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[AI]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Fri, 12 Dec 2025 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p><strong>Large Language Models</strong> (<strong>LLMs</strong>) such as ChatGPT, Claude and Gemini have moved quickly from research labs into everyday use. They write emails, summarize documents, and hold conversations well enough that many people treat them as if they “understand” what they’re saying.</p>
<p>But something important is changing beneath the surface.</p>
<p>As impressive as LLMs are, their strengths also reveal a limitation: fluency is not the same as reasoning. That gap is what has driven the emergence of <strong>Large Reasoning Models (LRMs)</strong>—systems designed not just to respond convincingly, but to work through problems deliberately and correctly.</p>
<h3>What is LLM?</h3>
<p>A <strong>Large Language Model</strong> is a powerful AI trained on essentially the entire internet. Its genius lies in statistical pattern recognition. When you give it a prompt, it predicts the next most likely word (or "<strong>token</strong>"), then the next, chaining them into coherent, human-like text.</p>
<p>Think of it as an incredibly sophisticated autocomplete. It doesn't "<strong>understand</strong>" in a human sense; it <strong>identifies patterns from its training data</strong>.</p>
<p>This makes LLMs exceptional for:</p>
<ul>
<li><p>Drafting emails and blog posts</p>
</li>
<li><p>Creative storytelling and brainstorming</p>
</li>
<li><p>Summarizing long documents</p>
</li>
<li><p>General conversation and Q&amp;A on familiar topics</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765869161543/27f7c274-37c9-4da4-9e65-f6989f1f7264.png" alt="" style="display:block;margin:0 auto" />

<h3>What is LRM ?</h3>
<p>A <strong>Large Reasoning Model</strong> is what you get when you build deliberate, structured thought on top of an LLM's foundation. If an LLM provides a quick reflex, an LRM offers a considered reflection.</p>
<p><strong>The key difference is the internal "chain of thought."</strong> Before generating an answer, an LRM pauses to:</p>
<ol>
<li><p><strong>Plan:</strong> Sketch a roadmap to a solution.</p>
</li>
<li><p><strong>Execute:</strong> Work through multi-step calculations or logic.</p>
</li>
<li><p><strong>Verify:</strong> Double-check steps in an internal "sandbox" before committing to a final answer.</p>
</li>
</ol>
<p>This allows LRMs to tackle problems where the statistically likely next word is often the <em>wrong</em> one—like debugging complex code, tracing a financial discrepancy, or solving a logic puzzle.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765869077165/4d2dc6bc-69f1-47e0-885d-ac4fd6748155.png" alt="" style="display:block;margin:0 auto" />

<h3>How LRMs Are Developed</h3>
<p>Creating an LRM isn't about building a new model from scratch, but about teaching an existing LLM to reason. The process is intensive and layered:</p>
<ol>
<li><p><strong>Start with a Strong LLM Foundation:</strong> It begins with a heavily pre-trained LLM, which already possesses vast world knowledge and language mastery.</p>
</li>
<li><p><strong>Reasoning-Focused Fine-Tuning:</strong> This is the crucial step. The model is trained on specialized datasets—collections of math word problems, logic puzzles, and code challenges—where each example includes a <strong>full, step-by-step solution</strong>. The model learns to emulate this "<em>show your work</em>" process.</p>
</li>
<li><p><strong>Reinforcement Learning from Process Feedback:</strong> Here, the model's <em>reasoning steps</em> are judged, not just its final answer. A <strong>Process Reward Model (PRM)</strong> evaluates each interim step for quality. Through reinforcement learning, the LRM learns to generate reasoning chains that are logically sound, maximizing its "<strong>reward</strong>."</p>
</li>
<li><p><strong>Knowledge Distillation:</strong> Often, a larger, more capable "teacher" model generates high-quality reasoning traces. These are then used to train a more efficient "student" model, effectively transferring reasoning skills.</p>
</li>
</ol>
<p>The outcome is a system trained to pause, plan, and verify, making it robust for complex, multi-domain problems.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765869366966/4ca496c3-e51d-4750-be18-4b436d76c4b0.png" alt="" style="display:block;margin:0 auto" />

<h3>Where LLMs and LRMs Overlap</h3>
<p>LRMs and LLMs are family, sharing a core DNA:<br /><strong>Architecture</strong>: Both are built on transformer-based neural networks.<br /><strong>Training Foundation</strong>: Both undergo initial pre-training on colossal text and code datasets.<br /><strong>Core Output</strong>: Both ultimately communicate through natural language.</p>
<h3>Key Differences: A Matter of Process</h3>
<table>
<thead>
<tr>
<th><strong>Aspect</strong></th>
<th><strong>Large Language Model (LLM)</strong></th>
<th><strong>Large Reasoning Model (LRM)</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>Primary Mechanism</strong></td>
<td>Next-token prediction (statistical pattern-matching).</td>
<td>Multi-step planning and logical deliberation / thinking.</td>
</tr>
<tr>
<td><strong>Response Generation</strong></td>
<td>Immediate, fluent generation.</td>
<td>Plan -&gt; Execute Steps -&gt; Verify -&gt; Respond.</td>
</tr>
<tr>
<td><strong>Optimal Use Case</strong></td>
<td>Tasks requiring fluency, creativity, and speed: content creation, summarization, casual dialogue.</td>
<td>Tasks requiring logic, planning, and accuracy: complex code debugging, financial analysis, strategic planning.</td>
</tr>
<tr>
<td><strong>Compute &amp; Cost</strong></td>
<td>Lower inference cost and latency (faster, cheaper per query).</td>
<td>Higher inference cost and latency (more "thinking" passes = more compute and time).</td>
</tr>
<tr>
<td><strong>Prompt Reliance</strong></td>
<td>Often requires clever prompting (e.g., "Let's think step by step") to elicit reasoning.</td>
<td>Has structured reasoning baked into its core process.</td>
</tr>
<tr>
<td><strong>Analogy</strong></td>
<td>A brilliant, quick-witted conversationalist.</td>
<td>A meticulous scientist who shows all their calculations.</td>
</tr>
</tbody></table>
<h3>Conclusion: Choosing the Right Tool</h3>
<p>The rise of LRMs marks a shift from AI that <em><strong>speaks</strong></em> to AI that <em><strong>reasons</strong></em>. Today's top-performing models on advanced benchmarks are increasingly reasoning models.</p>
<p><strong>When to use an LLM:</strong> For tasks where speed, creativity, and low cost are paramount—social media posts, brainstorming, or simple queries—an LLM's reflex is perfectly sufficient.</p>
<p><strong>When an LRM is worth the cost:</strong> For problems where accuracy, logical soundness, and multi-step deduction are critical—untangling complex code, analyzing financial structures, or solving intricate planning problems—the LRM's deliberate think-time is a worthy investment.</p>
<p>The future of AI isn't just about faster text generation; it's about building systems that pause, reason, and show their work. LRMs represent a significant step toward that future, offering not just answers, but accountable and verifiable thought processes.</p>
]]></content:encoded></item><item><title><![CDATA[Aligning Agent Patterns with Microservice Patterns]]></title><description><![CDATA[Introduction
Although AI agent systems are often presented as something entirely new, many of their architectural patterns will feel familiar to anyone who has worked with microservices. In practice, ]]></description><link>https://blogs.codingfreaks.net/agent-patterns-and-microservice-patterns</link><guid isPermaLink="true">https://blogs.codingfreaks.net/agent-patterns-and-microservice-patterns</guid><category><![CDATA[ai agent patterns]]></category><category><![CDATA[ai-agent]]></category><category><![CDATA[AI Agent Development]]></category><category><![CDATA[Microservices]]></category><category><![CDATA[#codingfreaks]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Fri, 12 Dec 2025 12:24:58 GMT</pubDate><content:encoded><![CDATA[<h2>Introduction</h2>
<p>Although AI agent systems are often presented as something entirely new, many of their architectural patterns will feel familiar to anyone who has worked with microservices. In practice, most agent patterns can be mapped quite naturally to well-known microservice patterns. This makes them easier to understand and, more importantly, easier to remember.</p>
<p>At a high level, agent patterns reuse the same architectural intent as microservices: <strong>routing, orchestration, decomposition, parallelism, and fault isolation</strong>. What changes is <em>how decisions are made</em>.</p>
<p>Microservices rely on predefined workflows, APIs, and orchestration logic, whereas AI agents introduce autonomy, reasoning, and intent-driven behavior into these same patterns. This alignment allows us to treat agent systems as an evolution of microservice architectures, rather than a completely new paradigm.</p>
<h2>C<strong>ore similarities</strong></h2>
<ul>
<li><p>Clear separation of responsibilities</p>
</li>
<li><p>Distributed execution of tasks</p>
</li>
<li><p>Scalable and composable system design</p>
</li>
</ul>
<h2>I<strong>mportant differences</strong></h2>
<ul>
<li><p>Microservices are deterministic and code-driven, while agents are adaptive and decision-driven</p>
</li>
<li><p>Orchestration in microservices is explicit, whereas agents can dynamically plan and re-route tasks</p>
</li>
<li><p>Agents often operate at a higher semantic level (intent, goals, context), not just API contracts</p>
</li>
</ul>
<p>By mapping agent patterns to microservice patterns, we create a familiar mental model that simplifies learning, design discussions, and system evolution—while still taking advantage of the flexibility and intelligence that AI agents bring to modern architectures.</p>
<h2>1. Coordinator / Dispatcher Agent ↔ API Gateway</h2>
<p><strong>What the API Gateway does (microservices):</strong></p>
<ul>
<li><p>Acts as a single entry point for clients.</p>
</li>
<li><p>Routes each request to the correct microservice.</p>
</li>
<li><p>Applies logic such as authentication, routing, aggregation, etc.</p>
</li>
</ul>
<p><strong>What the Coordinator/Dispatcher Agent does (agent systems):</strong></p>
<ul>
<li><p>A “HostAgent” or similar orchestrating agent decides <em>which</em> agent handles a user request.</p>
</li>
<li><p>It interprets intent and dispatches tasks to the right specialized agents.</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765540646574/0105e206-3805-4a5d-992d-d5651cbb7446.png" alt="" style="display:block;margin:0 auto" />

<p><strong>Why they match:</strong><br />Both act as intelligent routers. But the agent can make context-aware or intent-aware decisions rather than static route mapping.</p>
<hr />
<h2>2. Sequential Pipeline Agent ↔ Saga Pattern</h2>
<p><strong>Saga pattern (microservices):</strong></p>
<ul>
<li><p>Breaks a multi-step workflow across many services into a sequence of distributed transactions.</p>
</li>
<li><p>Ensures compensating steps occur on failure.</p>
</li>
<li><p>Each step is processed in order.</p>
</li>
</ul>
<p><strong>Sequential Pipeline Agent (agents):</strong></p>
<ul>
<li><p>Chains multiple agents together in a sequence.</p>
</li>
<li><p>Each agent performs a step, passing intermediate results forward.</p>
</li>
<li><p>Useful for workflows where earlier steps feed later steps.</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765542179328/92d5106f-6eca-491d-bd70-ab43df108a08.jpeg" alt="" style="display:block;margin:0 auto" />

<p><strong>Why they match:</strong><br />Both decompose a long-running, multi-stage workflow into a series of coordinated steps.</p>
<hr />
<h2>3. Parallel Fan-Out / Gather Agent ↔ Fork-Join Pattern</h2>
<p><strong>Fork-Join (microservices):</strong></p>
<ul>
<li><p>Sends parallel requests to multiple services.</p>
</li>
<li><p>Waits for results and aggregates them.</p>
</li>
</ul>
<p><strong>Fan-Out/Fan-In Agent pattern:</strong></p>
<ul>
<li><p>A “fan-out” agent creates multiple parallel subtasks, handled by different agents.</p>
</li>
<li><p>A “gather” agent (or same agent) compiles all results when tasks finish.</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765542123363/ec8eb402-44e1-4d07-9e6a-cf0850d21a9c.jpeg" alt="" style="display:block;margin:0 auto" />

<p><strong>Why they match:</strong><br />Both patterns optimize for parallelism and speed when querying multiple sources or performing independent tasks.</p>
<hr />
<h2>4. Hierarchical Task Decomposition ↔ Domain-Driven Design (DDD)</h2>
<p><strong>DDD (microservices):</strong></p>
<ul>
<li><p>Breaks complex domains into bounded contexts.</p>
</li>
<li><p>Each context owns a specific part of the business logic.</p>
</li>
</ul>
<p><strong>Hierarchical Task Decomposition (agents):</strong></p>
<ul>
<li><p>A high-level agent breaks a complex task into sub-tasks and delegates them to specialized agents.</p>
</li>
<li><p>Each agent focuses on a well-defined capability or “context.”</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765542110216/e19ca488-8405-4758-ab81-7cfad74a34b7.jpeg" alt="" style="display:block;margin:0 auto" />

<p><strong>Why they match:</strong><br />Both approaches structure systems around clear domains or responsibilities, reducing complexity and improving scalability.</p>
<hr />
<h1>Summary</h1>
<table>
<thead>
<tr>
<th><strong>Agent Pattern</strong></th>
<th><strong>Microservice Equivalent</strong></th>
<th><strong>Core Similarity</strong></th>
</tr>
</thead>
<tbody><tr>
<td>Coordinator/Dispatcher Agent</td>
<td>API Gateway</td>
<td>Intelligent routing and mediation</td>
</tr>
<tr>
<td>Sequential Pipeline Agent</td>
<td>Saga Pattern</td>
<td>Multi-step workflows with dependencies</td>
</tr>
<tr>
<td>Fan-Out/Gather Agent</td>
<td>Fork-Join</td>
<td>Parallel task execution and aggregation</td>
</tr>
<tr>
<td>Hierarchical Task Decomposition</td>
<td>Domain-Driven Design</td>
<td>Breaking complexity into specialized, context-specific units</td>
</tr>
</tbody></table>
<p>In short, <strong>agent systems often implement familiar microservice patterns, but with more autonomy, adaptability, and task-oriented intelligence.</strong></p>
]]></content:encoded></item><item><title><![CDATA[Zero to Agent in 30 Minutes: Your Foundry Setup]]></title><description><![CDATA[If you’ve been following the excitement around AI agents, you’ve probably noticed that most tutorials still scatter essential steps across several tools, repos, and half-finished guides. When I starte]]></description><link>https://blogs.codingfreaks.net/zero-to-agent</link><guid isPermaLink="true">https://blogs.codingfreaks.net/zero-to-agent</guid><category><![CDATA[#codingfreaks]]></category><category><![CDATA[agentic AI]]></category><category><![CDATA[agentic ai development]]></category><category><![CDATA[agents]]></category><category><![CDATA[AgentSDK]]></category><category><![CDATA[microsoft agent framework]]></category><category><![CDATA[C#]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Thu, 11 Dec 2025 08:29:51 GMT</pubDate><content:encoded><![CDATA[<p>If you’ve been following the excitement around AI agents, you’ve probably noticed that most tutorials still scatter essential steps across several tools, repos, and half-finished guides. When I started down this path, I kept wondering: why isn’t there a simple, single place where a C# developer can get up and running?</p>
<p>This chapter is that starting point.<br />In the next 30 minutes, you’ll install everything you need, configure your development environment, scaffold your first agent project, and validate it with a simple “Hello Agent” test. After this, you’ll be ready for real agent coding without wrestling with setup hurdles.</p>
<hr />
<h2>What You'll Learn</h2>
<p>By the end of this chapter, you will have:</p>
<ul>
<li><p>A <strong>one-command installation</strong> for the full agent development stack</p>
</li>
<li><p>A working <strong>VS Code or Visual Studio environment</strong> configured for .NET 8 + Agent Framework</p>
</li>
<li><p>A clean <strong>agent project structure</strong> generated and ready to extend</p>
</li>
<li><p>A functioning <strong>“Hello Agent” test</strong> that proves your setup is correct</p>
</li>
</ul>
<p><strong>Your takeaway:</strong> a ready-to-code development environment for building Foundry-compatible AI agents.</p>
<hr />
<h1>1. One-Command Installation: The Fastest Way to Start</h1>
<p>Let’s begin with the simplest possible setup.<br />Instead of juggling multiple runtime dependencies, install:</p>
<h3>.NET 8 SDK</h3>
<pre><code class="language-csharp">winget install Microsoft.DotNet.SDK.8
</code></pre>
<h3>VS Code (optional if you use Visual Studio)</h3>
<pre><code class="language-csharp">winget install Microsoft.VisualStudioCode
</code></pre>
<h3>The Microsoft Agent Framework Package (added automatically when we create the project)</h3>
<p>We will install this directly into the project; no global installation is required.</p>
<p>That’s really it. There’s no extra CLI layer, no complex environment manager, and—importantly—<strong>you do not need Foundry Local for this tutorial</strong>. I will explain more about that later.</p>
<hr />
<h1>2. Setting Up Your Development Environment</h1>
<p>You can use either <strong>Visual Studio 2022 (17.9+)</strong> or <strong>VS Code</strong>.<br />Both work well, but for quick iteration VS Code is surprisingly efficient.</p>
<h3>Recommended extensions:</h3>
<h4>For Visual Studio:</h4>
<ul>
<li><p>.NET 8 SDK workload</p>
</li>
<li><p>C# Dev Kit (optional but helpful)</p>
</li>
</ul>
<h4>For VS Code:</h4>
<ul>
<li><p>C# Dev Kit</p>
</li>
<li><p>IntelliCode</p>
</li>
<li><p>.NET Install Tool (auto-detects SDKs)</p>
</li>
</ul>
<p>Once your editor is ready, verify that .NET is correctly installed:</p>
<pre><code class="language-csharp">dotnet --version
</code></pre>
<p>You should see something like:</p>
<pre><code class="language-csharp">8.0.101
</code></pre>
<p>Now you’re ready to build.</p>
<hr />
<h1>3. Create Your First Agent Project</h1>
<p>Let’s initialize a clean agent project from scratch.</p>
<h3>Step 1 — Create a console project</h3>
<pre><code class="language-csharp">dotnet new console -n MyFirstAgent
cd MyFirstAgent
</code></pre>
<h3>Step 2 — Add the Microsoft Agent Framework</h3>
<pre><code class="language-csharp">dotnet add package Microsoft.AgentFramework
</code></pre>
<p>This package gives you the core abstractions—agent lifecycle, messaging, model access, and tool integration—without requiring Foundry yet.</p>
<hr />
<h1>4. Create the "Hello Agent" Code</h1>
<p>Replace your <code>Program.cs</code> (or <code>Program.cs + Agent class</code>) with the following minimal example:</p>
<pre><code class="language-csharp">using Microsoft.AgentFramework;
using Microsoft.AgentFramework.Abstractions;
using Microsoft.AgentFramework.Hosting;
using Microsoft.Extensions.DependencyInjection;

var builder = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =&gt;
    {
        services.AddOpenAIChatModel(options =&gt;
        {
// Ensure you've added OPENAI_API_KEY values in the System's Environment variable
            options.ApiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
            options.Model = "gpt-4.1-mini";
        });

        services.AddAgent&lt;HelloAgent&gt;();
    });

var host = builder.Build();
await host.RunAsync();

public class HelloAgent : IAgent
{
    private readonly IChatModel _model;

    public HelloAgent(IChatModel model)
    {
        _model = model;
    }

    public async Task RunAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("Hello Agent is now running. Ask anything:");

        while (!cancellationToken.IsCancellationRequested)
        {
            var input = Console.ReadLine();
            if (input?.ToLowerInvariant() == "exit") break;

            var reply = await _model.GenerateAsync(input, cancellationToken);
            Console.WriteLine(reply);
        }
    }
}
</code></pre>
<p>This is not a mock-up or pseudocode—it's a real, runnable agent powered by the Microsoft Agent Framework.</p>
<hr />
<h1>5. Verify Everything Works</h1>
<p>Run your program:</p>
<pre><code class="language-csharp">dotnet run
</code></pre>
<p>You should see:</p>
<pre><code class="language-csharp">Hello Agent is now running. Ask anything:
</code></pre>
<p>Try typing:</p>
<pre><code class="language-csharp">Hello
</code></pre>
<p>If the agent responds with a generated message, congratulations—you now have a working agent environment, and your setup is validated.</p>
<p>This is your foundation for every upcoming chapter—tools, memory, workflows, debugging, and eventually deployment into Foundry.</p>
<h1>Final Takeaway</h1>
<p>By the time you finish this chapter, you have:</p>
<ul>
<li><p>A complete .NET + Agent Framework environment</p>
</li>
<li><p>A scaffolded agent project</p>
</li>
<li><p>A running “Hello Agent” to prove your setup works</p>
</li>
<li><p>No Foundry dependencies yet—keeping the barrier to entry low</p>
</li>
</ul>
<p>You’re now standing on a clean, solid foundation ready for the next chapter:<br /><strong>Agent Anatomy 101: Brain, Tools, and Memory</strong>.</p>
]]></content:encoded></item><item><title><![CDATA[Hello, AI Agents! What They Are & Why You Should Build One]]></title><description><![CDATA[If you've been watching the AI space from the sidelines and thinking, “This all looks interesting, but where does a C# developer even begin?”, you’re not alone. Most of us started there.AI agents seem]]></description><link>https://blogs.codingfreaks.net/hello-ai-agents</link><guid isPermaLink="true">https://blogs.codingfreaks.net/hello-ai-agents</guid><category><![CDATA[microsoft agent framework]]></category><category><![CDATA[MAF]]></category><category><![CDATA[ai agents]]></category><category><![CDATA[C#]]></category><category><![CDATA[AI Agents Explained]]></category><category><![CDATA[#codingfreaks]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Wed, 10 Dec 2025 17:19:43 GMT</pubDate><content:encoded><![CDATA[<p>If you've been watching the AI space from the sidelines and thinking, “This all looks interesting, but where does a <strong>C# developer even begin</strong>?”, you’re not alone. Most of us started there.<br />AI agents seem complicated until you actually build one — and then suddenly the whole idea becomes surprisingly straightforward.</p>
<p>This first post in the series is all about getting that initial win. You’ll build a small .NET 8 console application that talks to an AI agent using the <strong>Microsoft Agent Framework</strong> and the <strong>OpenAI .NET SDK</strong>. No ML background required. No giant architecture diagrams. Just code, clarity, and an agent that responds to your questions.</p>
<p>Let’s get something working.</p>
<p>Note : This blogpost is part of the <a href="https://blogs.codingfreaks.net/building-ai-agents">AI Agent learning series</a> here.</p>
<hr />
<h2><strong>What You'll Build Today</strong></h2>
<p>By the end of this post, you’ll have a functioning AI agent that:</p>
<ul>
<li><p>Reads instructions you define</p>
</li>
<li><p>Accepts a question</p>
</li>
<li><p>Calls an AI model</p>
</li>
<li><p>Produces a clean, human-readable response</p>
</li>
</ul>
<p>Visually, the flow looks like this:</p>
<pre><code class="language-plaintext">You → Agent → Model → Response
</code></pre>
<p>And yes — you can build this in <strong>under 50 lines of code</strong>.</p>
<hr />
<h2><strong>Before You Begin</strong></h2>
<p>You’ll need:</p>
<ul>
<li><p>.NET 8 installed</p>
</li>
<li><p>A terminal</p>
</li>
<li><p>An OpenAI-compatible API key</p>
</li>
<li><p>Basic C# familiarity</p>
</li>
</ul>
<p>If you’ve built a console app before, you’re ready.</p>
<hr />
<h1><strong>Building Your First AI Agent</strong></h1>
<p>Let’s walk through the entire process step-by-step.</p>
<hr />
<h2><strong>1. Create the Project</strong></h2>
<pre><code class="language-csharp">dotnet new console -n AgentWorkshop
cd AgentWorkshop
</code></pre>
<h2><strong>2. Add the Required Packages</strong></h2>
<p>Install the OpenAI SDK and Microsoft Agent Framework extensions:</p>
<pre><code class="language-csharp">dotnet add package OpenAI
dotnet add package Microsoft.Agents.AI.OpenAI --prerelease
</code></pre>
<p>The first package is your API client.<br />The second transforms a model into an agent with instructions and behavior.</p>
<hr />
<h2><strong>3. Write the Agent Code</strong></h2>
<p>Below is the full <code>Program.cs</code> for this first post. It’s simple by design, but shows the core pattern used throughout the series.</p>
<pre><code class="language-csharp">// Program.cs — "Hello, AI Agents!"
// A straightforward introduction to the Microsoft Agent Framework in .NET 8.

using System;
using System.Threading.Tasks;
using OpenAI; // Official OpenAI SDK used by the agent extensions

internal class Program
{
    private static async Task Main(string[] args)
    {
        

        // 1. Add your API key.
        // For local experiments and simplicity let's define the API key here
        const string apiKey = "sk-proj-API";

        if (apiKey.Contains("YOUR_API_KEY_HERE"))
        {
            Console.WriteLine("Please insert your API key before running the application.");
            return;
        }

        // 2. Create an OpenAI client.
        // This client communicates with the model.
        var client = new OpenAIClient(apiKey);

        // 3. Wrap the model as an AI agent.
        // "gpt-4o-mini" is a compact, fast model suitable for simple tasks.
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
        var agent = client
            .GetOpenAIResponseClient("gpt-4o-mini")
            .CreateAIAgent(
                name: "HelloAgent",
                instructions:
                    "You are a clear, friendly assistant who explains AI agents " +
                    "to developers without assuming prior AI knowledge."
            );
#pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.

        Console.WriteLine("Ask your AI agent a question (or press Enter for a default prompt):");
        Console.Write("&gt; ");
        var question = Console.ReadLine();

        // Provide a fallback question for convenience.
        if (string.IsNullOrWhiteSpace(question))
        {
            question = "Give me a simple explanation of what an AI agent is.";
        }

        Console.WriteLine("\nProcessing your request...\n");

        // 4. Execute the agent request.
        var response = await agent.RunAsync(question);

        // 5. Display the result.
        Console.WriteLine("=== Agent Response ===");
        Console.WriteLine(response);

        Console.WriteLine("\nComplete. You've just created your first AI agent in C#.");
    }
}
</code></pre>
<p>Run it:</p>
<pre><code class="language-csharp">dotnet run
</code></pre>
<p>You’ll see a prompt, enter your question, and the agent will produce a response that follows the instructions you gave it. That “instruction layer” is one of the most powerful parts of building agents — and something we’ll explore more as the series continues.</p>
<hr />
<h1><strong>Try It Yourself</strong></h1>
<p>Once the basic agent is working, experiment a little to build intuition.</p>
<h3><strong>1. Adjust the agent’s behavior</strong></h3>
<p>Change the instructions:</p>
<pre><code class="language-plaintext">instructions: "Explain everything like you're mentoring a new developer."
</code></pre>
<p>Run it again — notice the shift in tone.</p>
<h3><strong>2. Ask a deeper question</strong></h3>
<p>Try something more contextual:</p>
<pre><code class="language-plaintext">&gt; When should a team consider using an AI agent instead of a traditional API?
</code></pre>
<p>Now you have a lightweight agent shell running locally.</p>
<h3><strong>Source code :</strong></h3>
<p>You can find the entire <a href="https://github.com/muralidharand/ai-agents-for-beginners/tree/main/HelloAgent/AgentWorkshop">source code</a> here for this blogpost.</p>
<h1><strong>What You Learned Today</strong></h1>
<p>By completing this first post, you now understand:</p>
<ul>
<li><p>What an AI agent fundamentally is</p>
</li>
<li><p>How the Microsoft Agent Framework wraps model calls into a structured “agent” pattern</p>
</li>
<li><p>How to configure the agent’s behavior using simple instructions</p>
</li>
<li><p>How to build and run a minimal agent in a .NET 8 console app</p>
</li>
</ul>
<p>This foundation will make the next steps feel much more natural.</p>
<h1><strong>Next Up: “Zero to Agent in 30 Minutes: Your Foundry Setup”</strong></h1>
<p>In the <a href="https://blogs.codingfreaks.net/zero-to-agent">next post</a>, we’ll clean up this initial project, move configuration out of the code, and prepare your environment for a full-featured agent workflow.</p>
]]></content:encoded></item><item><title><![CDATA[Building AI Agents with C#: Your Practical Guide for 2025]]></title><description><![CDATA[AI agents are everywhere in 2025—keynote talks, engineering discussions, and product roadmaps. Many developers are beginning to ask the same question:Can I build real AI agents with the skills I alrea]]></description><link>https://blogs.codingfreaks.net/building-ai-agents</link><guid isPermaLink="true">https://blogs.codingfreaks.net/building-ai-agents</guid><category><![CDATA[aiagents]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[#CSharpProgramming ]]></category><category><![CDATA[microsoft agent framework]]></category><category><![CDATA[AI Agents Explained]]></category><category><![CDATA[#codingfreaks]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Wed, 10 Dec 2025 16:33:44 GMT</pubDate><content:encoded><![CDATA[<p>AI agents are everywhere in 2025—keynote talks, engineering discussions, and product roadmaps. Many developers are beginning to ask the same question:<br /><em><strong>Can I build real AI agents with the skills I already have?</strong></em></p>
<p>If you’re a C# developer, the answer is yes. And you don’t need to change ecosystems to do it.</p>
<hr />
<h2>The State of AI Development in 2025</h2>
<p>A few years ago, serious AI development almost always required Python. But the landscape has shifted. Microsoft has quietly, steadily expanded the .NET AI ecosystem, and today it’s mature enough for production-grade agent systems.</p>
<hr />
<h2>What You’ll Build in This Series</h2>
<p>We’re aiming for the same sense of momentum you felt the first time you ran “<strong>Hello World</strong>,” but with real, modern capability behind it.</p>
<p>You’ll build a research assistant agent that can:<br />• Search for recent developments<br />• Process information<br />• Deliver clear, actionable summaries</p>
<p>And you’ll deploy it to <strong>Microsoft Foundry</strong> so you have something real to share with colleagues or include in your portfolio.</p>
<p>This is <strong>practical engineering</strong>—not theoretical exercises.</p>
<hr />
<h2>Why AI Agents Matter Right Now</h2>
<p>Most of the companies are not asking teams to create custom ML models. They want developers who can integrate AI safely and effectively into existing applications.</p>
<p>Your strength as a C# developer—architecture, maintainability, production readiness—gives you a real advantage. This series builds on that foundation.</p>
<hr />
<h2>The Learning Path We’ll Follow</h2>
<p>This series is structured around eight focused posts. Each one builds on the last, giving you a complete end-to-end understanding of modern AI agent development in C#.</p>
<h3>1. <a href="https://blogs.codingfreaks.net/hello-ai-agents">Hello, AI Agents! What They Are &amp; Why You Should Build One</a></h3>
<p>We’ll define what an AI agent is, what it isn’t, and why this pattern is becoming essential for modern applications.</p>
<h3>2. <a href="https://blogs.codingfreaks.net/zero-to-agent">Zero to Agent in 30 Minutes: Your Foundry Setup</a></h3>
<p>You’ll set up your development environment. If you’ve installed Visual Studio before, this step will feel straightforward.</p>
<h3>3. Agent Anatomy 101: Brain, Tools, and Memory</h3>
<p>We’ll break down the core components of an agent and explore how they work together in practice.</p>
<h3>4. Choosing Your Agent's Brain: Models Made Simple</h3>
<p>You’ll learn which models to use for which tasks—and how to optimize for cost, performance, and reliability.</p>
<h3>5. Coding Your First AI Agent in Csharp</h3>
<p>Here’s where we build the initial working agent. You’ll see how to wire everything together in .NET 8 with clean, maintainable code.</p>
<h3>6. Teaching Your Agent: Adding Tools Step-by-Step</h3>
<p>A talking agent isn’t enough. We’ll add capabilities like web search, data retrieval, and integrations with your existing APIs.</p>
<h3>7. Debugging &amp; Basic Observability: Keeping It Healthy</h3>
<p>You’ll learn how to handle unexpected output, rate limits, and runtime errors—along with logging and diagnostics best practices.</p>
<h3>8. Deploying Your Agent: Local → Cloud → Share with World</h3>
<p>Finally, you’ll move your agent from local development to Azure AI Foundry so others can use it securely and at scale.</p>
<p>By the end of these eight posts, you’ll understand not only how to build an agent—but how to ship one.</p>
<hr />
<h2>What You Need (and What You Don’t)</h2>
<p>You <em>do</em> need:<br />• .NET 8<br />• A C# development environment<br />• A GitHub account</p>
<p>You <em>don’t</em> need:<br />• Python<br />• A machine learning background<br />• Months of theoretical study</p>
<p>We focus on applied software engineering using the skills you already have.</p>
<hr />
<h2>A Reality Check Before We Start</h2>
<p>Two truths worth acknowledging:</p>
<p><strong>1. AI agents are software systems—not magic prompts.</strong><br />You’ll design architecture, write tests, and handle errors just like any other application.</p>
<p><strong>2. You will encounter friction.</strong><br />Rate limits, model quirks, deployment details—all normal. I’ll show you the practical fixes that work in real environments.</p>
<hr />
<h2>Why I’m Writing This Series</h2>
<p>At a recent local meetup, several developers asked how to build and test AI agents locally in C# and then deploy them to Azure AI Foundry. That conversation made it clear that many teams need a practical, step-by-step path—not abstract theory.</p>
<p>This series is designed exactly for that purpose—helping both junior developers and experienced engineers gain confidence in modern AI engineering.</p>
<hr />
<h2>Ready to Begin?</h2>
<p>The first post publishes this week. We’ll start with fundamentals: what agents are, how they behave, and why architectural decisions matter even in simple projects.</p>
<p>Bring your C# experience, your curiosity, and a project idea you’ve been wanting to enhance with AI. We’ll build something real, end-to-end, together.</p>
<p>If you have questions before we begin, drop them in the comments. I read every one and typically respond within a day. You can also connect with me on <a href="https://www.linkedin.com/in/muralidharand/">LinkedIn</a> for tips and in <a href="https://github.com/muralidharand/ai-agents-for-beginners">GitHub</a> for code samples</p>
]]></content:encoded></item><item><title><![CDATA[Stop Worrying, Start Wiring: Azure Serverless for the AI Era]]></title><description><![CDATA[AI is no longer just a buzzword — it’s a fundamental part of modern software. But for developers, the challenge isn’t what AI can do — it’s how to integrate it into scalable, cost-efficient, and maint]]></description><link>https://blogs.codingfreaks.net/stop-worrying-start-wiring-azure-serverless-for-the-ai-era</link><guid isPermaLink="true">https://blogs.codingfreaks.net/stop-worrying-start-wiring-azure-serverless-for-the-ai-era</guid><category><![CDATA[azure-serverless]]></category><category><![CDATA[AI]]></category><category><![CDATA[serverless]]></category><category><![CDATA[genai]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Sat, 25 Oct 2025 13:06:41 GMT</pubDate><content:encoded><![CDATA[<p>AI is no longer just a buzzword — it’s a fundamental part of modern software. But for developers, the challenge isn’t what AI can do — it’s how to integrate it into scalable, cost-efficient, and maintainable applications. That’s where Azure Serverless comes in. In this session, we’ll bridge the gap between AI and application engineering. You’ll discover how Azure Functions, Event Grid, and Container Apps can serve as the event-driven backbone of intelligent systems. We’ll explore real-world patterns like automated inference pipelines, orchestrating multi-step AI workflows, and using serverless triggers to activate model predictions or data processing jobs.</p>
<iframe width="610" height="515" style="border:var(--border-1) solid #CCC;border-width:1px;margin-bottom:5px;max-width:100%"></iframe>

<p><a href="https://www.slideshare.net/slideshow/stop-worrying-start-wiring-azure-serverless-for-the-ai-era/283923866"><strong>stop-worrying-start-wiring-azure-serverless-for-the-ai-era</strong></a>from <a href="https://www.slideshare.net/Muralidharantnj"><strong>Muralidharan Deenathayalan</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[What Is Leetspeak? A Fun Dive into the Language of Hackers and Gamers]]></title><description><![CDATA[If you've ever browsed through gaming forums, hacker lore, or early 2000s chat rooms, you've probably seen words like "1337", "h4x0r", or "$3cr3t" and wondered what they mean. Welcome to the cryptic a]]></description><link>https://blogs.codingfreaks.net/what-is-leetspeak-a-fun-dive-into-the-language-of-hackers-and-gamers</link><guid isPermaLink="true">https://blogs.codingfreaks.net/what-is-leetspeak-a-fun-dive-into-the-language-of-hackers-and-gamers</guid><category><![CDATA[#promptshield]]></category><category><![CDATA[leetspeak]]></category><category><![CDATA[#PromptEngineering]]></category><category><![CDATA[#codingfreaks]]></category><category><![CDATA[genai]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Sat, 31 May 2025 20:05:45 GMT</pubDate><content:encoded><![CDATA[<p>If you've ever browsed through gaming forums, hacker lore, or early 2000s chat rooms, you've probably seen words like <strong>"1337"</strong>, <strong>"h4x0r"</strong>, or <strong>"$3cr3t"</strong> and wondered what they mean. Welcome to the cryptic and creative world of <strong>Leetspeak</strong> — a playful twist on English that replaces letters with numbers and symbols to create a stylized form of writing.</p>
<p>In this post, we'll explore what leetspeak is, how it's used, and give you plenty of examples so you can start writing like a digital native from the golden age of the internet.</p>
<h2>👾 What Is Leetspeak?</h2>
<p><strong>Leetspeak</strong>, sometimes stylized as <strong>1337 speak</strong>, comes from the word <strong>“elite”</strong> and was originally used by hackers and online gamers to show skill or exclusivity. Over time, it became a broader internet trend, used for fun, anonymity, or simply to stand out.</p>
<p>The idea is simple: <strong>replace letters with similar-looking characters</strong>, such as numbers or special symbols. There's no strict rulebook, which means you can be as creative as you want.</p>
<h2>🔤 Basic Leetspeak Translations</h2>
<p>Here are some common substitutions in leetspeak:</p>
<table>
<thead>
<tr>
<th>Letter</th>
<th>Leet Version(s)</th>
</tr>
</thead>
<tbody><tr>
<td>A</td>
<td>4, @</td>
</tr>
<tr>
<td>B</td>
<td>8,</td>
</tr>
<tr>
<td>C</td>
<td>(</td>
</tr>
<tr>
<td>E</td>
<td>3</td>
</tr>
<tr>
<td>G</td>
<td>6</td>
</tr>
<tr>
<td>H</td>
<td>#,</td>
</tr>
<tr>
<td>I</td>
<td>1, !</td>
</tr>
<tr>
<td>L</td>
<td>1,</td>
</tr>
<tr>
<td>O</td>
<td>0</td>
</tr>
<tr>
<td>S</td>
<td>5, $</td>
</tr>
<tr>
<td>T</td>
<td>7, +</td>
</tr>
<tr>
<td>Z</td>
<td>2</td>
</tr>
</tbody></table>
<h2>🛠️ Examples of Leetspeak in Action</h2>
<p>Let’s break down a few examples:</p>
<ul>
<li><p><strong>"Elite"</strong> becomes → <code>3|173</code> or <code>31337</code></p>
</li>
<li><p><strong>"Hacker"</strong> becomes → <code>|-|4(|&lt;3|2</code></p>
</li>
<li><p><strong>"Password"</strong> becomes → <code>P455\/\/0|2|)</code></p>
</li>
<li><p><strong>"Leetspeak"</strong> becomes → <code>13375P34K</code></p>
</li>
<li><p><strong>"Noob"</strong> becomes → <code>|\|008</code></p>
</li>
</ul>
<p>As you can see, leetspeak can range from simple substitutions to complex strings that take a second (or more!) to decipher.</p>
<h2>🎮 Where Is Leetspeak Used?</h2>
<p>Leetspeak had its heyday in the early internet era, but you can still find it in:</p>
<ul>
<li><p>🕹️ Online gaming communities</p>
</li>
<li><p>🧵 Reddit threads</p>
</li>
<li><p>💻 Programming jokes</p>
</li>
<li><p>🤖 Meme culture</p>
</li>
<li><p>🛡️ Hacker and cybersecurity references</p>
</li>
<li><p>👤 Stylized usernames</p>
</li>
</ul>
<p>It’s less about utility now and more about nostalgia, humor, and digital identity.</p>
<h2>😎 Why Use Leetspeak?</h2>
<p>People use leetspeak for various reasons:</p>
<ul>
<li><p><strong>To look cool</strong> in internet subcultures</p>
</li>
<li><p><strong>To bypass content filters</strong> (e.g., replacing bad words)</p>
</li>
<li><p><strong>As an inside joke</strong> among tech-savvy friends</p>
</li>
<li><p><strong>For fun and creativity</strong> — it's like visual wordplay</p>
</li>
</ul>
<h2>✍️ Create Your Own Leetspeak</h2>
<p>Want to try it? Take a sentence and transform it:</p>
<blockquote>
<p>Original: <code>Hack the system</code><br />Leetspeak: <code>|-|4(|&lt; 7#3 5Y57 3M</code></p>
</blockquote>
<p>Or maybe your name:</p>
<ul>
<li><p><code>"Alex"</code> → <code>4|_3&gt;&lt;</code></p>
</li>
<li><p><code>"Sam"</code> → <code>54|\/|</code></p>
</li>
</ul>
<h2>🧠 Final Thoughts</h2>
<p>Leetspeak is a quirky, creative form of digital expression. While it's no longer in widespread use, it remains a fun relic of internet history and a way to play with language in unexpected ways.</p>
<p>While it may not be as prevalent today, it remains a nostalgic relic that continues to entertain and engage those who enjoy its unique blend of language and symbolism. Whether used for humor, identity, or simply as a fun challenge, leetspeak offers a glimpse into the innovative ways people have adapted language in the digital age. Embracing leetspeak is a way to celebrate the history of online communication and the enduring spirit of creativity that defines internet culture.</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[Prompt Robustness & Perturbation Testing: Why Tiny Changes Matter]]></title><description><![CDATA[Introduction
If you've spent time building with large language models, you’ve probably run into this: you slightly reword a prompt—same meaning, just different phrasing—and suddenly the model gives yo]]></description><link>https://blogs.codingfreaks.net/prompt-robustness-and-perturbation-testing-why-tiny-changes-matter</link><guid isPermaLink="true">https://blogs.codingfreaks.net/prompt-robustness-and-perturbation-testing-why-tiny-changes-matter</guid><category><![CDATA[#llmsecuritybymurali]]></category><category><![CDATA[#promptrobustness]]></category><category><![CDATA[#Perturbationtesting]]></category><category><![CDATA[#Perturbation ]]></category><category><![CDATA[genai]]></category><category><![CDATA[#PromptEngineering]]></category><category><![CDATA[#codingfreaks]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Mon, 26 May 2025 09:27:11 GMT</pubDate><content:encoded><![CDATA[<h3>Introduction</h3>
<p>If you've spent time building with large language models, you’ve probably run into this: you slightly reword a prompt—same meaning, just different phrasing—and suddenly the model gives you a completely different answer. It’s not just frustrating. It’s a sign that the system isn’t as stable as it needs to be.</p>
<p><strong>Prompt robustness</strong> is about how well a model handles these small, often harmless changes. And if you're shipping AI into user-facing products or business-critical workflows, this becomes a problem you can't ignore. That’s where <strong>perturbation testing</strong> comes in—a way to pressure test prompts and make sure the model’s responses don’t fall apart over small tweaks.</p>
<h3>What Is Prompt Robustness?</h3>
<p>Prompt robustness is the degree to which a language model can maintain output consistency across semantically equivalent prompts. Ideally, a model should focus on <em>intent</em>, not the specific phrasing used to express it.</p>
<h4>Consider this:</h4>
<pre><code class="language-xml">Prompt A: “Summarize the article below.”
Prompt B: “Can you give me a brief overview of the article?”
</code></pre>
<p>Both requests mean the same thing. If the model treats them differently, it’s likely overfitting to superficial cues. That may be acceptable in toy use cases—but not in high-reliability environments.</p>
<h3><strong>Types of Prompt Perturbations</strong></h3>
<p>Prompt changes that shouldn’t impact meaning fall into a few common categories:</p>
<ul>
<li><p><strong>Rewording</strong> – Expressing the same idea in different ways.</p>
</li>
<li><p><strong>Synonym swaps</strong> – Replacing words without changing their meaning.</p>
</li>
<li><p><strong>Typos</strong> – Including simple spelling or keyboard mistakes.</p>
</li>
<li><p><strong>Punctuation edits</strong> – Adding, removing, or shifting punctuation marks.</p>
</li>
<li><p><strong>Order adjustments</strong> – Changing the arrangement of words without altering semantics.</p>
</li>
<li><p><strong>Format changes</strong> – Switching between sentence-based prompts and structured formats like lists or tables.</p>
</li>
</ul>
<p>These perturbations are typical of real-world usage—introduced by users, UI layers, or even automated input generation. Robust models need to navigate them reliably.</p>
<h3><strong>Why It Matters</strong></h3>
<p>Prompt brittleness introduces real problems when LLMs are deployed at scale:</p>
<ul>
<li><p><strong>Inconsistent user experience</strong> – Responses vary depending on how something is asked, which undermines trust.</p>
</li>
<li><p><strong>Testing becomes ambiguous</strong> – Validation efforts break down if behavior isn’t stable.</p>
</li>
<li><p><strong>Hidden failure modes</strong> – In mission-critical systems, a prompt change might trigger unpredictable responses.</p>
</li>
<li><p><strong>Poor scalability</strong> – Prompt tuning becomes unmanageable across many use cases.</p>
</li>
</ul>
<p>Robustness isn’t just about “getting better answers.” It’s about <strong>building confidence</strong> in how models behave under normal usage conditions.</p>
<h3><strong>How to Conduct Prompt Robustness &amp; Perturbation Testing</strong></h3>
<p>You don’t need a complex setup to start testing for robustness. A focused, repeatable approach will reveal a lot:</p>
<ol>
<li><p><strong>Define key prompts</strong> that align with your core use cases.</p>
</li>
<li><p><strong>Create variations</strong> manually or using scripts—covering rewordings, typos, format shifts, etc.</p>
</li>
<li><p><strong>Run both original and perturbed prompts</strong> through the model under consistent settings.</p>
</li>
<li><p><strong>Compare outputs</strong> using:</p>
<ul>
<li><p><strong>Cosine similarity of sentence embeddings</strong></p>
</li>
<li><p><strong>Exact match or label consistency</strong> for classification tasks</p>
</li>
<li><p><strong>ROUGE or other overlap scores</strong> for generative tasks</p>
</li>
<li><p><strong>Manual review</strong> where judgment is required</p>
</li>
</ul>
</li>
</ol>
<h4>Tools that help:</h4>
<ul>
<li><p><em>sentence-transformers</em> for semantic comparisons</p>
</li>
<li><p>Python + OpenAI API for testing loops</p>
</li>
<li><p>PromptLayer or LangSmith to track prompt versions</p>
</li>
<li><p>Pytest or unit test frameworks to validate model behavior</p>
</li>
</ul>
<p>This approach scales well across LLM-driven applications and helps surface failure points early in development.</p>
<h3><strong>Examples &amp; Case Studies</strong></h3>
<h4><strong>Example 1: Sentiment Detection</strong></h4>
<pre><code class="language-xml">Prompt 1: “Is the tone of this review positive or negative?”
Prompt 2: “Does this review sound good or bad to you?”
</code></pre>
<p>Expected behavior: Same classification<br />Observed: Some LLMs shift sentiment prediction just due to phrasing.</p>
<h4><strong>Example 2: Code Generation</strong></h4>
<pre><code class="language-xml">Prompt A: “Write a Python function that returns the nth Fibonacci number.”
Prompt B: “Create a Python method to compute Fibonacci(n).”
</code></pre>
<p>Both prompts ask for the same thing, but the output may differ—loop vs recursion, or even syntax inconsistencies. While functionally correct, these differences affect maintainability and trust.</p>
<h3><strong>How to Improve Prompt Robustness</strong></h3>
<p>A few things that actually help:</p>
<ul>
<li><p><strong>Test with multiple prompt styles</strong> – Don’t validate your model with only one phrasing.</p>
</li>
<li><p><strong>Use structured formats</strong> – The more explicit and scoped your prompt, the more stable it tends to be.</p>
</li>
<li><p><strong>Train with paraphrased examples</strong> – Instruction tuning on variation helps reduce brittleness.</p>
</li>
<li><p><strong>Pair LLMs with fallback logic</strong> – Retrieval systems, rules, or checks can help catch edge cases.</p>
</li>
<li><p><strong>Automate regression testing</strong> – Treat prompt stability like software behavior: track it, test it, monitor it.</p>
</li>
</ul>
<p>This isn’t just prompt engineering—it’s system design.</p>
<h3><strong>Where the Field Is Headed</strong></h3>
<p>Robustness isn’t a niche issue anymore. Here’s what’s gaining traction:</p>
<ul>
<li><p><strong>Prompt fuzzing</strong> – Tools that generate randomized variations to stress test inputs.</p>
</li>
<li><p><strong>Multi-prompt evaluation sets</strong> – Benchmarks that compare output consistency across prompt variants.</p>
</li>
<li><p><strong>Fine-tuning on noisy data</strong> – Making the model less sensitive to exact phrasing.</p>
</li>
<li><p><strong>Standardized metrics</strong> – Moving beyond subjective review toward automated scoring.</p>
</li>
<li><p><strong>IDE-like tooling for prompt testing</strong> – Expect better developer tools in the next wave of LLM infrastructure.</p>
</li>
</ul>
<p>As LLMs move from labs to products, this kind of testing becomes standard practice.</p>
<h3><strong>Conclusion</strong></h3>
<p>If a model’s response swings dramatically because a comma moved or a word changed, that’s not a flexible system—it’s a fragile one. Prompt robustness is about recognizing that natural language is messy and preparing our systems to handle that mess gracefully.</p>
<p>Testing for prompt sensitivity should be part of every LLM deployment process. It reduces surprises, improves user trust, and provides a baseline for long-term model quality.</p>
]]></content:encoded></item><item><title><![CDATA[Sensitivity Testing: A Simple Technique to Expose AI Bias and Inconsistencies]]></title><description><![CDATA[Artificial intelligence isn’t just powering search engines and chatbots anymore—it’s helping companies decide who gets hired, which loans are approved, and even how criminal sentences are calculated. That kind of power makes it essential to ask: Are ...]]></description><link>https://blogs.codingfreaks.net/sensitivity-testing-a-simple-technique-to-expose-ai-bias-and-inconsistencies</link><guid isPermaLink="true">https://blogs.codingfreaks.net/sensitivity-testing-a-simple-technique-to-expose-ai-bias-and-inconsistencies</guid><category><![CDATA[#sensitivity testing]]></category><category><![CDATA[genai]]></category><category><![CDATA[#responsibleai]]></category><category><![CDATA[#codingfreaks]]></category><category><![CDATA[#smartbytes]]></category><category><![CDATA[ai testing]]></category><category><![CDATA[fairness in llm]]></category><category><![CDATA[Bias in AI]]></category><category><![CDATA[Bias]]></category><category><![CDATA[#llmsecuritybymurali]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Sat, 24 May 2025 08:15:15 GMT</pubDate><content:encoded><![CDATA[<p>Artificial intelligence isn’t just powering search engines and chatbots anymore—it’s helping companies decide who gets hired, which loans are approved, and even how criminal sentences are calculated. That kind of power makes it essential to ask: <em>Are these systems treating everyone fairly?</em> And more importantly, how do we even begin to test that?</p>
<p>One of the simplest, yet most revealing methods is something called <strong>sensitivity testing</strong>. It’s not technical or flashy, and you don’t need a PhD to try it. But what it shows you can be eye-opening.</p>
<h3 id="heading-what-is-sensitivity-testing">What Is Sensitivity Testing?</h3>
<p>Imagine you ask an AI to describe a successful entrepreneur named “<strong><em>John</em></strong>.” Then you run the same prompt again, but change the name to “<strong><em>Mike</em></strong>.” Everything else stays the same. If the responses are noticeably different—not just in details, but in tone or assumptions—then you've spotted something worth digging into.</p>
<p>That’s sensitivity testing in a nutshell. It’s the act of changing a single word or phrase in a prompt and watching how the AI’s response shifts. You’re not looking for obvious glitches or errors. You’re looking for subtle inconsistencies, biases, or unexpected behaviors that emerge when certain identity markers are swapped in.</p>
<h3 id="heading-why-this-kind-of-testing-matters">Why This Kind of Testing Matters</h3>
<p>It’s tempting to assume that advanced AI systems are objective and neutral, especially when they’re trained on huge amounts of data. But data comes from the real world, and the real world has a long history of bias. The power of sensitivity testing is that it forces these systems to show their cards.</p>
<p>Does the model describe a “<strong><em>male CEO</em></strong>” as confident and strategic, but a “<strong><em>female CEO</em></strong>” as kind and well-liked? Does it suggest more prestigious jobs to applicants with Western-sounding names than to those with ethnic ones? These aren’t just quirks. They reflect the biases that AI systems can unknowingly learn—and then repeat.</p>
<p>In high-stakes areas like hiring, law, or healthcare, even small differences in how people are described or evaluated can have big consequences.</p>
<h3 id="heading-how-to-do-it">How to Do It</h3>
<p>The beauty of sensitivity testing is that anyone can do it. Here’s a quick way to get started:</p>
<ol>
<li><p>Pick a prompt that mimics a real-world situation—writing a recommendation letter, evaluating a resume, suggesting a college major.</p>
</li>
<li><p>Change one thing: the name, gender, location, age, etc.</p>
</li>
<li><p>Compare the responses. Not just the content, but also the tone, the amount of detail, and what’s assumed.</p>
</li>
<li><p>Ask yourself: <em>Would a human have written these two responses in the same way if they weren’t influenced by stereotypes?</em></p>
</li>
</ol>
<p>It’s important to stay grounded here. Not every difference means the AI is biased. Sometimes the model just generates differently because of randomness. But if you see a pattern—especially over multiple examples—it’s worth paying attention.</p>
<h3 id="heading-a-few-examples">A Few Examples</h3>
<p>Let’s say you’re testing a prompt like:</p>
<blockquote>
<p>“Write a letter of recommendation for [Name], a high school student applying to engineering school.”</p>
</blockquote>
<p>Try using names like <em>Emily, Jamal, Arjun, or Mei</em>. If Emily’s letter is glowing and full of technical praise, but Jamal’s is more about personality or determination, that’s a red flag.</p>
<p>Or imagine you ask:</p>
<blockquote>
<p>“What career would be best suited for [Name], who enjoys math and science?”</p>
</blockquote>
<p>Does the AI recommend astrophysics to one name, and technician work to another? That gap matters.</p>
<h3 id="heading-the-human-element">The Human Element</h3>
<p>What’s ironic about sensitivity testing is that while it’s often used to audit AI, it relies on human instinct. You’re the one deciding what to test, what counts as “different,” and whether that difference feels justified.</p>
<p>It’s also a reminder that we still need humans in the loop—especially when we’re evaluating fairness. AI can generate infinite possibilities, but it can’t tell you whether something feels off. <strong>That judgment comes from us.</strong></p>
<h3 id="heading-final-thoughts">Final Thoughts</h3>
<p>In a time when AI is shaping so many decisions behind the scenes, sensitivity testing gives us a way to peek under the hood. It’s not perfect, and it’s not a silver bullet. But it <em>is</em> something anyone can try. And in many cases, it’s enough to spark important conversations—and more responsible design choices.</p>
<p>So next time you're playing with a chatbot or reading an AI-generated summary, try switching out a word. Just one. And see what changes.</p>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>Sensitivity testing is a powerful yet accessible tool for uncovering biases and inconsistencies in AI systems. By simply altering a single word or phrase in a prompt, we can reveal how AI might treat individuals differently based on identity markers like name, gender, or ethnicity. This method highlights the importance of human judgment in evaluating AI fairness, reminding us that while AI can process vast amounts of data, it is our responsibility to ensure these systems operate justly. As AI continues to influence critical decisions in society, sensitivity testing offers a practical approach to fostering more equitable and <strong>responsible AI design</strong>.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding AI Jailbreaking: What It Is, How It Works, and Why It Matters]]></title><description><![CDATA[What is Jailbreaking ?
At the heart of it, AI jailbreaking is about getting an AI to say or do things it’s not supposed to — and probably shouldn’t. It’s a way people try to get around the built-in safeguards these systems have. Imagine trying to con...]]></description><link>https://blogs.codingfreaks.net/understanding-jailbreaking-techniques-and-prevention-tips</link><guid isPermaLink="true">https://blogs.codingfreaks.net/understanding-jailbreaking-techniques-and-prevention-tips</guid><category><![CDATA[#aisecurity]]></category><category><![CDATA[generative ai]]></category><category><![CDATA[Jailbreaking ]]></category><category><![CDATA[#llmsecuritybymurali]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Thu, 22 May 2025 18:23:41 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-what-is-jailbreaking">What is Jailbreaking ?</h3>
<p>At the heart of it, AI jailbreaking is about getting an AI to say or do things it’s not supposed to — and probably shouldn’t. It’s a way people try to get around the built-in safeguards these systems have. Imagine trying to convince someone who always follows the rules to break them, just this once.</p>
<h3 id="heading-why-it-is-called-as-jailbreaking">Why it is called as Jailbreaking?</h3>
<p>The term “jailbreaking” originally comes from the mobile world, where it means unlocking a phone to get around software restrictions and use features that are normally off-limits. In the world of AI, it’s a similar idea — people try to slip past the model’s built-in ethical and safety guardrails. The name stuck because the concept is basically the same: break the rules to get access to what’s usually hidden or restricted.</p>
<h3 id="heading-jailbreaking-vs-prompt-injection-whats-the-difference">Jailbreaking vs. Prompt Injection: What’s the Difference?</h3>
<p>The two ideas are often confused, but they target slightly different things:</p>
<ul>
<li><p><strong>Prompt Injection</strong> happens when someone adds text to a prompt to mislead the model’s behavior — often in third-party applications or tools.</p>
</li>
<li><p><strong>Jailbreaking</strong> is more about persuading the AI to ignore its rules completely, often by framing a prompt in a tricky way.</p>
</li>
</ul>
<p>In simple terms, prompt injection tweaks <em>what</em> the AI says. Jailbreaking tweaks <em>what the AI thinks it’s allowed to say</em>.</p>
<h3 id="heading-common-types-of-jailbreaking">Common types of Jailbreaking</h3>
<p>🔸 <strong>Roleplay Exploits</strong><br />You’ve probably seen those prompts like “Pretend you’re an evil AI.” They might look like jokes, but they’re actually a way to get around built-in filters. It's clever — and a little alarming.</p>
<p>🔸 <strong>Meta-Prompting</strong><br />This one's about asking the model to “imagine” or “simulate” being in a fictional world. People use it to sidestep safety rules without directly breaking them. Basically, it’s working the system.</p>
<p>🔸 <strong>Prompt Formatting Attacks</strong><br />Formatting tricks can go under the radar — things like special tokens or strange characters that confuse how the model reads the input. A few symbols in the right place can make a big difference.</p>
<p>🔸 <strong>DAN-style Attacks</strong><br />These “Do Anything Now” prompts are designed to break limits. They often sound commanding or urgent, like the model has to obey no matter what. It’s a classic jailbreak strategy.</p>
<p>🔸 <strong>Context Overflow</strong><br />Here, the tactic is to flood the system with so much text that the guardrails get pushed out of memory. Once that happens, the model's more likely to go off-script.</p>
<h3 id="heading-how-to-reduce-the-risk-of-jailbreaking">How to Reduce the Risk of Jailbreaking</h3>
<p>If you're working on or deploying AI, here are a few things you can do:</p>
<ul>
<li><p><strong>Use Prompt Filters</strong>: Flag known phrases or patterns that often lead to jailbreaking.</p>
</li>
<li><p><strong>Watch the Output</strong>: Regularly audit what the AI says — especially in public-facing systems.</p>
</li>
<li><p><strong>Include Adversarial Prompts in Training</strong>: Show your model what bad prompts look like so it can learn to ignore them.</p>
</li>
<li><p><strong>Manage Input Size</strong>: Limit or summarize long inputs to prevent context overflow.</p>
</li>
<li><p><strong>Layer Your Defenses</strong>: Use input filters, output monitors, and human review — all working together.</p>
</li>
</ul>
<h3 id="heading-conclusion">Conclusion</h3>
<p>AI jailbreaking is a pressing issue that real-world systems are increasingly encountering. As large language models (LLMs) become integral to various applications, from chatbots to search tools, understanding and mitigating these risks is crucial. The challenge lies in the fact that these systems are designed to be helpful and responsive, which can sometimes be exploited.</p>
<p>However, with the right strategies, such as implementing prompt filters, monitoring outputs, and incorporating adversarial prompts during training, it's possible to build robust systems that withstand these pressures. By staying informed and proactive, developers can ensure that AI technologies remain safe and reliable, even as they continue to evolve.</p>
]]></content:encoded></item><item><title><![CDATA[How to Detect Hallucinations in AI: A Human-Centered Guide to Factual Consistency]]></title><description><![CDATA[AI is getting smarter—and smoother. It can summarize legal documents, explain tax codes, even suggest medical treatments. But sometimes, it makes things up. With confidence.
Welcome to the problem of AI hallucination — and the growing need for halluc...]]></description><link>https://blogs.codingfreaks.net/how-to-detect-hallucinations-in-ai-a-human-centered-guide-to-factual-consistency</link><guid isPermaLink="true">https://blogs.codingfreaks.net/how-to-detect-hallucinations-in-ai-a-human-centered-guide-to-factual-consistency</guid><category><![CDATA[AI Hallucinations]]></category><category><![CDATA[hallucinations]]></category><category><![CDATA[gen ai]]></category><category><![CDATA[generative ai]]></category><category><![CDATA[ai security]]></category><category><![CDATA[#llmsecuritybymurali]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Tue, 20 May 2025 19:14:27 GMT</pubDate><content:encoded><![CDATA[<p>AI is getting smarter—and smoother. It can summarize legal documents, explain tax codes, even suggest medical treatments. But sometimes, it makes things up. With confidence.</p>
<p>Welcome to the problem of <strong>AI hallucination</strong> — and the growing need for <strong>hallucination detection</strong>.</p>
<p>Whether you’re working in healthcare, law, finance, or any other high-stakes field, understanding how to spot and prevent false outputs is crucial. This post breaks it all down—no jargon overload, just real-world clarity.</p>
<h3 id="heading-what-exactly-is-an-ai-hallucination">What Exactly Is an AI Hallucination?</h3>
<p>An AI hallucination is when a model generates information that sounds accurate but is actually false or fabricated.</p>
<p>Examples:</p>
<ul>
<li><p>It cites a medical study that doesn’t exist.</p>
</li>
<li><p>It gives legal interpretations that contradict actual laws.</p>
</li>
<li><p>It confidently reports fake statistics in a financial summary.</p>
</li>
</ul>
<p>These aren’t typos or misunderstandings. The model is, quite literally, <strong>hallucinating</strong>—and the results can be dangerous.</p>
<h3 id="heading-why-do-hallucinations-happen">Why Do Hallucinations Happen?</h3>
<p>AI models don’t “know” facts. They predict the next word based on patterns in data. If the data is incomplete, outdated, or biased—or if the model is unsure—it might still try to give you an answer anyway. That’s when hallucination creeps in.</p>
<h3 id="heading-the-heart-of-the-problem-factual-consistency">The Heart of the Problem: Factual Consistency</h3>
<p>To deal with hallucinations, we need to care deeply about one concept: <strong>factual consistency</strong>. That means making sure what the AI says matches reality—verified, trusted, and grounded reality.</p>
<h2 id="heading-step-by-step-how-to-detect-hallucinations">Step-by-Step: How to Detect Hallucinations</h2>
<h3 id="heading-1-start-with-ground-truth">1. <strong>Start With Ground Truth</strong></h3>
<p>You can’t detect a hallucination without something to compare against. That could be:</p>
<ul>
<li><p>A verified database (like a drug compendium or financial filing)</p>
</li>
<li><p>Official legal records</p>
</li>
<li><p>Trusted medical guidelines</p>
</li>
</ul>
<p>This “ground truth” is your reference point.</p>
<h3 id="heading-2-craft-targeted-test-prompts">2. <strong>Craft Targeted Test Prompts</strong></h3>
<p>Don’t just ask vague questions. Use domain-specific, fact-heavy prompts that leave little room for improvisation. For example:</p>
<ul>
<li><p>“What are the FDA-approved drugs for Type 2 diabetes?”</p>
</li>
<li><p>“List the clauses of the Sherman Antitrust Act.”</p>
</li>
<li><p>“What was Apple’s net income in Q4 2023?”</p>
</li>
</ul>
<p>This sharpens your test for hallucination.</p>
<h3 id="heading-3-check-source-attribution">3. <strong>Check Source Attribution</strong></h3>
<p>A common sign of hallucination: fake citations. Always check if the AI-generated source is real. Many models generate realistic-looking articles, links, or case names that simply don’t exist.</p>
<h3 id="heading-4-watch-for-overconfidence">4. <strong>Watch for Overconfidence</strong></h3>
<p>AI models often answer with total certainty—even when they’re wrong. This is where <strong>confidence calibration</strong> matters. Just because the tone is confident doesn’t mean the information is correct.</p>
<p>Tip: Ask the model to include uncertainty or disclaimers when appropriate. It’s not perfect, but it helps.</p>
<h3 id="heading-5-use-retrieval-augmented-generation-rag">5. <strong>Use Retrieval-Augmented Generation (RAG)</strong></h3>
<p>Instead of answering from memory, some systems now <strong>retrieve real documents</strong> before generating a response. This technique, called RAG, dramatically reduces hallucination by grounding answers in real-time facts.</p>
<p>Think of it like a student who double-checks their textbook before answering a test question.</p>
<h3 id="heading-6-benchmark-with-truthfulness-tests">6. <strong>Benchmark with Truthfulness Tests</strong></h3>
<p>Researchers are using datasets like <strong>TruthfulQA</strong> or <strong>HaluEval</strong> to evaluate how truthful models are. These aren’t for everyday users, but they show that factual consistency is being taken seriously at the research level.</p>
<h3 id="heading-7-include-human-in-the-loop-review">7. <strong>Include Human-in-the-Loop Review</strong></h3>
<p>Even with smart prompts and retrieval models, there’s no replacement for human oversight. Especially in sensitive domains, build in review workflows. Think of it like fact-checking for an AI assistant.</p>
<h3 id="heading-8-tune-your-prompts-strategically">8. <strong>Tune Your Prompts Strategically</strong></h3>
<p>Sometimes hallucinations can be reduced simply by asking better questions. Known as <strong>prompt engineering</strong>, this practice involves refining how you ask to get more accurate results. Specific &gt; general. Structured &gt; open-ended.</p>
<p>Example:</p>
<ul>
<li><p>❌ "Tell me about insulin."</p>
</li>
<li><p>✅ "Summarize the types of insulin approved by the FDA as of 2024."</p>
</li>
</ul>
<h3 id="heading-9-understand-domain-specific-risk">9. <strong>Understand Domain-Specific Risk</strong></h3>
<p>Not all hallucinations are equal. In creative writing? Fine. In legal contracts or diagnostic advice? A disaster. Always calibrate your AI strategy based on the domain you’re in.</p>
<h3 id="heading-10-frame-it-as-part-of-responsible-ai">10. <strong>Frame It as Part of Responsible AI</strong></h3>
<p>Ultimately, hallucination detection isn’t just a technical fix—it’s an ethical obligation. If your AI system is used to make real decisions, you’re responsible for ensuring it doesn’t mislead.</p>
<h2 id="heading-conclusions">Conclusions</h2>
<p>Hallucination detection might sound like a niche technical issue, but it’s actually central to trust in AI. As language models become more powerful and more embedded in our daily work, the line between useful and harmful becomes thinner. By grounding AI outputs in truth, verifying sources, and keeping a human in the loop, we can move toward AI that isn’t just smart—but <strong>reliable</strong>.</p>
<p><strong>Because in the end, accuracy isn’t optional.</strong></p>
]]></content:encoded></item><item><title><![CDATA[Input Fuzzing: A Powerful Tool to Shield AI from Real-World Unpredictability]]></title><description><![CDATA[Ever run into a bug caused by a weird user input? Of course you have. Sometime the user enters special characters like ‘ or % or # which may break the process.
Now imagine your AI model—trained on cle]]></description><link>https://blogs.codingfreaks.net/input-fuzzing-a-powerful-tool-to-shield-ai-from-real-world-unpredictability</link><guid isPermaLink="true">https://blogs.codingfreaks.net/input-fuzzing-a-powerful-tool-to-shield-ai-from-real-world-unpredictability</guid><category><![CDATA[input-fuzzing]]></category><category><![CDATA[input fuzz testing]]></category><category><![CDATA[generative ai]]></category><category><![CDATA[#llmsecuritybymurali]]></category><category><![CDATA[ai testing]]></category><category><![CDATA[llm testing]]></category><category><![CDATA[AI reliability]]></category><dc:creator><![CDATA[Muralidharan Deenathayalan]]></dc:creator><pubDate>Mon, 19 May 2025 19:51:57 GMT</pubDate><content:encoded><![CDATA[<p>Ever run into a bug caused by a weird user input? Of course you have. Sometime the user enters special characters like ‘ or % or # which may break the process.</p>
<p>Now imagine your AI model—trained on clean, well-structured data—getting hit with one of those messy, typo-ridden, half-formed prompts that real users throw around.</p>
<p><strong>What happens next?</strong><br />That’s where <strong>input fuzzing</strong> comes in.</p>
<hr />
<h3>Wait, what is fuzzing again?</h3>
<p>Input fuzzing isn’t a new idea—it’s been used in traditional software testing for years. The concept is simple:</p>
<blockquote>
<p>You generate a <strong>ton of messy, malformed, or random inputs</strong>, and see how your system reacts.</p>
</blockquote>
<p>In web apps, it helps catch crashes. In security, it uncovers vulnerabilities. And in AI/ML, fuzzing can reveal some <em>truly weird</em> model behavior.</p>
<hr />
<h3>Why it’s so useful in AI testing</h3>
<p>We tend to train and validate our models on clean data. But real-world input? It’s anything but.</p>
<p>Here’s what your users might actually type:</p>
<ul>
<li><p>“heloo can yu halp me resett pasword?”</p>
</li>
<li><p>“reset passssswwwwwwwwwwwwwd”</p>
</li>
<li><p>“🔐🧠🧠 RESET plzzz idk anymore”</p>
</li>
</ul>
<p>And that’s just the tame stuff.</p>
<p>Without fuzzing, you might not know how your model will handle that noise. Will it:</p>
<ul>
<li><p>Misunderstand the intent?</p>
</li>
<li><p>Hallucinate a response?</p>
</li>
<li><p>Crash completely?</p>
</li>
<li><p>Echo the nonsense back?</p>
</li>
</ul>
<p>I’ve seen models do all four.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747684125300/b17a17bb-2ed2-4de6-8605-d33561ffa603.png" alt="" style="display:block;margin:0 auto" />

<hr />
<h3>Real example? Sure.</h3>
<p>At one point, we tested a customer support bot with some “fuzzed” prompts—just added extra spaces, emoji, typos, and repeated words.</p>
<p>A surprising number of them triggered <strong>fallback responses</strong>, or worse, caused the model to ignore the actual intent of the prompt.</p>
<p>Fuzzing helped us catch those edge cases before customers did.</p>
<hr />
<h3>How to actually do it</h3>
<p>You don’t need a massive framework to get started. Here's what works:</p>
<ol>
<li><p><strong>Manual variations</strong><br />Add typos, broken grammar, emoji spam—whatever your users might realistically do.</p>
</li>
<li><p><strong>Simple scripts</strong><br />A Python script that randomly adds noise, duplicates words, or flips characters can go a long way.</p>
</li>
<li><p><strong>Repurpose real inputs</strong><br />Take anonymized user prompts, modify them slightly, and use those as fuzz seeds.</p>
</li>
<li><p><strong>Mix with other testing</strong><br />Fuzzing pairs well with red teaming or regression testing. Think of it as the chaos layer.</p>
</li>
</ol>
<hr />
<h3>When should you care about this?</h3>
<p>Input fuzzing shines when:</p>
<ul>
<li><p>You’re launching anything user-facing (chatbots, voice assistants, form inputs)</p>
</li>
<li><p>Your app deals with multilingual, informal, or error-prone input</p>
</li>
<li><p>You want to preempt crashes or strange edge cases</p>
</li>
</ul>
<p>And honestly? It’s just a smart habit to build in.</p>
<hr />
<h3>Final thoughts</h3>
<p>Fuzzing won’t make headlines. It won’t give you shiny charts or benchmark bragging rights.</p>
<p>But it will quietly save you from real problems.</p>
<p>The kind that show up <strong>after launch</strong>, when it's already in users' hands. And those are the ones that matter most.</p>
]]></content:encoded></item></channel></rss>