{"id":624,"date":"2026-06-15T21:08:01","date_gmt":"2026-06-15T21:08:01","guid":{"rendered":"https:\/\/codingwithramin.com\/?p=624"},"modified":"2026-07-23T08:02:20","modified_gmt":"2026-07-23T08:02:20","slug":"meet-work-iq-the-intelligence-behind-copilot-now-an-api-you-can-build-on","status":"publish","type":"post","link":"https:\/\/codingwithramin.com\/?p=624","title":{"rendered":"Meet Work IQ: The Intelligence Behind Copilot, Now an API You Can Build On"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Over the last year, our team has been building a private AI application for clients. The use cases changed from project to project, but the infrastructure underneath them started to look uncomfortably familiar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We needed agents. Then tools for those agents. Then connectors to Microsoft 365 and other systems. Then indexing, retrieval, conversation state, monitoring and permission checks. Every new capability solved a user problem while quietly giving us another component to operate.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I saw the same pattern in my own experiments. In my <a href=\"https:\/\/codingwithramin.com\/?p=518\">SharePoint agents series<\/a>, I grounded an agent in SharePoint content. Later, I added <a href=\"https:\/\/codingwithramin.com\/?p=592\">long-term memory to Foundry agents<\/a> so they could retain useful information between conversations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The demos worked. The engineering bill arrived afterwards.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Connectors need maintenance. Indexes fall behind. Retrieval quality changes as content grows. Permissions are even less forgiving: a system that gets access control right 99% of the time is not nearly good enough.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is why Work IQ caught my attention. It reached general availability on June 16, 2026, but the announcement itself was not the interesting part for me. I was more interested in the code I might no longer need to own: sync jobs, custom indexes, permission-trimming logic and the long list of edge cases that appear when a prototype becomes a client-facing application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This series is my attempt to understand whether Work IQ genuinely removes that work or simply moves it behind another SDK.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this first part, I will explain the mental model that clicked for me and make the smallest useful call from C#.<a href=\"https:\/\/codingwithramin.com\/?p=644\"> Part 2<\/a> adds the A2A SDK, multi-turn context and streaming. <a href=\"https:\/\/codingwithramin.com\/?p=654\">Part 3<\/a> moves from delegated answers to MCP tools.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Version note:<\/strong> The API details in this article were checked against the Microsoft documentation available in July 2026. Work IQ is moving quickly, so check the linked documentation before copying preview-specific code into a production project.<\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><strong><strong>The hard part was never the demo<\/strong><\/strong><\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"498\" src=\"https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/part1_1.png\" alt=\"\" class=\"wp-image-764\" srcset=\"https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/part1_1.png 800w, https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/part1_1-300x187.png 300w, https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/part1_1-768x478.png 768w, https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/part1_1-769x479.png 769w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine an agent that can answer this:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Catch me up on the Contoso migration. What changed, who owns the open actions, and what did we agree in the last review?<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">The impressive demo is the final answer, the difficult system sits behind it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To answer properly, the agent may need information from email, Teams chats, meeting transcripts, SharePoint, OneDrive and the organisation directory. A traditional implementation usually grows into something like this:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Connect to each source.<\/li>\n\n\n\n<li>Extract and index the content.<\/li>\n\n\n\n<li>Keep every index in sync.<\/li>\n\n\n\n<li>Reproduce enough of Microsoft 365&#8217;s permission model to filter every result correctly.<\/li>\n\n\n\n<li>Rank the retrieved content and send it to a model.<\/li>\n\n\n\n<li>Preserve citations so the user can verify the answer.<\/li>\n\n\n\n<li>Monitor the whole pipeline when the data, permissions or APIs change.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Retrieval gets most of the attention because it is easy to demonstrate. Permission trimming deserves more.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A stale result is annoying. A result containing a document the user should not see is a security incident.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That failure rarely arrives as a helpful exception. The application still returns a fluent answer. The problem is that one of its sources crossed a sharing boundary, sensitivity label or access rule that your custom pipeline did not model correctly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is where several of my prototypes stopped feeling like AI projects and started feeling like data-governance projects.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><strong>The mental model that finally clicked<\/strong><\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">My first assumption was that Work IQ would be Microsoft Graph with a more conversational endpoint.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is not how I think about it now.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Graph gives your application <strong>data<\/strong>. You call \/me\/messages, receive messages and decide what to do with them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Work IQ gives an agent access to Microsoft&#8217;s <strong>understanding of work<\/strong>. It combines Microsoft 365 data with context, permissions and reasoning so the caller can ask a work-shaped question rather than manually reconstructing the answer from several APIs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That difference sounds small until you build both versions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With Graph, the application owns retrieval, ranking and synthesis. With Work IQ Chat, the application can hand over the question and receive a grounded answer with citations. The request still runs as the signed-in user, so existing Microsoft 365 permissions and compliance controls remain part of the boundary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The simplest comparison I can offer is this:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Graph is the filing system.<\/li>\n\n\n\n<li>Work IQ is the colleague who can investigate the filing system and explain what matters.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Both are useful. They solve different problems.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><strong>The four parts of Work IQ<\/strong><\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Microsoft describes Work IQ through four connected components. I find it easier to think about them in terms of what an agent needs.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Chat<\/strong> answers a natural-language question using grounded Microsoft 365 context. This is where I start in Parts 1 and 2.<\/li>\n\n\n\n<li><strong>Context<\/strong> assembles relevant grounding for an agent that wants to perform its own reasoning rather than receive a finished answer.<\/li>\n\n\n\n<li><strong>Tools<\/strong> let an agent read, create, update and act across Microsoft 365. Part 3 explores this through MCP.<\/li>\n\n\n\n<li><strong>Workspaces<\/strong> provide persistent working state for longer-running agent scenarios.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The distinction between Chat and Tools is especially important.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sometimes you want to delegate the whole problem:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Find the latest decisions about this project and summarise them.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">At other times, your own agent is already doing the reasoning and only needs a capability:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Read these messages, create a draft and schedule a follow-up.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">The first is a conversation with Work IQ. The second is tool use. I confused those models initially, and separating them made the rest of the API much easier to understand.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><strong>How it changes a custom RAG architecture<\/strong><\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If you already have a RAG solution over Microsoft 365, Work IQ does not automatically make the whole architecture irrelevant. You may still need your own model, domain data, prompts, workflows or non-Microsoft connectors.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What it can remove is the part many teams would rather not rebuild:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>separate vector indexes for Microsoft 365 content;<\/li>\n\n\n\n<li>sync jobs for files, messages and meetings;<\/li>\n\n\n\n<li>custom permission trimming;<\/li>\n\n\n\n<li>retrieval ranking across several Microsoft 365 workloads;<\/li>\n\n\n\n<li>home-grown citation handling.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For the private AI application we have been developing, this is the interesting trade-off. Every component we remove is one less component that can drift, fail or expose information incorrectly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It also changes what the team spends time discussing. Instead of asking, &#8220;How do we keep this connector and index in sync?&#8221;, we can spend more time on the behaviour of the agent itself.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is a better engineering problem.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Choosing the right protocol<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Work IQ exposes the same underlying intelligence through different interaction models.<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table class=\"has-fixed-layout\"><thead><tr><th>Protocol<\/th><th>I would use it when\u2026<\/th><th>Typical caller<\/th><\/tr><\/thead><tbody><tr><td><strong>A2A<\/strong><\/td><td>One agent needs to delegate a structured task to Work IQ<\/td><td>Another agent<\/td><\/tr><tr><td><strong>REST<\/strong><\/td><td>An application or backend needs a request\/response integration<\/td><td>Web app, service or orchestrator<\/td><\/tr><tr><td><strong>MCP<\/strong><\/td><td>A model-driven client needs Work IQ capabilities as tools<\/td><td>Custom agent, IDE assistant or agent platform<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">I am starting with <strong>A2A<\/strong> because it makes the delegation model visible. We will send a message to Work IQ and receive a task containing a grounded answer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For a normal web application, REST may feel more familiar. For an agent that wants individual Microsoft 365 capabilities, MCP is usually the more interesting surface.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is no single correct protocol. The question is: who is doing the reasoning?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><strong><strong>Licensing after general availability<\/strong><\/strong><\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is one area where old preview guidance can mislead you.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As of July 2026, custom use of the Work IQ API is billed through a consumption-based model using <strong>Copilot Credits<\/strong>. Microsoft states that there is no separate Work IQ API subscription, SKU or per-user licence for this API usage. Administrators enable and govern consumption through the Microsoft 365 admin centre, including access policies, spending limits and alerts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Microsoft 365 Copilot&#8217;s prebuilt experiences follow their own licensing treatment. Custom agents built through Copilot Studio, Foundry or third-party platforms can incur Work IQ API consumption.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In other words, do not copy a preview-era setup guide and assume the licensing section still applies. Confirm billing and access in the tenant before debugging the code.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><strong><strong><strong>A note before copying samples<\/strong><\/strong><\/strong><\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Work IQ changed quickly between preview and general availability. Endpoints, permissions and samples did not all move at exactly the same pace.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When I first worked through the examples, I found it useful to compare three things rather than trusting one page in isolation:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>the current Microsoft Learn article;<\/li>\n\n\n\n<li>the implementation in the <a href=\"https:\/\/github.com\/microsoft\/work-iq-samples\">official samples repository<\/a>;<\/li>\n\n\n\n<li>the actual request and response captured from my test tenant.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">The code in this article uses the dedicated Work IQ A2A gateway:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>https:&#47;&#47;workiq.svc.cloud.microsoft\/a2a\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It requests a token for the Work IQ resource, not Microsoft Graph. That distinction matters. A valid Graph token is not automatically a valid Work IQ token.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><strong><strong>The first call<\/strong><\/strong><\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I deliberately avoided the A2A SDK for this first sample.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is not how I would build the finished client. I wanted to see the protocol once: the token audience, JSON-RPC envelope, A2A version header and response shape.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once you understand those pieces, the SDK in <a href=\"https:\/\/codingwithramin.com\/?p=644\">Part 2 <\/a>feels like a useful abstraction rather than magic.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Register an Entra app<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Before you register your app, there&#8217;s one tenant-level prerequisite that is easy to miss: an organization admin has to enable the Work IQ API in the tenant by creating its service principal. That&#8217;s a one-time setup per organization, not something every developer repeats.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If it hasn&#8217;t been done yet, an admin can run:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Bash<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>az ad sp create --id fdcc1f02-fc51-4226-8753-f668596af7f7<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #DCDCAA\">az<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">ad<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">sp<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">create<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">--id<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">fdcc1f02-fc51-4226-8753-f668596af7f7<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Once that service principal exists in the tenant, you can register your own client app.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the <a href=\"https:\/\/portal.azure.com\">Azure portal<\/a>, open <strong>Microsoft Entra ID<\/strong> \u2192 <strong>App registrations<\/strong> \u2192 <strong>New registration<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For a simple console demo:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>choose the account type that matches your tenant;<\/li>\n\n\n\n<li>add a <strong>public client\/native<\/strong> redirect URI of <code>http:\/\/localhost<\/code>;<\/li>\n\n\n\n<li>add the Work IQ delegated permission;<\/li>\n\n\n\n<li>grant admin consent.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The delegated permission is <code>WorkIQAgent.Ask<\/code> on the Work IQ resource. The sample below requests:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"832\" height=\"886\" src=\"https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/image.png\" alt=\"\" class=\"wp-image-635\" style=\"width:608px;height:auto\" srcset=\"https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/image.png 832w, https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/image-282x300.png 282w, https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/image-768x818.png 768w, https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/image-769x819.png 769w\" sizes=\"auto, (max-width: 832px) 100vw, 832px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"360\" src=\"https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/image-1.png\" alt=\"\" class=\"wp-image-767\" srcset=\"https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/image-1.png 800w, https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/image-1-300x135.png 300w, https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/image-1-768x346.png 768w, https:\/\/codingwithramin.com\/wp-content\/uploads\/2026\/06\/image-1-769x346.png 769w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Work IQ uses delegated authentication. Requests run in the context of the signed-in user. On-behalf-of flows are supported, but application-only authentication is not.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I see that as part of the design rather than an inconvenience. There is no background service identity with unrestricted access to everybody&#8217;s work data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Copy the <strong>application (client) ID<\/strong> and <strong>tenant ID<\/strong>. We need both in the sample.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: <strong>Create the project<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Now let&#8217;s keep the project itself as small as possible: a plain console app and the one package we need for interactive sign-in.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">PowerShell<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>dotnet new console -n WorkIQHello\ncd WorkIQHello\ndotnet add package Microsoft.Identity.Client<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">dotnet new console -n WorkIQHello<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">cd WorkIQHello<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">dotnet add package Microsoft.Identity.Client<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">MSAL handles interactive authentication. The rest is standard HttpClient and System.Text.Json.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This sample targets .NET 10, but the protocol itself is not tied to that version.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: <strong>Acquire a token and send a message<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">With that in place, we can write the whole flow end to end: sign the user in, call the Work IQ gateway, and print the answer that comes back.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>using System.Net.Http.Headers;\nusing System.Text;\nusing System.Text.Json;\nusing Microsoft.Identity.Client;\n\n\/\/ --- 1. Acquire a delegated token for the Work IQ resource ---\nconst string ClientId = \"&lt;your-app-client-id>\";\nconst string TenantId = \"&lt;your-tenant-id>\";\nconst string Scope    = \"api:\/\/workiq.svc.cloud.microsoft\/.default\";\nconst string Endpoint = \"https:\/\/workiq.svc.cloud.microsoft\/a2a\/\";\n\nvar app = PublicClientApplicationBuilder\n    .Create(ClientId)\n    .WithAuthority($\"https:\/\/login.microsoftonline.com\/{TenantId}\")\n    .WithDefaultRedirectUri()\n    .Build();\n\nvar auth = await app\n    .AcquireTokenInteractive(new[] { Scope })\n    .ExecuteAsync();\n\n\/\/ --- 2. Build an HttpClient pointed at the Work IQ gateway ---\nvar http = new HttpClient();\nhttp.DefaultRequestHeaders.Authorization =\n    new AuthenticationHeaderValue(\"Bearer\", auth.AccessToken);\nhttp.DefaultRequestHeaders.Accept.Add(\n    new MediaTypeWithQualityHeaderValue(\"application\/json\"));\n\n\/\/ Opt in to the A2A v1.0 wire format. Without this header the gateway\nhttp.DefaultRequestHeaders.TryAddWithoutValidation(\"A2A-Version\", \"1.0\");\n\n\/\/ --- 3. Build an A2A message wrapped in a JSON-RPC envelope ---\nvar message = new Dictionary&lt;string, object?>\n{\n    &#91;\"role\"&#93;      = \"ROLE_USER\",\n    &#91;\"messageId\"&#93; = Guid.NewGuid().ToString(),\n    &#91;\"parts\"&#93;     = new object[] { new { text = \"What meetings do I have today?\" } },\n    \/\/ Location lets Work IQ resolve \"today\" \/ \"this week\" in the user's local time.\n    &#91;\"metadata\"&#93;  = new Dictionary&lt;string, object>\n    {\n        &#91;\"Location\"&#93; = new\n        {\n            timeZoneOffset = (int)TimeZoneInfo.Local.BaseUtcOffset.TotalMinutes,\n            timeZone = TimeZoneInfo.Local.Id\n        }\n    }\n};\n\nvar rpc = new\n{\n    jsonrpc = \"2.0\",\n    id = Guid.NewGuid().ToString(),\n    method = \"SendMessage\",          \/\/ sync; \"SendStreamingMessage\" for SSE (Part 2)\n    @params = new { message }\n};\n\nvar content = new StringContent(\n    JsonSerializer.Serialize(rpc), Encoding.UTF8, \"application\/json\");\n\n\/\/ --- 4. POST to the gateway base URL \u2014 the method lives in the body, not the path ---\nvar response = await http.PostAsync(Endpoint, content);\nvar body = await response.Content.ReadAsStringAsync();\n\nif (!response.IsSuccessStatusCode)\n{\n    Console.WriteLine($\"{(int)response.StatusCode} {response.StatusCode}\\n{body}\");\n    return;\n}\n\n\/\/ --- 5. Pull the answer out of result.task.artifacts[].parts[].text ---\nusing var doc = JsonDocument.Parse(body);\nvar result = doc.RootElement.GetProperty(\"result\");\n\nConsole.WriteLine(ExtractAnswer(result));\nPrintCitations(result);\n\nstatic string ExtractAnswer(JsonElement result)\n{\n    \/\/ A completed task carries the answer as one or more artifacts.\n    if (result.TryGetProperty(\"task\", out var task) &amp;&amp;\n        task.TryGetProperty(\"artifacts\", out var artifacts))\n    {\n        var sb = new StringBuilder();\n        foreach (var artifact in artifacts.EnumerateArray())\n            if (artifact.TryGetProperty(\"parts\", out var parts))\n                foreach (var p in parts.EnumerateArray())\n                    if (p.TryGetProperty(\"text\", out var t))\n                        sb.Append(t.GetString());\n        return sb.ToString();\n    }\n    return \"(no answer found)\";\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">System<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Net<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Http<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Headers<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">System<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Text<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">System<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Text<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Json<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Microsoft<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Identity<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #4EC9B0\">Client<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">\/\/ --- 1. Acquire a delegated token for the Work IQ resource ---<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">string<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">ClientId<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;&lt;your-app-client-id&gt;&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">string<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">TenantId<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;&lt;your-tenant-id&gt;&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">string<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Scope<\/span><span style=\"color: #D4D4D4\">    = <\/span><span style=\"color: #CE9178\">&quot;api:\/\/workiq.svc.cloud.microsoft\/.default&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">string<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Endpoint<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;https:\/\/workiq.svc.cloud.microsoft\/a2a\/&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">app<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">PublicClientApplicationBuilder<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    .<\/span><span style=\"color: #DCDCAA\">Create<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ClientId<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    .<\/span><span style=\"color: #DCDCAA\">WithAuthority<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">$&quot;https:\/\/login.microsoftonline.com\/{<\/span><span style=\"color: #9CDCFE\">TenantId<\/span><span style=\"color: #CE9178\">}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    .<\/span><span style=\"color: #DCDCAA\">WithDefaultRedirectUri<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    .<\/span><span style=\"color: #DCDCAA\">Build<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">auth<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">app<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    .<\/span><span style=\"color: #DCDCAA\">AcquireTokenInteractive<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\">[] { <\/span><span style=\"color: #9CDCFE\">Scope<\/span><span style=\"color: #D4D4D4\"> })<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    .<\/span><span style=\"color: #DCDCAA\">ExecuteAsync<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">\/\/ --- 2. Build an HttpClient pointed at the Work IQ gateway ---<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">http<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">HttpClient<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">http<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">DefaultRequestHeaders<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Authorization<\/span><span style=\"color: #D4D4D4\"> =<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">AuthenticationHeaderValue<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Bearer&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">auth<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">AccessToken<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">http<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">DefaultRequestHeaders<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Accept<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">Add<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">MediaTypeWithQualityHeaderValue<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;application\/json&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">\/\/ Opt in to the A2A v1.0 wire format. Without this header the gateway<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">http<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">DefaultRequestHeaders<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryAddWithoutValidation<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;A2A-Version&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;1.0&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">\/\/ --- 3. Build an A2A message wrapped in a JSON-RPC envelope ---<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">message<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Dictionary<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #569CD6\">string<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">object<\/span><span style=\"color: #D4D4D4\">?&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    &#91;<\/span><span style=\"color: #CE9178\">&quot;role&quot;<\/span><span style=\"color: #D4D4D4\">&#93;      = <\/span><span style=\"color: #CE9178\">&quot;ROLE_USER&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    &#91;<\/span><span style=\"color: #CE9178\">&quot;messageId&quot;<\/span><span style=\"color: #D4D4D4\">&#93; = <\/span><span style=\"color: #9CDCFE\">Guid<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">NewGuid<\/span><span style=\"color: #D4D4D4\">().<\/span><span style=\"color: #DCDCAA\">ToString<\/span><span style=\"color: #D4D4D4\">(),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    &#91;<\/span><span style=\"color: #CE9178\">&quot;parts&quot;<\/span><span style=\"color: #D4D4D4\">&#93;     = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">object<\/span><span style=\"color: #D4D4D4\">[] { <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">text<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;What meetings do I have today?&quot;<\/span><span style=\"color: #D4D4D4\"> } },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">    \/\/ Location lets Work IQ resolve &quot;today&quot; \/ &quot;this week&quot; in the user&#39;s local time.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    &#91;<\/span><span style=\"color: #CE9178\">&quot;metadata&quot;<\/span><span style=\"color: #D4D4D4\">&#93;  = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Dictionary<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #569CD6\">string<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">object<\/span><span style=\"color: #D4D4D4\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        &#91;<\/span><span style=\"color: #CE9178\">&quot;Location&quot;<\/span><span style=\"color: #D4D4D4\">&#93; = <\/span><span style=\"color: #569CD6\">new<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">timeZoneOffset<\/span><span style=\"color: #D4D4D4\"> = (<\/span><span style=\"color: #569CD6\">int<\/span><span style=\"color: #D4D4D4\">)<\/span><span style=\"color: #9CDCFE\">TimeZoneInfo<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Local<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">BaseUtcOffset<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">TotalMinutes<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">timeZone<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">TimeZoneInfo<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Local<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Id<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">rpc<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">jsonrpc<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;2.0&quot;<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">id<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">Guid<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">NewGuid<\/span><span style=\"color: #D4D4D4\">().<\/span><span style=\"color: #DCDCAA\">ToString<\/span><span style=\"color: #D4D4D4\">(),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">method<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;SendMessage&quot;<\/span><span style=\"color: #D4D4D4\">,          <\/span><span style=\"color: #6A9955\">\/\/ sync; &quot;SendStreamingMessage&quot; for SSE (Part 2)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">@params<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #9CDCFE\">message<\/span><span style=\"color: #D4D4D4\"> }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">content<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">StringContent<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">JsonSerializer<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">Serialize<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">rpc<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #9CDCFE\">Encoding<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">UTF8<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;application\/json&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">\/\/ --- 4. POST to the gateway base URL \u2014 the method lives in the body, not the path ---<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">http<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">PostAsync<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">Endpoint<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">content<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">body<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Content<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">ReadAsStringAsync<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (!<\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">IsSuccessStatusCode<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">Console<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">WriteLine<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">$&quot;{(<\/span><span style=\"color: #569CD6\">int<\/span><span style=\"color: #CE9178\">)<\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #CE9178\">.<\/span><span style=\"color: #9CDCFE\">StatusCode<\/span><span style=\"color: #CE9178\">} {<\/span><span style=\"color: #9CDCFE\">response<\/span><span style=\"color: #CE9178\">.<\/span><span style=\"color: #9CDCFE\">StatusCode<\/span><span style=\"color: #CE9178\">}<\/span><span style=\"color: #D7BA7D\">\\n<\/span><span style=\"color: #CE9178\">{<\/span><span style=\"color: #9CDCFE\">body<\/span><span style=\"color: #CE9178\">}&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">\/\/ --- 5. Pull the answer out of result.task.artifacts[].parts[].text ---<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">using<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">doc<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">JsonDocument<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">Parse<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">body<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">doc<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">RootElement<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">GetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;result&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">Console<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">WriteLine<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #DCDCAA\">ExtractAnswer<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">PrintCitations<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">static<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">string<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">ExtractAnswer<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #4EC9B0\">JsonElement<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">    \/\/ A completed task carries the answer as one or more artifacts.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryGetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;task&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">out<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">task<\/span><span style=\"color: #D4D4D4\">) &amp;&amp;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">task<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryGetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;artifacts&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">out<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">artifacts<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">sb<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #569CD6\">new<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">StringBuilder<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">foreach<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">artifact<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">artifacts<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">EnumerateArray<\/span><span style=\"color: #D4D4D4\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">artifact<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryGetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;parts&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">out<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">parts<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #C586C0\">foreach<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">p<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">parts<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">EnumerateArray<\/span><span style=\"color: #D4D4D4\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">p<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryGetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;text&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">out<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">t<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                        <\/span><span style=\"color: #9CDCFE\">sb<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">Append<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">t<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">GetString<\/span><span style=\"color: #D4D4D4\">());<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">sb<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">ToString<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;(no answer found)&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The sample is small, but three details are easy to miss.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>The method is in the body<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You post every request to the A2A gateway base URL. <code>SendMessage<\/code> is the JSON-RPC method; it is not a URL segment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That felt unusual after years of REST APIs, where the path normally tells you what operation is happening.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>The version header changes the wire format<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Work IQ supports A2A 1.0 and 0.3. If you omit A2A-Version, the service currently falls back to 0.3 for compatibility.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The message above uses the 1.0 shape, including ROLE_USER. Sending that shape without the header can produce a &#8220;method not found&#8221; error that points you in the wrong direction.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Time-sensitive prompts need location<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Words such as <em>today<\/em>, <em>tomorrow<\/em> and <em>this week<\/em> are ambiguous without a time zone.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Location metadata gives Work IQ enough information to interpret those prompts for the current user. I now treat that metadata as part of the request rather than an optional enhancement.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Do not hide the sources<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A fluent answer is not enough for an enterprise agent.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Users need to see where the answer came from, and developers need the same evidence when the output looks wrong. Work IQ returns attribution metadata that can be rendered as citations.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">C#<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>static void PrintCitations(JsonElement result)\n{\n    \/\/ Metadata can sit on the task's status message; shape mirrors the streaming case.\n    if (!result.TryGetProperty(\"task\", out var task) ||\n        !task.TryGetProperty(\"status\", out var status) ||\n        !status.TryGetProperty(\"message\", out var msg) ||\n        !msg.TryGetProperty(\"metadata\", out var meta) ||\n        !meta.TryGetProperty(\"attributions\", out var attributions) ||\n        attributions.ValueKind != JsonValueKind.Array)\n        return;\n\n    Console.WriteLine(\"\\nSources:\");\n    foreach (var a in attributions.EnumerateArray())\n    {\n        var name = a.TryGetProperty(\"providerDisplayName\", out var n) ? n.GetString() : \"(source)\";\n        var url  = a.TryGetProperty(\"seeMoreWebUrl\", out var u) ? u.GetString() : \"\";\n        Console.WriteLine($\"  \u2022 {name}  {url}\");\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">static<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">void<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">PrintCitations<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #4EC9B0\">JsonElement<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">    \/\/ Metadata can sit on the task&#39;s status message; shape mirrors the streaming case.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (!<\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryGetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;task&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">out<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">task<\/span><span style=\"color: #D4D4D4\">) ||<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        !<\/span><span style=\"color: #9CDCFE\">task<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryGetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;status&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">out<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">status<\/span><span style=\"color: #D4D4D4\">) ||<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        !<\/span><span style=\"color: #9CDCFE\">status<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryGetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;message&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">out<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">) ||<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        !<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryGetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;metadata&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">out<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">meta<\/span><span style=\"color: #D4D4D4\">) ||<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        !<\/span><span style=\"color: #9CDCFE\">meta<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryGetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;attributions&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">out<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">attributions<\/span><span style=\"color: #D4D4D4\">) ||<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">attributions<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">ValueKind<\/span><span style=\"color: #D4D4D4\"> != <\/span><span style=\"color: #9CDCFE\">JsonValueKind<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Array<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">Console<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">WriteLine<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #D7BA7D\">\\n<\/span><span style=\"color: #CE9178\">Sources:&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">foreach<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">a<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">attributions<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">EnumerateArray<\/span><span style=\"color: #D4D4D4\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">a<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryGetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;providerDisplayName&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">out<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">n<\/span><span style=\"color: #D4D4D4\">) ? <\/span><span style=\"color: #9CDCFE\">n<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">GetString<\/span><span style=\"color: #D4D4D4\">() : <\/span><span style=\"color: #CE9178\">&quot;(source)&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">url<\/span><span style=\"color: #D4D4D4\">  = <\/span><span style=\"color: #9CDCFE\">a<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">TryGetProperty<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;seeMoreWebUrl&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">out<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">var<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">u<\/span><span style=\"color: #D4D4D4\">) ? <\/span><span style=\"color: #9CDCFE\">u<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">GetString<\/span><span style=\"color: #D4D4D4\">() : <\/span><span style=\"color: #CE9178\">&quot;&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">Console<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">WriteLine<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">$&quot;  \u2022 {<\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #CE9178\">}  {<\/span><span style=\"color: #9CDCFE\">url<\/span><span style=\"color: #CE9178\">}&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Run it (<strong>dotnet run<\/strong>), sign in when the browser pops up, and you should get back something like:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">Bash<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>Today you have: 9 AM standup, 11 AM review with Dana, 2 PM customer call.\n\nSources:\n  \u2022 Calendar  https:\/\/outlook.office.com\/...<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #DCDCAA\">Today<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">you<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">have:<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">9<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">AM<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">standup,<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">11<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">AM<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">review<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">with<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">Dana,<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">PM<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">customer<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">call.<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">Sources:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">\u2022<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">Calendar<\/span><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #CE9178\">https:\/\/outlook.office.com\/...<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The answer is grounded in the signed-in user&#8217;s Microsoft 365 context and returned with sources. We did not create a calendar connector, copy events into a vector store or write permission filters.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is the point of the demo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Not that forty lines of C# are impressive. That roughly forty lines replaced a collection of infrastructure I have spent much of the last year thinking about.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><strong>What I would not ship yet<\/strong><\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This sample proves the integration, nothing more.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It has no conversational state. It waits for the entire response before showing anything. The JSON-RPC envelope and response parsing are handwritten. Token caching and production error handling are deliberately absent.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I still think starting here is useful. Seeing the raw request removed several wrong assumptions I had about Work IQ, particularly the difference between its token audience and Microsoft Graph.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But I would stop using raw JSON at this point.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/codingwithramin.com\/?p=644\">Part 2<\/a> replaces it with the A2A .NET SDK, preserves context between turns and streams the answer as it arrives.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><strong><strong>The bigger reason I am exploring Work IQ<\/strong><\/strong><\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I am not interested in Work IQ because it gives me another way to call an AI service.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I am interested because our private AI work has repeatedly pulled us towards the same operational problems: maintaining agents, tools, connectors, retrieval and permissions across systems that continue changing after the demo is finished.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Work IQ will not remove every one of those problems. It may, however, let us stop rebuilding the Microsoft 365 part.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is a meaningful improvement.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Code for this series is available in <a href=\"https:\/\/github.com\/AhmadiRamin\/work-iq-samples\">AhmadiRamin\/work-iq-samples<\/a>. Next: building a conversational client with the A2A SDK.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Over the last year, our team has been building a private AI application for clients. The use cases changed from project to project, but the infrastructure underneath them started to look uncomfortably familiar. We needed agents. Then tools for those agents. Then connectors to Microsoft 365 and other systems. Then indexing, retrieval, conversation state, monitoring and permission checks. Every new capability solved a user problem while quietly giving us another component to operate. I saw&hellip;<\/p>\n","protected":false},"author":1,"featured_media":643,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[55,72,65,5,6],"tags":[49,9,76],"class_list":["post-624","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai","category-ai-agent","category-azure-ai-foundry","category-microsoft-azure","category-microsoft-graph","tag-ai","tag-azure","tag-workiq"],"_links":{"self":[{"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/posts\/624","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=624"}],"version-history":[{"count":33,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/posts\/624\/revisions"}],"predecessor-version":[{"id":768,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/posts\/624\/revisions\/768"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=\/wp\/v2\/media\/643"}],"wp:attachment":[{"href":"https:\/\/codingwithramin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=624"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=624"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codingwithramin.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=624"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}