<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Microsoft Agent Framework on dotnetuniversity</title>
        <link>https://dotnetuniversity.com/tags/microsoft-agent-framework/</link>
        <description>Recent content in Microsoft Agent Framework on dotnetuniversity</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-us</language>
        <lastBuildDate>Mon, 10 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://dotnetuniversity.com/tags/microsoft-agent-framework/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Microsoft Agent Framework: Agent Harness</title>
        <link>https://dotnetuniversity.com/microsoft-agent-framework-agent-harness/</link>
        <pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate>
        
        <guid>https://dotnetuniversity.com/microsoft-agent-framework-agent-harness/</guid>
        <description>&lt;img src="https://dotnetuniversity.com/microsoft-agent-framework-agent-harness/jesus-vidal-8QJU-HsXLJQ-unsplash.jpg" alt="Featured image of post Microsoft Agent Framework: Agent Harness" /&gt;&lt;h1 id=&#34;introduction&#34;&gt;Introduction
&lt;/h1&gt;&lt;p&gt;Calling a language model is easy. Building an agent that can work through a multi-step task, keep its context, request approval before using tools, and continue after another turn is harder.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Microsoft Agent Framework&lt;/strong&gt; is Microsoft&amp;rsquo;s set of APIs and abstractions for building agents, sessions, messages, tools, and workflows. The &lt;strong&gt;Agent Harness&lt;/strong&gt; is one runtime capability in that framework: it wraps an &lt;code&gt;IChatClient&lt;/code&gt; and coordinates agent execution around model calls.&lt;/p&gt;
&lt;p&gt;This is the first article in the Microsoft Agent Framework series. You do not need a separate framework introduction before reading it; this post introduces only the concepts needed for the Harness. We will build a small .NET API that keeps an agent session across requests.&lt;/p&gt;
&lt;h2 id=&#34;what-you-will-build&#34;&gt;What You Will Build
&lt;/h2&gt;&lt;p&gt;You will build a small customer support resolution assistant. It is backed by DeepSeek and the Agent Harness. A support agent can start with a customer issue, then continue with focused questions without resending the original context.&lt;/p&gt;
&lt;div class=&#34;copilot-prompt&#34;&gt;
&lt;div class=&#34;copilot-prompt__header&#34;&gt;Copilot Prompt&lt;/div&gt;
&lt;div class=&#34;copilot-prompt__body&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code data-lang=&#34;text&#34;&gt;Session 1: &#34;A customer cannot complete checkout after a card payment. Summarize the issue and suggest safe troubleshooting steps.&#34;
&lt;p&gt;Session 2: &amp;ldquo;Turn those troubleshooting steps into a customer-facing reply and include when to escalate.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Expected result: the second response builds on the first case because both turns use the same AgentSession.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h1 id=&#34;what-is-agent-harness&#34;&gt;What Is Agent Harness?
&lt;/h1&gt;&lt;p&gt;An Agent Harness is the execution layer around an agent. The model still decides what to say or which tool to call, but the Harness coordinates the work around those model calls.&lt;/p&gt;
&lt;p&gt;In this sample, the most visible Harness behavior is session continuity. The sample does not yet add custom functions, approval workflows, durable storage, or a multi-step plan. Those capabilities are useful extensions for later articles in the series.&lt;/p&gt;
&lt;p&gt;Without a Harness, an application commonly has to assemble these concerns itself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Store chat history between turns.&lt;/li&gt;
&lt;li&gt;Decide how multi-step work is planned and tracked.&lt;/li&gt;
&lt;li&gt;Invoke functions and apply approval policies.&lt;/li&gt;
&lt;li&gt;Control context growth and compact old history.&lt;/li&gt;
&lt;li&gt;Expose progress and operational state to the host application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Microsoft Agent Framework Harness gives these concerns a standard runtime surface. It does not replace the model, provide a model key, or decide where the application is hosted.&lt;/p&gt;
&lt;h2 id=&#34;agent-framework-harness-and-hosting&#34;&gt;Agent Framework, Harness, and Hosting
&lt;/h2&gt;&lt;p&gt;These terms describe different layers:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Layer&lt;/th&gt;
          &lt;th&gt;Responsibility&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Agent Framework&lt;/td&gt;
          &lt;td&gt;APIs and abstractions for agents, sessions, messages, tools, and workflows&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Agent Harness&lt;/td&gt;
          &lt;td&gt;Runtime scaffolding that coordinates planning, context, tools, approvals, and session state&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Hosting&lt;/td&gt;
          &lt;td&gt;The place and infrastructure where the application runs, such as an ASP.NET Core process or a managed agent service&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The Harness can run inside a console application, an ASP.NET Core service, or another host. The host owns authentication, persistence, networking, and deployment.&lt;/p&gt;
