* feat(foundry): add experimental to_prompt_agent converter Adds `to_prompt_agent(agent)`, an experimental converter (`ExperimentalFeature.TO_PROMPT_AGENT`) that turns an Agent Framework `Agent` into a Foundry `PromptAgentDefinition` ready to publish via `AIProjectClient.agents.create_version(...)`. Behaviour: * `agent.client` must be a `FoundryChatClient` (or subclass); otherwise `TypeError` is raised. The model deployment name is lifted from the bound client so the same Agent definition used for local runs can be published as a hosted prompt agent without restating the model. * Foundry SDK tool instances (from `FoundryChatClient.get_*_tool()`) are passed through unchanged. AF `FunctionTool`s (and `@tool`-decorated callables) are emitted as Foundry `FunctionTool` declarations. * Local AF MCP tools cannot be expressed in a `PromptAgentDefinition`; the converter raises `ValueError` and points at `FoundryChatClient.get_mcp_tool()` for hosted MCP servers. * The converter walks both `agent.default_options["tools"]` and `agent.mcp_tools` because `normalize_tools()` splits local MCP off into its own list. Re-exported through the `agent_framework.foundry` lazy-loading namespace (updates both `__init__.py` and the `__init__.pyi` type stub). Adds a portable-agent sample showing the same `Agent` driven through both `agent.run(...)` and `to_prompt_agent(agent)`, and a README section covering the new converter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(samples): remove snippet tags from portable agent sample Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(samples): inline FoundryChatClient and enable prompt-agent publish Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(samples): drop async credential context manager Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): trim README to_prompt_agent example to publish-only flow Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): note FoundryAgent runs @tool callables for deployed prompt agents Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): address review comments on to_prompt_agent converter * Construct `PromptAgentDefinition` `Tool` from a dict via `**tool_item` unpacking rather than the positional Mapping constructor \u2014 cleaner and matches the typical Pydantic / Azure SDK pattern. * Drop the redundant `isinstance(mcp_tool, MCPTool)` guard in `_convert_tools`; the parameter is already typed `Iterable[MCPTool]` so the second `raise` was unreachable. The remaining single `raise` fires for every entry as intended. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): match Agent.__init__ model resolution in to_prompt_agent * Read the model from `agent.default_options.get("model")` first, falling back to `agent.client.model`. This mirrors the order `Agent.__init__` uses (`_agents.py:740`) when assembling default_options, so the model the agent runs with is the same model the converter publishes \u2014 e.g. when the caller passes `default_options={"model": "..."}` to override the bound client. * Updated the missing-model error message to point at both the client and the default_options paths. * Added tests: * tool-only agent with no `instructions` produces a definition where `instructions` is `None` and is omitted from the dict payload (`Agent.__init__` strips None values from default_options before storing them). * `default_options['model']` wins over the bound client's model. * Fallback to client.model when default_options has no model. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(foundry): add deploy_as_prompt_agent helper + samples Adds `deploy_as_prompt_agent(agent)`, a convenience wrapper around `to_prompt_agent` that reuses the bound FoundryChatClient's project client to call `project_client.agents.create_version(...)`. Defaults `agent_name` / `description` from `agent.name` / `agent.description` so the Agent stays the single source of truth. * Exposed from `agent_framework_foundry` and the lazy-loading `agent_framework.foundry` namespace (including the .pyi stub). * Marked experimental with the existing `ExperimentalFeature.TO_PROMPT_AGENT` tag. * Tests cover the happy path, name/description defaulting, explicit override, no-name error, metadata + description forwarding, extra kwargs passthrough, and the experimental metadata. Samples: * Renamed the existing sample to `creating_prompt_agents.py`, drops 'portable' wording, presents `deploy_as_prompt_agent` first as the recommended path and `to_prompt_agent` + `AIProjectClient` as the two-step alternative, and adds a cleanup step that deletes the published agent so re-runs stay idempotent. * New `using_prompt_agents.py` shows the end-to-end loop: deploy the agent, connect to it with `FoundryAgent` passing the same local `@tool` callable, run a query against the deployed prompt agent, then clean up. README updated to introduce `deploy_as_prompt_agent` as the recommended path and link to both runnable samples. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): restore missing-model ValueError in to_prompt_agent The check was accidentally dropped while reworking docstrings in the previous commit. Test `test_to_prompt_agent_rejects_missing_model` exercises this path and was failing on CI as a result. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): rename deploy_as_prompt_agent -> create_prompt_agent Renames the helper across the foundry package, core lazy-loader stubs, tests, README and samples. The new name better matches the action performed (a prompt-agent definition is created in Foundry) and is consistent with the surrounding ''create_*'' API surface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): drop create_prompt_agent, enrich to_prompt_agent params Remove the create_prompt_agent helper and consolidate on to_prompt_agent. Expose every PromptAgentDefinition parameter that has either an Agent Framework equivalent (sourced from default_options) or no equivalent (accepted as a keyword argument). * default_options-sourced (with kwarg overrides): temperature, top_p, string tool_choice * kwarg-only Foundry knobs: reasoning, text, structured_inputs, rai_config, ToolChoiceParam tool_choice Precedence is always: explicit keyword > default_options entry > unset. Tests cover every path (defaults, default_options, kwargs, kwarg override). Samples and README rewritten around the enriched to_prompt_agent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): single source of truth for prompt-agent options Stop duplicating the generation-parameter surface between FoundryChatOptions and to_prompt_agent. Translate every field with an Agent Framework equivalent (temperature, top_p, tool_choice, reasoning, response_format/text/verbosity) from agent.default_options via a new RawFoundryChatClient helper _prepare_prompt_agent_options. Only Foundry-specific fields with no AF equivalent — structured_inputs and rai_config — remain as keyword arguments on to_prompt_agent. - tool_choice is dropped when there are no tools (mirrors _prepare_options semantics and avoids polluting tool-less prompt agents with Agent.__init__'s 'auto' default). - response_format Pydantic models route through openai.lib._parsing._responses.type_to_text_format_param; dict shapes go through the existing _prepare_response_and_text_format helper. - default_options is not mutated; text dict is defensively copied. Tests, README, and creating_prompt_agents.py sample updated to reflect the new single-source model. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): consolidate prompt-agent sample Drop creating_prompt_agents.py (the publish-only variant) and rename using_prompt_agents.py to foundry_prompt_agents.py so the single sample covers the full convert -> publish -> connect -> run loop. Update the README link list accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): run local Agent + deployed agent in same sample Add an agent.run() call against the local Agent before publishing, then run the deployed prompt agent on the same query. Expand the docstring with a compare-and-contrast covering runtime/latency, configurability, and persistence/sharing differences between the two execution paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(foundry): cover conflicting response_format + text.format in to_prompt_agent Exercises the ValueError path when a Pydantic response_format would overwrite an explicit text.format mapping with a different shape. Lifts _chat_client.py coverage from 89% to 90%. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): move _prepare_prompt_agent_options into _to_prompt_agent Lift the translation helper off RawFoundryChatClient and into the _to_prompt_agent module as a module-private function that takes the client as its first argument. The chat client no longer needs to carry a method whose only consumer is the prompt-agent converter, while still serving as the source of the request-path helper (_prepare_response_and_text_format) that the converter reuses for dict-shaped response_format values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(python): codify GA terminology + post-run docs review Add two pieces of guidance to python/AGENTS.md: * Terminology - reserve 'GA' for hosted services; use 'released' or 'stable' for Agent Framework code/features to match the feature-lifecycle stages. * Maintaining Documentation - review AGENTS.md and skills at the end of every run and update any guidance the conversation made stale; before adding a new principle, ask the user to confirm it should be captured. Also pulls in a docstring fix in foundry_prompt_agents.py that swaps the stray 'GA' for 'released', applying the new terminology rule. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * address PR review: strict=True default, Tool._deserialize dispatch, sample cleanup safety - FunctionTool published as strict=True so the server-side schema validation matches what the local FoundryAgent(tools=[same_callable]) dispatcher enforces. AF FunctionTool has no 'strict' attribute, so the safer default is used uniformly instead of silently downgrading to a permissive contract. - _validate_mapping_tool now dispatches through ProjectsTool._deserialize so dict-shaped tools rehydrate to the concrete subclass (FunctionTool, WebSearchTool, ...) via the 'type' discriminator instead of returning a generic Tool. Added a test that asserts isinstance(WebSearchTool) and a new test for the function-typed dict path. - foundry_prompt_agents.py sample now wraps credential + project client in async with and the create_version / run flow in try/finally so a failure on connect or run still deletes the published prompt agent rather than leaving an orphaned, billable resource in the user's Foundry project. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(ci): correct linkspector ignorePattern typo (./pulls -> ./pull) GitHub PR URLs use the singular segment /pull/N (compare to /issues/N for issues). The existing './pulls' ignore pattern never matched anything as a result, so legitimately stale PR links (e.g. PRs deleted from forks) surface as linkspector failures on unrelated PRs. This is the same convention the './issues' rule above already follows. Fixes the markdown-link-check failure on a dangling link in dotnet/src/Microsoft.Agents.AI.DurableTask/CHANGELOG.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Welcome to Microsoft Agent Framework!
Microsoft Agent Framework (MAF) is an open, multi-language framework for building production-grade AI agents and multi-agent workflows in .NET and Python.
Microsoft Agent Framework is built for teams taking agents from prototype to production. It provides a consistent foundation for building, orchestrating, and operating agent systems across Python and .NET, while keeping architecture choices open as requirements evolve, and supports a broad ecosystem including Microsoft Foundry, Azure OpenAI, OpenAI, and the GitHub Copilot SDK, with samples and hosting patterns for both local development and cloud deployment.
Watch the full Agent Framework introduction (30 min)
Is this the right framework for you?
MAF is a strong fit if you:
- are building agents and workflows you expect to run in production,
- need orchestration beyond a single prompt or stateless chat loop,
- want graph-based patterns such as sequential, concurrent, handoff, and group collaboration,
- care about durability, restartability, observability, governance, or human-in-the-loop control,
- need provider flexibility so your architecture can evolve without major rewrites.
Key Features
Explore new MAF capabilities and real implementation patterns on the official blog.
- Python and C#/.NET Support: Full framework support for both Python and C#/.NET implementations with consistent APIs
- Multiple Agent Provider Support: Support for various LLM providers with more being added continuously
- Middleware: Flexible middleware system for request/response processing, exception handling, and custom pipelines
- Orchestration Patterns & Workflows: Build multi-agent systems with graph-based workflows supporting sequential, concurrent, handoff, and group collaboration patterns; includes checkpointing, streaming, human-in-the-loop, and time-travel
- Foundry Hosted Agents (new): Deploy and host your agents to Foundry-hosted infrastructure with just 2 additional lines of code
- Observability: Built-in OpenTelemetry integration for distributed tracing, monitoring, and debugging
- Declarative Agents: Define agents using YAML for faster setup and versioning
- Agent Skills: Build domain-specific knowledge bases from multiple sources—files, inline code, class libraries—for agents to discover and use
- AF Labs: Experimental packages for cutting-edge features including benchmarking, reinforcement learning, and research initiatives
- DevUI: Interactive developer UI for agent development, testing, and debugging workflows
Table of Contents
Getting Started
Installation
Python
pip install agent-framework
# This will install all sub-packages, see `python/packages` for individual packages.
# It may take a minute on first install on Windows.
.NET
dotnet add package Microsoft.Agents.AI
# For Foundry integration (used in the .NET quickstart below):
dotnet add package Microsoft.Agents.AI.Foundry
dotnet add package Azure.AI.Projects
dotnet add package Azure.Identity
Learning Resources
- Overview - High level overview of the framework
- Quick Start - Get started with a simple agent
- Tutorials - Step by step tutorials
- User Guide - In-depth user guide for building agents and workflows
- Migration from Semantic Kernel - Guide to migrate from Semantic Kernel
- Migration from AutoGen - Guide to migrate from AutoGen
Quickstart
Basic Agent - Python
Create a simple Azure Responses Agent that writes a haiku about the Microsoft Agent Framework
# pip install agent-framework
# Use `az login` to authenticate with Azure CLI
import os
import asyncio
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
async def main():
# Initialize a chat agent with Microsoft Foundry
# the endpoint, deployment name, and api version can be set via environment variables
# or they can be passed in directly to the FoundryChatClient constructor
agent = Agent(
client=FoundryChatClient(
credential=AzureCliCredential(),
# project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
# model=os.environ["FOUNDRY_MODEL_DEPLOYMENT_NAME"],
),
name="HaikuAgent",
instructions="You are an upbeat assistant that writes beautifully.",
)
print(await agent.run("Write a haiku about Microsoft Agent Framework."))
if __name__ == "__main__":
asyncio.run(main())
Basic Agent - .NET
Create a simple Agent, using Microsoft Foundry that writes a haiku about the Microsoft Agent Framework
// This sample shows how to create and run a basic agent with AIProjectClient.AsAIAgent(...).
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-5.4-mini";
AIAgent agent =
new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
.AsAIAgent(model: deploymentName, instructions: "You are an upbeat assistant that writes beautifully.", name: "HaikuAgent");
// Once you have the agent, you can invoke it like any other AIAgent.
Console.WriteLine(await agent.RunAsync("Write a haiku about Microsoft Agent Framework."));
More Examples & Samples
Python
- Getting Started: progressive tutorial from hello-world to hosting
- Agent Concepts: deep-dive samples by topic (tools, middleware, providers, etc.)
- Workflows: workflow creation and integration with agents
- Hosting: A2A, Azure Functions, Durable Task hosting
- End-to-End: full applications, evaluation, and demos
.NET
- Getting Started: progressive tutorial from hello agent to hosting
- Agent Concepts: basic agent creation and tool usage
- Agent Providers: samples showing different agent providers
- Workflows: advanced multi-agent patterns and workflow orchestration
- Hosting: A2A, Durable Agents, Durable Workflows
- End-to-End: full applications and demos
Community & Feedback
- Found a bug? File a GitHub issue to help us improve.
- Enjoying MAF?
to show your support and help others discover the project.
- Have questions? Join our Discord or visit weekly office hours.
Troubleshooting
Authentication
| Problem | Cause | Fix |
|---|---|---|
| Authentication errors when using Azure credentials | Not signed in to Azure CLI | Run az login before starting your app |
| API key errors | Wrong or missing API key | Verify the key and ensure it's for the correct resource/provider |
Tip:
DefaultAzureCredentialis convenient for development but in production, consider using a specific credential (e.g.,ManagedIdentityCredential) to avoid latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
Environment Variables
For environment variable configuration specific to each sample, refer to the README in the sample directory (Python samples | .NET samples).
Contributor Resources
Important Notes
Important
If you use Microsoft Agent Framework to build applications that operate with any third-party servers, agents, code, or non-Azure Direct models (“Third-Party Systems”), you do so at your own risk. Third-Party Systems are Non-Microsoft Products under the Microsoft Product Terms and are governed by their own third-party license terms. You are responsible for any usage and associated costs.
We recommend reviewing all data being shared with and received from Third-Party Systems and being cognizant of third-party practices for handling, sharing, retention and location of data. It is your responsibility to manage whether your data will flow outside of your organization’s Azure compliance and geographic boundaries and any related implications, and that appropriate permissions, boundaries and approvals are provisioned.
You are responsible for carefully reviewing and testing applications you build using Microsoft Agent Framework in the context of your specific use cases, and making all appropriate decisions and customizations. This includes implementing your own responsible AI mitigations such as metaprompt, content filters, or other safety systems, and ensuring your applications meet appropriate quality, reliability, security, and trustworthiness standards. See also: Transparency FAQ
