chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import Agent
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
"""
|
||||
Hello Agent — Simplest possible agent
|
||||
|
||||
This sample creates a minimal agent using FoundryChatClient via an
|
||||
Azure AI Foundry project endpoint, and runs it in both non-streaming and streaming modes.
|
||||
|
||||
There are XML tags in all of the get started samples, those are used to display the same code in the docs repo.
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# <create_agent>
|
||||
client = FoundryChatClient(
|
||||
project_endpoint="https://your-project.services.ai.azure.com",
|
||||
model="gpt-4o",
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
client=client,
|
||||
name="HelloAgent",
|
||||
instructions="You are a friendly assistant. Keep your answers brief.",
|
||||
)
|
||||
# </create_agent>
|
||||
|
||||
# <run_agent>
|
||||
# Non-streaming: get the complete response at once
|
||||
result = await agent.run("What is the capital of France?")
|
||||
print(f"Agent: {result}")
|
||||
# </run_agent>
|
||||
|
||||
# <run_agent_streaming>
|
||||
# Streaming: receive tokens as they are generated
|
||||
print("Agent (streaming): ", end="", flush=True)
|
||||
async for chunk in agent.run("Tell me a one-sentence fun fact.", stream=True):
|
||||
if chunk.text:
|
||||
print(chunk.text, end="", flush=True)
|
||||
print()
|
||||
# </run_agent_streaming>
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,58 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from random import randint
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import Agent, tool
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from azure.identity import AzureCliCredential
|
||||
from pydantic import Field
|
||||
|
||||
"""
|
||||
Add Tools — Give your agent a function tool
|
||||
|
||||
This sample shows how to define a function tool with the @tool decorator
|
||||
and wire it into an agent so the model can call it.
|
||||
"""
|
||||
|
||||
|
||||
# <define_tool>
|
||||
# NOTE: approval_mode="never_require" is for sample brevity.
|
||||
# Use "always_require" in production for user confirmation before tool execution.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
) -> str:
|
||||
"""Get the weather for a given location."""
|
||||
conditions = ["sunny", "cloudy", "rainy", "stormy"]
|
||||
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
|
||||
|
||||
|
||||
# </define_tool>
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
client = FoundryChatClient(
|
||||
project_endpoint="https://your-project.services.ai.azure.com",
|
||||
model="gpt-4o",
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
|
||||
# <create_agent_with_tools>
|
||||
agent = Agent(
|
||||
client=client,
|
||||
name="WeatherAgent",
|
||||
instructions="You are a helpful weather agent. Use the get_weather tool to answer questions.",
|
||||
tools=[get_weather],
|
||||
)
|
||||
# </create_agent_with_tools>
|
||||
|
||||
# <run_agent>
|
||||
result = await agent.run("What's the weather like in Seattle?")
|
||||
print(f"Agent: {result}")
|
||||
# </run_agent>
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,47 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import Agent
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
"""
|
||||
Multi-Turn Conversations — Use AgentSession to maintain context
|
||||
|
||||
This sample shows how to keep conversation history across multiple calls
|
||||
by reusing the same session object.
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# <create_agent>
|
||||
client = FoundryChatClient(
|
||||
project_endpoint="https://your-project.services.ai.azure.com",
|
||||
model="gpt-4o",
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
client=client,
|
||||
name="ConversationAgent",
|
||||
instructions="You are a friendly assistant. Keep your answers brief.",
|
||||
)
|
||||
# </create_agent>
|
||||
|
||||
# <multi_turn>
|
||||
# Create a session to maintain conversation history
|
||||
session = agent.create_session()
|
||||
|
||||
# First turn
|
||||
result = await agent.run("My name is Alice and I love hiking.", session=session)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Second turn — the agent should remember the user's name and hobby
|
||||
result = await agent.run("What do you remember about me?", session=session)
|
||||
print(f"Agent: {result}")
|
||||
# </multi_turn>
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,105 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import Agent, AgentSession, ContextProvider, SessionContext
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
"""
|
||||
Agent Memory with Context Providers and Session State
|
||||
|
||||
Context providers inject dynamic context into each agent call. This sample
|
||||
shows a provider that stores the user's name in session state and personalizes
|
||||
responses — the name persists across turns via the session.
|
||||
"""
|
||||
|
||||
|
||||
# <context_provider>
|
||||
class UserMemoryProvider(ContextProvider):
|
||||
"""A context provider that remembers user info in session state."""
|
||||
|
||||
DEFAULT_SOURCE_ID = "user_memory"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(self.DEFAULT_SOURCE_ID)
|
||||
|
||||
async def before_run(
|
||||
self,
|
||||
*,
|
||||
agent: Any,
|
||||
session: AgentSession | None,
|
||||
context: SessionContext,
|
||||
state: dict[str, Any],
|
||||
) -> None:
|
||||
"""Inject personalization instructions based on stored user info."""
|
||||
user_name = state.get("user_name")
|
||||
if user_name:
|
||||
context.extend_instructions(
|
||||
self.source_id,
|
||||
f"The user's name is {user_name}. Always address them by name.",
|
||||
)
|
||||
else:
|
||||
context.extend_instructions(
|
||||
self.source_id,
|
||||
"You don't know the user's name yet. Ask for it politely.",
|
||||
)
|
||||
|
||||
async def after_run(
|
||||
self,
|
||||
*,
|
||||
agent: Any,
|
||||
session: AgentSession | None,
|
||||
context: SessionContext,
|
||||
state: dict[str, Any],
|
||||
) -> None:
|
||||
"""Extract and store user info in session state after each call."""
|
||||
for msg in context.input_messages:
|
||||
text = msg.text if hasattr(msg, "text") else ""
|
||||
if isinstance(text, str) and "my name is" in text.lower():
|
||||
state["user_name"] = text.lower().split("my name is")[-1].strip().split()[0].capitalize()
|
||||
|
||||
|
||||
# </context_provider>
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# <create_agent>
|
||||
client = FoundryChatClient(
|
||||
project_endpoint="https://your-project.services.ai.azure.com",
|
||||
model="gpt-4o",
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
client=client,
|
||||
name="MemoryAgent",
|
||||
instructions="You are a friendly assistant.",
|
||||
context_providers=[UserMemoryProvider()],
|
||||
)
|
||||
# </create_agent>
|
||||
|
||||
# <run_with_memory>
|
||||
session = agent.create_session()
|
||||
|
||||
# The provider doesn't know the user yet — it will ask for a name
|
||||
result = await agent.run("Hello! What's the square root of 9?", session=session)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Now provide the name — the provider stores it in session state
|
||||
result = await agent.run("My name is Alice", session=session)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Subsequent calls are personalized — name persists via session state
|
||||
result = await agent.run("What is 2 + 2?", session=session)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Inspect session state to see what the provider stored
|
||||
provider_state = session.state.get("user_memory", {})
|
||||
print(f"[Session State] Stored user name: {provider_state.get('user_name')}")
|
||||
# </run_with_memory>
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,55 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""
|
||||
Functional Workflow with Agents — Call agents inside @workflow
|
||||
|
||||
This sample shows how to call agents inside a functional workflow.
|
||||
Agent calls are just regular async function calls — no special wrappers needed.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import Agent, workflow
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from azure.identity import AzureCliCredential
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load environment variables from .env file (e.g., FOUNDRY_PROJECT_ENDPOINT, FOUNDRY_MODEL)
|
||||
load_dotenv()
|
||||
|
||||
# <create_agents>
|
||||
client = FoundryChatClient(credential=AzureCliCredential())
|
||||
|
||||
writer = Agent(
|
||||
name="WriterAgent",
|
||||
instructions="Write a short poem (4 lines max) about the given topic.",
|
||||
client=client,
|
||||
)
|
||||
|
||||
reviewer = Agent(
|
||||
name="ReviewerAgent",
|
||||
instructions="Review the given poem in one sentence. Is it good?",
|
||||
client=client,
|
||||
)
|
||||
# </create_agents>
|
||||
|
||||
|
||||
# <create_workflow>
|
||||
@workflow
|
||||
async def poem_workflow(topic: str) -> str:
|
||||
"""Write a poem, then review it."""
|
||||
poem = (await writer.run(f"Write a poem about: {topic}")).text
|
||||
review = (await reviewer.run(f"Review this poem: {poem}")).text
|
||||
return f"Poem:\n{poem}\n\nReview: {review}"
|
||||
|
||||
|
||||
# </create_workflow>
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
result = await poem_workflow.run("a cat learning to code")
|
||||
print(result.get_outputs()[0])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,59 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""
|
||||
Functional Workflow Basics — Orchestrate async functions with @workflow
|
||||
|
||||
The functional API lets you write workflows as plain Python async functions.
|
||||
No graph concepts, no edges, no executor classes — just call functions
|
||||
and use native control flow (if/else, loops, asyncio.gather).
|
||||
|
||||
This sample builds a minimal pipeline with two steps:
|
||||
1. Convert text to uppercase
|
||||
2. Reverse the text
|
||||
|
||||
No external services are required.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import workflow
|
||||
|
||||
|
||||
# Plain async functions — no decorators needed
|
||||
async def to_upper_case(text: str) -> str:
|
||||
"""Convert input to uppercase."""
|
||||
return text.upper()
|
||||
|
||||
|
||||
async def reverse_text(text: str) -> str:
|
||||
"""Reverse the string."""
|
||||
return text[::-1]
|
||||
|
||||
|
||||
# <create_workflow>
|
||||
@workflow
|
||||
async def text_workflow(text: str) -> str:
|
||||
"""Uppercase the text, then reverse it."""
|
||||
upper = await to_upper_case(text)
|
||||
return await reverse_text(upper)
|
||||
|
||||
|
||||
# </create_workflow>
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# <run_workflow>
|
||||
result = await text_workflow.run("hello world")
|
||||
print(f"Output: {result.get_outputs()}")
|
||||
print(f"Final state: {result.get_final_state()}")
|
||||
# </run_workflow>
|
||||
|
||||
"""
|
||||
Expected output:
|
||||
Output: ['DLROW OLLEH']
|
||||
Final state: WorkflowRunState.IDLE
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,73 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import (
|
||||
Executor,
|
||||
WorkflowBuilder,
|
||||
WorkflowContext,
|
||||
executor,
|
||||
handler,
|
||||
)
|
||||
from typing_extensions import Never
|
||||
|
||||
"""
|
||||
First Graph Workflow — Chain executors with edges
|
||||
|
||||
The graph API gives you full control over execution topology: edges,
|
||||
fan-out/fan-in, switch/case, and superstep-based checkpointing.
|
||||
|
||||
This sample builds a minimal graph workflow with two steps:
|
||||
1. Convert text to uppercase (class-based executor)
|
||||
2. Reverse the text (function-based executor)
|
||||
|
||||
No external services are required.
|
||||
"""
|
||||
|
||||
|
||||
# <create_workflow>
|
||||
# Step 1: A class-based executor that converts text to uppercase
|
||||
class UpperCase(Executor):
|
||||
def __init__(self, id: str):
|
||||
super().__init__(id=id)
|
||||
|
||||
@handler
|
||||
async def to_upper_case(self, text: str, ctx: WorkflowContext[str]) -> None:
|
||||
"""Convert input to uppercase and forward to the next node."""
|
||||
await ctx.send_message(text.upper())
|
||||
|
||||
|
||||
# Step 2: A function-based executor that reverses the string and yields output
|
||||
@executor(id="reverse_text")
|
||||
async def reverse_text(text: str, ctx: WorkflowContext[Never, str]) -> None:
|
||||
"""Reverse the string and yield the final workflow output."""
|
||||
await ctx.yield_output(text[::-1])
|
||||
|
||||
|
||||
def create_workflow():
|
||||
"""Build the workflow: UpperCase → reverse_text."""
|
||||
upper = UpperCase(id="upper_case")
|
||||
return WorkflowBuilder(start_executor=upper).add_edge(upper, reverse_text).build()
|
||||
|
||||
|
||||
# </create_workflow>
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# <run_workflow>
|
||||
workflow = create_workflow()
|
||||
|
||||
events = await workflow.run("hello world")
|
||||
print(f"Output: {events.get_outputs()}")
|
||||
print(f"Final state: {events.get_final_state()}")
|
||||
# </run_workflow>
|
||||
|
||||
"""
|
||||
Expected output:
|
||||
Output: ['DLROW OLLEH']
|
||||
Final state: WorkflowRunState.IDLE
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,40 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
# ruff: noqa: E305
|
||||
# fmt: off
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import Agent
|
||||
from agent_framework.azure import AgentFunctionApp
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
"""Host your agent with Azure Functions.
|
||||
This sample shows the Python hosting pattern used in docs:
|
||||
- Create an agent with `FoundryChatClient`
|
||||
- Register it with `AgentFunctionApp`
|
||||
- Run with Azure Functions Core Tools (`func start`)
|
||||
Prerequisites:
|
||||
pip install agent-framework-azurefunctions --pre
|
||||
"""
|
||||
|
||||
|
||||
# <create_agent>
|
||||
def _create_agent() -> Any:
|
||||
"""Create a hosted agent backed by Azure OpenAI."""
|
||||
return Agent(
|
||||
client=FoundryChatClient(
|
||||
project_endpoint="https://your-project.services.ai.azure.com",
|
||||
model="gpt-4o",
|
||||
credential=AzureCliCredential(),
|
||||
),
|
||||
name="HostedAgent",
|
||||
instructions="You are a helpful assistant hosted in Azure Functions.",
|
||||
)
|
||||
# </create_agent>
|
||||
# <host_agent>
|
||||
app = AgentFunctionApp(agents=[_create_agent()], enable_health_check=True, max_poll_retries=50)
|
||||
# </host_agent>
|
||||
if __name__ == "__main__":
|
||||
print("Start the Functions host with: func start")
|
||||
print("Then call: POST /api/agents/HostedAgent/run")
|
||||
@@ -0,0 +1,38 @@
|
||||
# Get Started with Agent Framework for Python
|
||||
|
||||
This folder contains a progressive set of samples that introduce the core
|
||||
concepts of **Agent Framework** one step at a time.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
```bash
|
||||
pip install agent-framework
|
||||
```
|
||||
|
||||
Set the required environment variables:
|
||||
|
||||
```bash
|
||||
export FOUNDRY_PROJECT_ENDPOINT="https://your-project-endpoint"
|
||||
export FOUNDRY_MODEL="gpt-4o" # optional, defaults to gpt-4o
|
||||
```
|
||||
|
||||
## Samples
|
||||
|
||||
| # | File | What you'll learn |
|
||||
|---|------|-------------------|
|
||||
| 1 | [01_hello_agent.py](01_hello_agent.py) | Create your first agent and run it (streaming and non-streaming). |
|
||||
| 2 | [02_add_tools.py](02_add_tools.py) | Define a function tool with `@tool` and attach it to an agent. |
|
||||
| 3 | [03_multi_turn.py](03_multi_turn.py) | Keep conversation history across turns with `AgentSession`. |
|
||||
| 4 | [04_memory.py](04_memory.py) | Add dynamic context with a custom `ContextProvider`. |
|
||||
| 5 | [05_functional_workflow_with_agents.py](05_functional_workflow_with_agents.py) | Call agents inside a functional workflow. |
|
||||
| 6 | [06_functional_workflow_basics.py](06_functional_workflow_basics.py) | Write a workflow as a plain async function. |
|
||||
| 7 | [07_first_graph_workflow.py](07_first_graph_workflow.py) | Chain executors into a graph workflow with edges. |
|
||||
| 8 | [08_host_your_agent.py](08_host_your_agent.py) | Host a single agent with Azure Functions. |
|
||||
|
||||
Run any sample with:
|
||||
|
||||
```bash
|
||||
python 01_hello_agent.py
|
||||
```
|
||||
|
||||
These samples use Azure Foundry models with the Responses API. To switch providers, just replace the client, see [all providers](../02-agents/providers/README.md)
|
||||
Reference in New Issue
Block a user