&lt;h1 id=&#34;real-world-example-customer-support-resolution-assistant&#34;&gt;Real-World Example: Customer Support Resolution Assistant
&lt;/h1&gt;&lt;p&gt;Imagine a support agent handling a customer who cannot complete checkout after a card payment. The case may require clarifying questions, safe troubleshooting, a customer-facing explanation, and escalation when the issue involves a payment or account risk. A single model response can suggest ideas, but the agent needs to continue the case while preserving the original details.&lt;/p&gt;
&lt;p&gt;The Harness is useful here for three reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first turn can summarize the issue and propose safe troubleshooting steps.&lt;/li&gt;
&lt;li&gt;The session keeps the customer and case details available during follow-up questions.&lt;/li&gt;
&lt;li&gt;The application can add tools later for knowledge-base search, ticket lookup, or escalation, with approval policies around consequential actions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Start the sample and send the first prompt:&lt;/p&gt;
&lt;div class=&#34;copilot-prompt&#34;&gt;
&lt;div class=&#34;copilot-prompt__header&#34;&gt;Copilot Prompt&lt;/div&gt;
&lt;div class=&#34;copilot-prompt__body&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code data-lang=&#34;text&#34;&gt;Session 1: &#34;A customer cannot complete checkout after a card payment. Summarize the issue and suggest safe troubleshooting steps.&#34;
&lt;p&gt;Session 2: &amp;ldquo;Turn those troubleshooting steps into a customer-facing reply and include when to escalate.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Expected result: the second response refines the support case using the details from Session 1.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The API returns a &lt;code&gt;sessionId&lt;/code&gt;. Send that value with Session 2 so the Harness can continue the same conversation.&lt;/p&gt;
&lt;p&gt;The second request is not a new conversation. The Harness receives the same &lt;code&gt;AgentSession&lt;/code&gt;, so the response can refine the original support case. This is a practical starting point: begin with conversation state, then add domain-specific tools as the workflow becomes more automated.&lt;/p&gt;
&lt;h1 id=&#34;harness-request-lifecycle&#34;&gt;Harness Request Lifecycle
&lt;/h1&gt;&lt;p&gt;The sample architecture is:&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;%%{init: {&#39;theme&#39;: &#39;base&#39;, &#39;themeVariables&#39;: {
  &#39;primaryColor&#39;: &#39;#e0f2fe&#39;,
  &#39;primaryTextColor&#39;: &#39;#172b4d&#39;,
  &#39;primaryBorderColor&#39;: &#39;#0284c7&#39;,
  &#39;lineColor&#39;: &#39;#64748b&#39;,
  &#39;secondaryColor&#39;: &#39;#dcfce7&#39;,
  &#39;tertiaryColor&#39;: &#39;#fef3c7&#39;,
  &#39;fontSize&#39;: &#39;20px&#39;,
  &#39;fontFamily&#39;: &#39;Arial&#39;
}}}%%
flowchart LR
    U[Support Client] --&gt;|POST prompt and optional sessionId| API

    subgraph HOST[ASP.NET Core Host]
        API[Agent API]
        R[AgentRuntime]
        S[(In-memory session store)]
        API --&gt;|prompt, sessionId| R
        R &lt;--&gt;|create or reuse AgentSession| S
    end

    subgraph HARNESS[Microsoft Agent Framework]
        H[Harness Agent]
        C[IChatClient]
        R --&gt;|RunAsync with AgentSession| H
        H --&gt; C
        H -.-&gt; T[Future: functions, approvals, context providers]
    end

    style HOST fill:#f1f5f9,stroke:#94a3b8,stroke-width:2px,color:#334155
    style HARNESS fill:#f1f5f9,stroke:#64748b,stroke-width:2px,color:#334155

    M[DeepSeek model endpoint] --&gt;|model response| C
    C --&gt;|chat completion request| M
    H --&gt;|AgentResponse| R
    R --&gt;|response and sessionId| API
    API --&gt; U

    classDef client fill:#e0e7ff,stroke:#4f46e5,stroke-width:2px,color:#312e81
    classDef api fill:#ccfbf1,stroke:#0f766e,stroke-width:2px,color:#134e4a
    classDef runtime fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#172b4d
    classDef state fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d
    classDef model fill:#f3f4f6,stroke:#6b7280,stroke-width:2px,color:#1f2937
    classDef future fill:#fce7f3,stroke:#db2777,stroke-width:2px,color:#831843

    class U client
    class API api
    class R,H,C runtime
    class S state
    class M model
    class T future&lt;/div&gt;
