Table of Contents
In the previous article, we treated an agent as an application with testable boundaries: model calls, tools, structured output, routing, workflows, approvals, and failure handling.
The testing approach assumes the agent belongs to your application. C# code creates it, the process owns the session, your application stores the conversation, and your deployment platform runs the service.
Foundry gives you another place to put some of that responsibility. The agent can become a managed cloud resource with its own identity, endpoint, version, conversation state, access policy, and operational lifecycle. C# may still define its behavior, but the agent now exists outside your application process as well.
The ownership decision comes before the hosting details. You can keep the agent inside your application and call Foundry services, deploy the Agent Framework code as a hosted agent, or let Foundry own more of the definition through a prompt agent. Each choice puts the runtime, state, identity, and business policy in a different place.
Foundry does more than expose another model endpoint. Its control plane can handle enterprise identity, RBAC, governance, deployment, observability, and persistent state. You pay for that convenience with more resource boundaries, permissions, lifecycle decisions, and a tighter dependency on the platform.
My rule is simple:
Keep agent behavior and business policy in code when they need normal software engineering control. Use Foundry when the agent itself needs managed identity, durable state, controlled sharing, centralized governance, or a managed runtime.
Choose the ownership model first
Start by separating model access, agent runtime, conversation state, identity, and business authorization. Choosing Foundry for one of them does not force you to hand over the others.
The current Foundry Agent Service documentation describes two main agent types: prompt agents and hosted agents. There is also a useful third deployment choice for Agent Framework applications: keep the code in your own process and call the Foundry Responses API without creating a managed agent resource.
| Approach | Where the main behavior lives | What Foundry manages | What your application still manages |
|---|---|---|---|
| Prompt agent | Instructions, model selection, and tools configured through the portal, SDK, or REST API | Runtime, endpoint, scaling, identity, conversations, tools, and lifecycle | Product integration, end-user authorization, and domain policy |
| Hosted agent | Your Agent Framework code, packaged as a container or source bundle | Hosted runtime, endpoint, scaling, dedicated agent identity, session persistence, observability, and lifecycle | Agent logic, tools, business policy, tests, and the release artifact |
| In-process Agent Framework agent using Foundry | Your web app, worker, or service | Models, platform tools, and the project-scoped Responses API | Hosting, scaling, application endpoint, state mapping, and deployment lifecycle |
Foundry visual workflows are a separate orchestration capability, not a third agent type alongside prompt and hosted agents. Microsoft has announced that the visual workflow experience will retire on December 1, 2026 and recommends Microsoft Agent Framework for new workflow implementations. I treat workflows as migration context here, not as another ownership model.
An application may need Foundry model and tool access while keeping the runtime in its own process. Create a managed agent resource only when you want Foundry to operate that runtime.
A local Agent Framework agent starts as application state
In the local version, the application creates the AIAgent, creates or restores the AgentSession, invokes the model through IChatClient, and owns the surrounding endpoint, storage, authorization, and observability.
| Concern | Local Agent Framework application |
|---|---|
| Agent definition | C# code, configuration, and registered tools |
| Agent lifetime | The process creates and uses the agent |
| Session lifetime | In memory by default, or stored by an application-owned provider |
| Conversation identity | An application concept such as a user or chat ID |
| Authentication | The application authenticates to the model and downstream services |
| Authorization | Application code and tool policy decide what the user may do |
| Deployment | Your web app, worker, container, or job platform |
| Versioning | Source control, package versions, and your deployment pipeline |
| Observability | Your OpenTelemetry, logs, and monitoring setup |
This keeps the agent close to the code that owns its business rules. Your team also owns state, user mapping, deployment, scaling, endpoint security, versioning, and observability.
Foundry adds an agent control plane
Foundry puts resource boundaries above the running agent. The request path then looks roughly like this:
Application-owned boundary
--------------------------
User interface or API
|
v
Application API
- authentication
- end-user authorization
- tenant policy
- conversation mapping
|
v
Foundry-managed control plane
-----------------------------
Foundry project endpoint
|
v
Prompt agent or hosted Agent Framework runtime
|
+--> model deployment
+--> tools and connections
+--> conversation or session state
+--> traces, metrics, versions, and lifecycle metadata
The new URL is the least interesting part. What matters is that the agent now has a life outside one application process.
Foundry can provide:
- a project boundary for agents, files, evaluations, and related assets
- managed hosting and scaling
- a dedicated hosted-agent identity and a separate project identity
- RBAC for creating, managing, and invoking agents
- versioned agent endpoints and optional publishing or distribution lifecycle
- managed conversation or session state
- tracing and monitoring integrations
- networking, storage, and encryption options for enterprise requirements
With the control plane in place, platform and security teams can manage the agent as an operational resource instead of finding it buried inside an application deployment.
Hosted agents keep the code, but move the runtime
For an existing Agent Framework application, a hosted agent is usually the shortest path into Foundry. Your orchestration, tools, approval logic, and workflow can remain in C#. Foundry takes over the deployment and runtime around that code.
A minimal Responses host still creates an AIAgent, but exposes it through the Foundry hosting boundary:
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
AIAgent agent = new AIProjectClient(
new Uri(builder.Configuration["FOUNDRY_PROJECT_ENDPOINT"]!),
new DefaultAzureCredential())
.AsAIAgent(
model: builder.Configuration["AZURE_AI_MODEL_DEPLOYMENT_NAME"]!,
instructions: """
You help operators inspect deployments.
Use read-only tools automatically.
Request approval before production side effects.
""",
name: "deployment-agent",
description: "An operations assistant for deployment checks.");
builder.Services.AddFoundryResponses(agent);
WebApplication app = builder.Build();
app.MapFoundryResponses();
app.Run();
Responses fits conversational agents because it supports streaming and message continuity through previous_response_id or a conversation ID. Invocations is better suited to non-conversational work or a custom request and response shape.
Do not confuse a hosted session with a conversation. A hosted session identifies sandbox compute and persisted filesystem state such as $HOME and /files; a Responses conversation stores message, tool call, and response history. Reusing an agent_session_id routes work to the same sandbox but does not replay prior messages. Invocations leaves conversation history to your application.
A hosted deployment also needs an azure.yaml file that declares the agent protocol, source directory, project, model deployment, and deployment mode. The current azd ai agent init flow can generate this from existing Agent Framework code.
The azd extension surface is still moving quickly, so I would treat the official hosted-agent guide as the source of truth for exact commands. The command sequence is not the architectural point. What matters is that the same C# agent now has a deployed Foundry version, a dedicated endpoint, and a runtime identity.
Treat persistent agents as compatibility context
Documentation searches may still surface Azure.AI.Agents.Persistent and the older agent, thread, message, and run model. That API is real, but it belongs to the classic Azure AI Agents surface. Microsoft has deprecated Agents (classic) and lists March 31, 2027 as its retirement date.
For new systems, choose the current Foundry Agent Service surface first: Responses API for in-process Agent Framework integrations, hosted agents when Foundry should run your Agent Framework code, and prompt agents when Foundry should own the agent definition. Use the persistent client mainly when maintaining or migrating an existing classic implementation.
A managed conversation is still an application data record
With a local AgentSession, you decide whether the session is a short-lived object, a serialized row, or a custom ChatHistoryProvider. Responses, hosted sessions, and classic persistent threads can move part of that durable record into Foundry.
The convenience is real, but state now crosses an application boundary.
The application now needs an explicit mapping such as:
application user and tenant
|
+--> application conversation ID
|
+--> Foundry conversation, response, or session ID
Do not treat a raw service ID as authorization. The request handler must still verify that the authenticated caller may access the mapped conversation.
A simple repository boundary keeps that decision in your application:
public sealed record ConversationBinding(
string ApplicationConversationId,
string TenantId,
string UserId,
string FoundryStateId,
string FoundryStateKind,
string AgentVersion);
public interface IConversationBindingStore
{
Task<ConversationBinding?> FindAsync(
string tenantId,
string userId,
string applicationConversationId,
CancellationToken cancellationToken);
Task SaveAsync(
ConversationBinding binding,
CancellationToken cancellationToken);
}
The Foundry ID and its protocol-specific kind are implementation details. Keep an application-owned record so you have somewhere to enforce tenant isolation, user ownership, agent version selection, retention decisions, and audit correlation.
Before calling managed conversation state “memory solved,” answer these questions:
- How long should inactive conversations remain available?
- Can a user export or delete their conversation?
- Can support staff inspect it, and under which role?
- What happens when the agent version changes?
- Which data may be stored in the managed service?
Foundry provides storage and retention building blocks. In the basic agent setup, files, conversations, and related state can use Microsoft-managed multitenant storage with logical separation. The standard agent setup lets you bring your own Azure resources for customer data, including files, conversations, and vector stores.
Your product remains responsible for retention, deletion, export, and support access policies.
RBAC introduces a second authorization plane
In a local application, developers may have repository access and an application identity may have access to the model endpoint. The application then decides what each end user can do.
Foundry adds a second access plane around the resource and project.
The current Foundry architecture separates control-plane actions from data-plane actions:
- control plane: create resources, projects, model deployments, and security configuration
- data plane: build agents, run evaluations, upload files, invoke agents, and work with project assets
Those permissions can be scoped at the Foundry resource and project levels.
The role names are changing too. Current documentation uses names such as Foundry User, Foundry Project Manager, Foundry Account Owner, and Foundry Agent Consumer. Older pages and existing role assignments may still show the previous names.
For that reason, a role table in an architecture document should record the role purpose and scope instead of copying a role name alone:
| Actor | Typical responsibility | Important boundary |
|---|---|---|
| Platform administrator | Create the Foundry resource, networking, model deployments, and shared connections | Resource or subscription scope |
| Project manager | Configure and deploy project agents and hosted versions | Project or resource scope, depending on operation |
| Agent developer | Build and test agents, tools, evaluations, and prompts | Prefer project scope |
| Agent consumer | Invoke an agent endpoint without broad development access | Project or individual-agent scope |
| Application managed identity | Call the project endpoint from the application | Only the required project or agent permissions |
| Agent identity | Reach models, search, storage, MCP servers, or APIs | Downstream resource scope |
| End user | Use an agent through the product | Application authorization, not automatically Azure RBAC |
Every hosted agent receives a dedicated Microsoft Entra identity and endpoint when deployed. That agent identity is the runtime identity. The project managed identity handles project-level infrastructure operations and cannot stand in for the hosted agent’s identity. The agent identity still needs explicit role assignments for any external Azure resources it uses.
Use Microsoft Entra authentication when you need this granularity. Key-based authentication does not provide the same role-level separation because the key grants broad access to the service.
Broad owner permissions are a tempting shortcut when the first setup fails. They may unblock a prototype while quietly turning every developer into a resource administrator.
The subtler mistake is treating the agent’s managed identity as end-user authorization. It is not.
Suppose the agent can read an Azure AI Search index. The current user may still be allowed to see only some of its documents. User and tenant filters belong in the retrieval boundary. The same rule applies to tools that read tickets, invoices, deployments, or customer records.
Foundry RBAC controls who can manage or invoke the agent resource. Your application still needs to control what a particular user may ask that agent to do.
Governance becomes part of the architecture
When an agent lives only in code, the repository is usually the best record of its definition. Once it becomes a managed resource, its effective behavior may also depend on:
- instructions configured in the portal or resource
- model and deployment selection
- tool definitions and connection settings
- content filters and guardrails
- project-level permissions
- managed identity assignments
- network configuration
- stored files and conversation state
- deployed version, endpoint routing, and optional publishing settings
The C# class is now only part of the system. Foundry can add versioned endpoints, optional publishing and distribution, centralized monitoring, and resource-level governance. It can also introduce configuration drift.
A portal edit to instructions or tools is enough to make the repository disagree with the agent running in production.
I would treat the Foundry configuration as code or as a versioned deployment artifact wherever possible:
source code and prompt definitions
|
v
tests and evaluations
|
v
Foundry project configuration
|
v
deployed agent version
|
v
dedicated agent endpoint
|
v
optional publishing or distribution
For a prompt agent, I would create and update the definition through an SDK or REST API in the deployment pipeline rather than make production-only portal edits. With a hosted Agent Framework agent, the C# code remains the main behavior definition and the Foundry resource describes its runtime and deployment.
Whichever model you use, pick one authoritative layer.
Treat instructions, tools, model deployment names, connections, identity assignments, and protocol versions as release inputs. Promote tested versions through development, test, and production instead of editing the production agent casually.
Keep trace correlation across both ownership planes. A production trace should connect the application request, tenant, user, application conversation, Foundry agent version, Foundry state ID, model and tool spans, approvals, and side-effect IDs. Without that chain, Foundry may show a healthy agent run that you still cannot connect to a customer’s request.
Split responsibility deliberately
Foundry can take over operations around the agent. Domain responsibility stays with your application.
| Concern | Keep in application code | Foundry can manage |
|---|---|---|
| Agent behavior | Business rules, tool contracts, structured results, and deterministic workflow transitions | Prompt-agent configuration or the runtime around hosted code |
| Authorization | User, tenant, and record-level access checks | RBAC for managing and invoking Foundry resources and endpoints |
| Side effects | Validation, approval policy, idempotency, and audit records | Agent identity and secure access to downstream resources |
| Conversation data | Product conversation ID, ownership mapping, retention policy, and domain data | Response history, hosted sessions, or managed conversation storage, depending on the protocol |
| Quality | Deterministic tests for tools, routing, workflows, approvals, and failures | Evaluations, tracing, metrics, and managed monitoring |
| Deployment | Source review, release inputs, and promotion policy | Hosted runtime, scaling, endpoint, agent versions, and platform lifecycle |
| Governance | The authoritative definition of business behavior | Project boundaries, identities, connections, networking, encryption, and resource inventory |
A prompt such as “only show records the user can access” is not an authorization system. The API or tool must enforce user, tenant, and permission filters before returning data to the agent.
The same applies to side effects. Foundry governance does not make a model-authorized deployment, refund, email, or permission change safe by itself. The application must still decide whether the action is allowed and whether it needs human approval, as described in the human-in-the-loop article.
Foundry evaluations complement deterministic tests. They do not replace them. The service conversation schema is an integration contract, not your product’s domain model.
Pick the side of the table based on the operational work your team wants to own. Keep the domain responsibilities that cannot be delegated in application code.
When I would use Foundry
I would consider Foundry when:
- the agent needs a managed runtime instead of another application-owned container
- multiple products or teams need to invoke a shared agent
- the agent needs durable conversations or managed sessions
- platform teams need project boundaries and centralized RBAC
- an agent needs a dedicated identity for downstream resources
- security and compliance teams need network, storage, encryption, or audit controls
- the organization needs versioned endpoints, optional distribution, monitoring, and an agent inventory
Hosted agents fit an existing Agent Framework application well: the orchestration stays in code and the runtime becomes a managed resource.
Managed hosting may cost more than expected. Hosted-agent runtime billing is based on CPU and memory consumed across active sessions, so concurrency and oversized sandboxes multiply the cost. An in-process agent can reuse existing application compute, while leaving scaling, isolation, and operations with your team. Compare the full operating cost of both models, including the engineering work outside the compute bill.
When I would stay local
I would keep the agent primarily in the application when:
- it is a small feature used by one product
- the conversation state already belongs in the product database
- the agent must run locally or in multiple clouds
- the application owns complex domain workflows and side effects
- the agent changes frequently and needs tight source-level review
- a Foundry project would add more permissions and deployment ceremony than value
Using Foundry models and platform tools through the Responses API does not force you to create a managed agent. Model access and agent lifecycle are separate decisions.
Conclusion
Microsoft Agent Framework gives you the .NET runtime abstractions. Foundry can put a managed control plane around them. Once it does, the agent definition, conversation state, runtime identity, deployed version, and operational lifecycle may no longer belong to one application team.
I would keep Agent Framework in the application when the agent should share the product’s host, state, and release cycle. A hosted agent fits when the C# orchestration should remain intact but the runtime needs a managed endpoint, identity, and lifecycle. A prompt agent makes sense when Foundry should own the definition too.
None of these options lets the model decide business authorization or side-effect policy. Keep deterministic controls and application conversation IDs in code. Version the complete release input, and correlate Foundry state with the product request that created it.
All three options use code somewhere. The decision is about what happens after deployment: which team owns the agent, and where do they need to operate it?
Further reading
- Microsoft Agent Framework overview
- What is Microsoft Foundry Agent Service?
- Microsoft Foundry architecture
- Role-based access control for Microsoft Foundry
- Build agents using the Responses API
- Host Microsoft Agent Framework agents as Foundry hosted agents
- Hosted agents in Foundry Agent Service
- Foundry standard agent setup and customer-owned resources
- Testing Microsoft Agent Framework Applications
- Observability for Agents with OpenTelemetry, Aspire, and Application Insights