&lt;p&gt;&lt;code&gt;AgentSession&lt;/code&gt; is important. It is the state container passed to each run. Reusing the same session lets the Harness preserve conversation history and Harness-managed state across turns. Creating a new session for every request creates a new conversation.&lt;/p&gt;
&lt;h1 id=&#34;create-a-harness-agent&#34;&gt;Create a Harness Agent
&lt;/h1&gt;&lt;p&gt;The entry point is the &lt;code&gt;AsHarnessAgent&lt;/code&gt; extension method. It accepts an &lt;code&gt;IChatClient&lt;/code&gt; and returns an agent with Harness behavior configured around it. This example uses DeepSeek&amp;rsquo;s OpenAI-compatible API, so the Harness code stays independent from the model provider.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;29
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cba6f7&#34;&gt;using&lt;/span&gt; &lt;span style=&#34;color:#fab387&#34;&gt;System.ClientModel&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cba6f7&#34;&gt;using&lt;/span&gt; &lt;span style=&#34;color:#fab387&#34;&gt;Microsoft.Agents.AI&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cba6f7&#34;&gt;using&lt;/span&gt; &lt;span style=&#34;color:#fab387&#34;&gt;Microsoft.Extensions.AI&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cba6f7&#34;&gt;using&lt;/span&gt; &lt;span style=&#34;color:#fab387&#34;&gt;OpenAI&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;IChatClient chatClient = &lt;span style=&#34;color:#cba6f7&#34;&gt;new&lt;/span&gt; OpenAIClient(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#cba6f7&#34;&gt;new&lt;/span&gt; ApiKeyCredential(&lt;span style=&#34;color:#a6e3a1&#34;&gt;&amp;#34;&amp;lt;deepseek-api-key&amp;gt;&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#cba6f7&#34;&gt;new&lt;/span&gt; OpenAIClientOptions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Endpoint = &lt;span style=&#34;color:#cba6f7&#34;&gt;new&lt;/span&gt; Uri(&lt;span style=&#34;color:#a6e3a1&#34;&gt;&amp;#34;https://api.deepseek.com&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .GetChatClient(&lt;span style=&#34;color:#a6e3a1&#34;&gt;&amp;#34;deepseek-v4-flash&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .AsIChatClient();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AIAgent agent = chatClient.AsHarnessAgent(&lt;span style=&#34;color:#cba6f7&#34;&gt;new&lt;/span&gt; HarnessAgentOptions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ChatOptions = &lt;span style=&#34;color:#cba6f7&#34;&gt;new&lt;/span&gt; ChatOptions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Instructions = &lt;span style=&#34;color:#a6e3a1&#34;&gt;&amp;#34;You are a customer support resolution assistant.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    DisableWebSearch = &lt;span style=&#34;color:#fab387&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AgentSession session = &lt;span style=&#34;color:#cba6f7&#34;&gt;await&lt;/span&gt; agent.CreateSessionAsync();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AgentResponse response = &lt;span style=&#34;color:#cba6f7&#34;&gt;await&lt;/span&gt; agent.RunAsync(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e3a1&#34;&gt;&amp;#34;A customer cannot complete checkout after a card payment. Summarize the issue and suggest safe troubleshooting steps.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    session);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Console.WriteLine(response.Text);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The sample disables the built-in web search capability so the example has an explicit, predictable tool boundary. Enable and govern capabilities deliberately when an application needs them.&lt;/p&gt;
&lt;h1 id=&#34;the-sample-application&#34;&gt;The Sample Application
&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AgentHarness&lt;/code&gt; contains the agent runtime and Harness configuration.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AgentHarness.Api&lt;/code&gt; contains the HTTP host and endpoint.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AgentSession&lt;/code&gt; instances are held in an in-memory dictionary for clarity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The runtime creates one Harness agent and reuses it for requests. Each request supplies a session ID. The first request creates a session; later requests with that ID reuse it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f38ba8&#34;&gt;var&lt;/span&gt; session = &lt;span style=&#34;color:#cba6f7&#34;&gt;await&lt;/span&gt; _agent.CreateSessionAsync(cancellationToken);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f38ba8&#34;&gt;var&lt;/span&gt; response = &lt;span style=&#34;color:#cba6f7&#34;&gt;await&lt;/span&gt; _agent.RunAsync(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    prompt,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    session,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cancellationToken: cancellationToken);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;In a real service, replace the dictionary with a durable session store. Also authenticate the caller and verify that the caller owns the session before resuming it. A session ID is a lookup key, not an authorization boundary.&lt;/p&gt;
&lt;h1 id=&#34;configure-and-run&#34;&gt;Configure and Run
&lt;/h1&gt;&lt;p&gt;From the sample directory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f5e0dc&#34;&gt;$env&lt;/span&gt;:DS_KEY &lt;span style=&#34;color:#89dceb;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e3a1&#34;&gt;&amp;#34;&amp;lt;your-deepseek-api-key&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dotnet run --project AgentHarness.Api
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The sample reads the API key from the &lt;code&gt;DS_KEY&lt;/code&gt; environment variable. It uses &lt;code&gt;https://api.deepseek.com&lt;/code&gt; and &lt;code&gt;deepseek-v4-flash&lt;/code&gt; by default. Both endpoint and model are configurable through &lt;code&gt;DeepSeek:Endpoint&lt;/code&gt; and &lt;code&gt;DeepSeek:Model&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Send a first request:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -X POST http://localhost:5000/api/agent/chat &lt;span style=&#34;color:#89b4fa&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#89b4fa&#34;&gt;&lt;/span&gt;  -H &lt;span style=&#34;color:#a6e3a1&#34;&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#89b4fa&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#89b4fa&#34;&gt;&lt;/span&gt;  -d &lt;span style=&#34;color:#a6e3a1&#34;&gt;&amp;#39;{&amp;#34;prompt&amp;#34;:&amp;#34;A customer cannot complete checkout after a card payment. Summarize the issue and suggest safe troubleshooting steps.&amp;#34;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The response contains a &lt;code&gt;sessionId&lt;/code&gt;. Send it with the next request to continue the conversation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -X POST http://localhost:5000/api/agent/chat &lt;span style=&#34;color:#89b4fa&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#89b4fa&#34;&gt;&lt;/span&gt;  -H &lt;span style=&#34;color:#a6e3a1&#34;&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#89b4fa&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#89b4fa&#34;&gt;&lt;/span&gt;  -d &lt;span style=&#34;color:#a6e3a1&#34;&gt;&amp;#39;{&amp;#34;sessionId&amp;#34;:&amp;#34;&amp;lt;returned-session-id&amp;gt;&amp;#34;,&amp;#34;prompt&amp;#34;:&amp;#34;Turn those troubleshooting steps into a customer-facing reply and include when to escalate.&amp;#34;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h1 id=&#34;when-to-use-agent-harness&#34;&gt;When to Use Agent Harness
&lt;/h1&gt;&lt;p&gt;Use a Harness when work naturally spans multiple steps or turns and the application benefits from consistent session and tool behavior. Examples include research assistants, coding agents, data analysis workflows, and operations assistants.&lt;/p&gt;
&lt;p&gt;A plain chat client may be a better fit for a single request and response, especially when the application owns all state and does not need tool orchestration. The Harness adds useful behavior, but it also adds runtime policy that should be understood before production use.&lt;/p&gt;
&lt;h1 id=&#34;production-considerations&#34;&gt;Production Considerations
&lt;/h1&gt;&lt;p&gt;The sample is intentionally small. Production systems need additional decisions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Persist and version sessions instead of keeping them in process memory.&lt;/li&gt;
&lt;li&gt;Authenticate users and authorize every session resume.&lt;/li&gt;
&lt;li&gt;Restrict tools and require approval for consequential actions.&lt;/li&gt;
&lt;li&gt;Set execution, timeout, and token budgets.&lt;/li&gt;
&lt;li&gt;Record traces, tool calls, errors, and model usage.&lt;/li&gt;
&lt;li&gt;Pin package versions and review release notes because provider APIs are evolving.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h1&gt;&lt;p&gt;Microsoft Agent Framework Agent Harness is a runtime layer that turns an &lt;code&gt;IChatClient&lt;/code&gt; into a more capable, stateful agent. Its central idea is simple: create the Harness agent once, create a session for a conversation, and reuse that session across runs.&lt;/p&gt;
&lt;p&gt;The next posts in this series can build on this foundation with function tools, approvals, durable sessions, context providers, and observability.&lt;/p&gt;
&lt;h2 id=&#34;you-can-find-the-sample-code-in-this-repository&#34;&gt;You can find the sample code in this repository:
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/meysamhadeli/blog-samples/tree/main/src/agent-harness-sample&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Microsoft Agent Framework Agent Harness sample&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://learn.microsoft.com/agent-framework/concepts/harness&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Microsoft Agent Framework Harness overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://learn.microsoft.com/agent-framework/get-started/harness&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Get started with Agent Harness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://devblogs.microsoft.com/agent-framework/the-microsoft-agent-framework-harness-is-now-released&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Microsoft Agent Framework Harness released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/microsoft/agent-framework/tree/main/dotnet/samples/02-agents/Harness&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Microsoft Agent Framework .NET samples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://learn.microsoft.com/agent-framework/agents/tools/function-tools#use-function-tools-with-harness-agent&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Using function tools with a Harness agent&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        
    </channel>
</rss>
