mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: restructure: Python samples into progressive 01-05 layout (#3862)
* restructure: Python samples into progressive 01-05 layout - 01-get-started/: 6 numbered steps (hello agent → hosting) - 02-agents/: all agent concept samples (tools, middleware, providers, etc.) - 03-workflows/: ALL existing workflow samples preserved as-is - 04-hosting/: azure-functions, durabletask, a2a - 05-end-to-end/: demos, evaluation, hosted agents - Old files moved to _to_delete/ for review - Added AGENTS.md with structure documentation - autogen-migration/ and semantic-kernel-migration/ preserved at root * fix: switch to AzureOpenAI Foundry, fix CI failures - Switch all 01-get-started samples to AzureOpenAIResponsesClient with Azure AI Foundry project endpoint (AZURE_AI_PROJECT_ENDPOINT + AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME + AzureCliCredential) - Add _to_delete/ and 05-end-to-end/ to pyrightconfig.samples.json excludes - Fix test paths in packages/ that referenced old getting_started/ dirs: durabletask conftest + streaming test, azurefunctions conftest, devui conftest + capture_messages + openai_sdk_integration - Fix workflow_as_agent_human_in_the_loop.py import (sibling import) - Update hosting READMEs and tool comment paths - Replace root README.md with new structure overview - Update AGENTS.md to document Azure OpenAI Foundry as default provider * cleanup: remove _to_delete folder, copy resource files to active dirs All files in _to_delete/ were either: - Exact duplicates of files in the new structure (240 files) - Same file with only comment path updates (100 files) - One import-fix diff (workflow_as_agent_human_in_the_loop.py) - One superseded minimal_sample.py Resource files (sample.pdf, countries.json, employees.pdf, weather.json) copied to 02-agents/sample_assets/ and 02-agents/resources/ since active samples reference them. * fix: address PR review comments, centralize resources, remove root duplicates - Fix type annotation in 04_memory.py (string union -> proper types) - Fix old sample paths in observability files - Fix grammar/spelling in observability samples - Move sample_assets/ and resources/ to shared/ folder - Remove 8 duplicate observability files from 02-agents root - Update resource path references in multimodal_input and provider samples * fix: update broken links from old getting_started paths to new structure - Update relative paths in READMEs: getting_started/ → 01-get-started/, 02-agents/, 03-workflows/, 04-hosting/, 05-end-to-end/ - Fix absolute GitHub URLs in package READMEs - Fix broken link in ollama package README * fix: convert absolute GitHub URLs to relative paths for link checker Absolute URLs to python/samples/ on main branch 404 until PR merges. Converted to relative paths that linkspector can verify locally. * fix: update link for handoff sample moved to orchestrations/ * fix: update chatkit-integration README path from demos/ to 05-end-to-end/ * fix: update broken links in orchestrations README to match flat directory structure
This commit is contained in:
committed by
GitHub
Unverified
parent
69dcfe31ee
commit
a2856d3b92
@@ -0,0 +1,53 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
"""
|
||||
Hello Agent — Simplest possible agent
|
||||
|
||||
This sample creates a minimal agent using AzureOpenAIResponsesClient via an
|
||||
Azure AI Foundry project endpoint, and runs it in both non-streaming and streaming modes.
|
||||
|
||||
Environment variables:
|
||||
AZURE_AI_PROJECT_ENDPOINT — Your Azure AI Foundry project endpoint
|
||||
AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME — Model deployment name (e.g. gpt-4o)
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# <create_agent>
|
||||
credential = AzureCliCredential()
|
||||
client = AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME"],
|
||||
credential=credential,
|
||||
)
|
||||
|
||||
agent = client.as_agent(
|
||||
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,61 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from random import randint
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import tool
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
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.
|
||||
|
||||
Environment variables:
|
||||
AZURE_AI_PROJECT_ENDPOINT — Your Azure AI Foundry project endpoint
|
||||
AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME — Model deployment name (e.g. gpt-4o)
|
||||
"""
|
||||
|
||||
|
||||
# <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:
|
||||
credential = AzureCliCredential()
|
||||
client = AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME"],
|
||||
credential=credential,
|
||||
)
|
||||
|
||||
# <create_agent_with_tools>
|
||||
agent = client.as_agent(
|
||||
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,51 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
"""
|
||||
Multi-Turn Conversations — Use AgentThread to maintain context
|
||||
|
||||
This sample shows how to keep conversation history across multiple calls
|
||||
by reusing the same thread object.
|
||||
|
||||
Environment variables:
|
||||
AZURE_AI_PROJECT_ENDPOINT — Your Azure AI Foundry project endpoint
|
||||
AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME — Model deployment name (e.g. gpt-4o)
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# <create_agent>
|
||||
credential = AzureCliCredential()
|
||||
client = AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME"],
|
||||
credential=credential,
|
||||
)
|
||||
|
||||
agent = client.as_agent(
|
||||
name="ConversationAgent",
|
||||
instructions="You are a friendly assistant. Keep your answers brief.",
|
||||
)
|
||||
# </create_agent>
|
||||
|
||||
# <multi_turn>
|
||||
# Create a thread to maintain conversation history
|
||||
thread = agent.get_new_thread()
|
||||
|
||||
# First turn
|
||||
result = await agent.run("My name is Alice and I love hiking.", thread=thread)
|
||||
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?", thread=thread)
|
||||
print(f"Agent: {result}")
|
||||
# </multi_turn>
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,91 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from collections.abc import MutableSequence
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import Context, ContextProvider, Message
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
"""
|
||||
Agent Memory with Context Providers
|
||||
|
||||
Context providers let you inject dynamic instructions and context into each
|
||||
agent invocation. This sample defines a simple provider that tracks the user's
|
||||
name and enriches every request with personalization instructions.
|
||||
|
||||
Environment variables:
|
||||
AZURE_AI_PROJECT_ENDPOINT — Your Azure AI Foundry project endpoint
|
||||
AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME — Model deployment name (e.g. gpt-4o)
|
||||
"""
|
||||
|
||||
|
||||
# <context_provider>
|
||||
class UserNameProvider(ContextProvider):
|
||||
"""A simple context provider that remembers the user's name."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.user_name: str | None = None
|
||||
|
||||
async def invoking(self, messages: Message | MutableSequence[Message], **kwargs: Any) -> Context:
|
||||
"""Called before each agent invocation — add extra instructions."""
|
||||
if self.user_name:
|
||||
return Context(instructions=f"The user's name is {self.user_name}. Always address them by name.")
|
||||
return Context(instructions="You don't know the user's name yet. Ask for it politely.")
|
||||
|
||||
async def invoked(
|
||||
self,
|
||||
request_messages: Message | list[Message] | None = None,
|
||||
response_messages: "Message | list[Message] | None" = None,
|
||||
invoke_exception: Exception | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Called after each agent invocation — extract information."""
|
||||
msgs = [request_messages] if isinstance(request_messages, Message) else list(request_messages or [])
|
||||
for msg in msgs:
|
||||
text = msg.text if hasattr(msg, "text") else ""
|
||||
if isinstance(text, str) and "my name is" in text.lower():
|
||||
# Simple extraction — production code should use structured extraction
|
||||
self.user_name = text.lower().split("my name is")[-1].strip().split()[0].capitalize()
|
||||
# </context_provider>
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# <create_agent>
|
||||
credential = AzureCliCredential()
|
||||
client = AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME"],
|
||||
credential=credential,
|
||||
)
|
||||
|
||||
memory = UserNameProvider()
|
||||
|
||||
agent = client.as_agent(
|
||||
name="MemoryAgent",
|
||||
instructions="You are a friendly assistant.",
|
||||
context_provider=memory,
|
||||
)
|
||||
# </create_agent>
|
||||
|
||||
thread = agent.get_new_thread()
|
||||
|
||||
# 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?", thread=thread)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Now provide the name — the provider extracts and stores it
|
||||
result = await agent.run("My name is Alice", thread=thread)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Subsequent calls are personalized
|
||||
result = await agent.run("What is 2 + 2?", thread=thread)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
print(f"[Memory] Stored user name: {memory.user_name}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,72 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import (
|
||||
Executor,
|
||||
WorkflowBuilder,
|
||||
WorkflowContext,
|
||||
executor,
|
||||
handler,
|
||||
)
|
||||
from typing_extensions import Never
|
||||
|
||||
"""
|
||||
First Workflow — Chain executors with edges
|
||||
|
||||
This sample builds a minimal 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,60 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
"""
|
||||
Host Your Agent — Minimal A2A hosting stub
|
||||
|
||||
This sample shows the pattern for exposing an agent via the Agent-to-Agent
|
||||
(A2A) protocol. It creates the agent and demonstrates how to wrap it with
|
||||
the A2A hosting layer.
|
||||
|
||||
Prerequisites:
|
||||
pip install agent-framework[a2a] --pre
|
||||
|
||||
Environment variables:
|
||||
AZURE_AI_PROJECT_ENDPOINT — Your Azure AI Foundry project endpoint
|
||||
AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME — Model deployment name (e.g. gpt-4o)
|
||||
|
||||
To run a full A2A server, see samples/04-hosting/a2a/ for a complete example.
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# <create_agent>
|
||||
credential = AzureCliCredential()
|
||||
client = AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME"],
|
||||
credential=credential,
|
||||
)
|
||||
|
||||
agent = client.as_agent(
|
||||
name="HostedAgent",
|
||||
instructions="You are a helpful assistant exposed via A2A.",
|
||||
)
|
||||
# </create_agent>
|
||||
|
||||
# <host_agent>
|
||||
# The A2A hosting integration wraps your agent behind an HTTP endpoint.
|
||||
# Import is gated so this sample can run without the a2a extra installed.
|
||||
try:
|
||||
from agent_framework.a2a import A2AAgent # noqa: F401
|
||||
|
||||
print("A2A support is available.")
|
||||
print("See samples/04-hosting/a2a/ for a runnable A2A server example.")
|
||||
except ImportError:
|
||||
print("Install a2a extras: pip install agent-framework[a2a] --pre")
|
||||
|
||||
# Quick smoke-test: run the agent locally to verify it works
|
||||
result = await agent.run("Hello! What can you do?")
|
||||
print(f"Agent: {result}")
|
||||
# </host_agent>
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,34 @@
|
||||
# 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 --pre
|
||||
```
|
||||
|
||||
Set the required environment variables:
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY="sk-..."
|
||||
export OPENAI_RESPONSES_MODEL_ID="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 `AgentThread`. |
|
||||
| 4 | [04_memory.py](04_memory.py) | Add dynamic context with a custom `ContextProvider`. |
|
||||
| 5 | [05_first_workflow.py](05_first_workflow.py) | Chain executors into a workflow with edges. |
|
||||
| 6 | [06_host_your_agent.py](06_host_your_agent.py) | Prepare your agent for A2A hosting. |
|
||||
|
||||
Run any sample with:
|
||||
|
||||
```bash
|
||||
python 01_hello_agent.py
|
||||
```
|
||||
+1
-1
@@ -17,7 +17,7 @@ Shows function calling capabilities with custom business logic.
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -17,7 +17,7 @@ Shows function calling capabilities and automatic assistant creation.
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -17,7 +17,7 @@ Shows function calling capabilities with custom business logic.
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -17,7 +17,7 @@ Shows function calling capabilities with custom business logic.
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, "The location to get the weather for."],
|
||||
+1
-1
@@ -17,7 +17,7 @@ Shows function calling capabilities and automatic assistant creation.
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -17,7 +17,7 @@ Shows function calling capabilities with custom business logic.
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -17,7 +17,7 @@ Shows function calling capabilities with custom business logic.
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -9,7 +9,7 @@ from agent_framework.mem0 import Mem0Provider
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def retrieve_company_report(company_code: str, detailed: bool) -> str:
|
||||
if company_code != "CNTS":
|
||||
+1
-1
@@ -10,7 +10,7 @@ from azure.identity.aio import AzureCliCredential
|
||||
from mem0 import AsyncMemory
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def retrieve_company_report(company_code: str, detailed: bool) -> str:
|
||||
if company_code != "CNTS":
|
||||
+1
-1
@@ -9,7 +9,7 @@ from agent_framework.mem0 import Mem0Provider
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_user_preferences(user_id: str) -> str:
|
||||
"""Mock function to get user preferences."""
|
||||
+1
-1
@@ -37,7 +37,7 @@ from redisvl.extensions.cache.embeddings import EmbeddingsCache
|
||||
from redisvl.utils.vectorize import OpenAITextVectorizer
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def search_flights(origin_airport_code: str, destination_airport_code: str, detailed: bool = False) -> str:
|
||||
"""Simulated flight-search tool to demonstrate tool memory.
|
||||
+2
-2
@@ -21,7 +21,7 @@ DevUI is a sample application that provides:
|
||||
Run a single sample directly. This demonstrates how to wrap agents and workflows programmatically without needing a directory structure:
|
||||
|
||||
```bash
|
||||
cd python/samples/getting_started/devui
|
||||
cd python/samples/02-agents/devui
|
||||
python in_memory_mode.py
|
||||
```
|
||||
|
||||
@@ -32,7 +32,7 @@ This opens your browser at http://localhost:8090 with pre-configured agents and
|
||||
Launch DevUI to discover all samples in this folder:
|
||||
|
||||
```bash
|
||||
cd python/samples/getting_started/devui
|
||||
cd python/samples/02-agents/devui
|
||||
devui
|
||||
```
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ def analyze_content(
|
||||
return f"Analyzing content for: {query}"
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def summarize_document(
|
||||
length: Annotated[str, "Desired summary length: 'brief', 'medium', or 'detailed'"] = "medium",
|
||||
+1
-1
@@ -14,7 +14,7 @@ from azure.identity.aio import AzureCliCredential
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -16,7 +16,7 @@ from agent_framework.devui import serve
|
||||
from typing_extensions import Never
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
# Tool functions for the agent
|
||||
@tool(approval_mode="never_require")
|
||||
+1
-1
@@ -101,7 +101,7 @@ async def atlantis_location_filter_middleware(
|
||||
await call_next()
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, "The location to get the weather for."],
|
||||
+1
-1
@@ -32,7 +32,7 @@ with the following configuration:
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_specials() -> Annotated[str, "Returns the specials from the menu."]:
|
||||
return """
|
||||
+1
-1
@@ -54,7 +54,7 @@ Agent Middleware Execution Order:
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -37,7 +37,7 @@ The example covers:
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -34,7 +34,7 @@ from object-oriented design patterns.
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -42,7 +42,7 @@ Key benefits of decorator approach:
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_current_time() -> str:
|
||||
"""Get the current time."""
|
||||
+1
-1
@@ -24,7 +24,7 @@ a helpful message for the user, preventing raw exceptions from reaching the end
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def unstable_data_service(
|
||||
query: Annotated[str, Field(description="The data query to execute.")],
|
||||
+1
-1
@@ -31,7 +31,7 @@ can be implemented as async functions that accept context and call_next paramete
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -30,7 +30,7 @@ This is useful for implementing security checks, rate limiting, or early exit co
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -39,7 +39,7 @@ it creates a custom async generator that yields the override message in chunks.
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -81,7 +81,7 @@ class SessionContextContainer:
|
||||
runtime_context = SessionContextContainer()
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
async def send_email(
|
||||
to: Annotated[str, Field(description="Recipient email address")],
|
||||
+1
-1
@@ -27,7 +27,7 @@ This approach shows how middleware can work together by sharing state within the
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -32,7 +32,7 @@ Key behaviors demonstrated:
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+1
-1
@@ -7,7 +7,7 @@ from agent_framework import Content, Message
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
ASSETS_DIR = Path(__file__).resolve().parent.parent / "sample_assets"
|
||||
ASSETS_DIR = Path(__file__).resolve().parents[2] / "shared" / "sample_assets"
|
||||
|
||||
|
||||
def load_sample_pdf() -> bytes:
|
||||
+1
-1
@@ -8,7 +8,7 @@ from pathlib import Path
|
||||
from agent_framework import Content, Message
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
|
||||
ASSETS_DIR = Path(__file__).resolve().parent.parent / "sample_assets"
|
||||
ASSETS_DIR = Path(__file__).resolve().parents[2] / "shared" / "sample_assets"
|
||||
|
||||
|
||||
def load_sample_pdf() -> bytes:
|
||||
+1
-1
@@ -212,7 +212,7 @@ This folder contains different samples demonstrating how to use telemetry in var
|
||||
|
||||
### Running the samples
|
||||
|
||||
1. Open a terminal and navigate to this folder: `python/samples/getting_started/observability/`. This is necessary for the `.env` file to be read correctly.
|
||||
1. Open a terminal and navigate to this folder: `python/samples/02-agents/observability/`. This is necessary for the `.env` file to be read correctly.
|
||||
2. Create a `.env` file if one doesn't already exist in this folder. Please refer to the [example file](./.env.example).
|
||||
> **Note**: You can start with just `ENABLE_INSTRUMENTATION=true` and add `OTEL_EXPORTER_OTLP_ENDPOINT` or other configuration as needed. If no exporters are configured, you can set `ENABLE_CONSOLE_EXPORTERS=true` for console output.
|
||||
3. Activate your python virtual environment, and then run `python configure_otel_providers_with_env_var.py` or others.
|
||||
+1
-1
@@ -66,7 +66,7 @@ def setup_metrics():
|
||||
set_meter_provider(meter_provider)
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
async def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+4
-4
@@ -31,16 +31,16 @@ opentelemetry-enable_instrumentation \
|
||||
--metrics_exporter otlp \
|
||||
--service_name agent_framework \
|
||||
--exporter_otlp_endpoint http://localhost:4317 \
|
||||
python samples/getting_started/observability/advanced_zero_code.py
|
||||
python python/samples/02-agents/observability/advanced_zero_code.py
|
||||
```
|
||||
(or use uv run in front when you have did the install within your uv virtual environment)
|
||||
(or use uv run in front when you've done the install within your uv virtual environment)
|
||||
|
||||
You can also set the environment variables instead of passing them as CLI arguments.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
async def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
@@ -65,7 +65,7 @@ async def run_chat_client(client: "SupportsChatGetResponse", stream: bool = Fals
|
||||
|
||||
Remarks:
|
||||
When function calling is outside the open telemetry loop
|
||||
each of the call to the model is handled as a seperate span,
|
||||
each of the call to the model is handled as a separate span,
|
||||
while when the open telemetry is put last, a single span
|
||||
is shown, which might include one or more rounds of function calling.
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ same observability setup function.
|
||||
"""
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
async def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
# ]
|
||||
# ///
|
||||
# Run with any PEP 723 compatible runner, e.g.:
|
||||
# uv run samples/getting_started/observability/agent_with_foundry_tracing.py
|
||||
# uv run python/samples/02-agents/observability/agent_with_foundry_tracing.py
|
||||
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
@@ -41,7 +41,7 @@ dotenv.load_dotenv()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
async def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+2
-2
@@ -16,7 +16,7 @@ from opentelemetry.trace.span import format_trace_id
|
||||
from pydantic import Field
|
||||
|
||||
"""
|
||||
This sample shows you can can setup telemetry for an Azure AI agent.
|
||||
This sample shows you can setup telemetry for an Azure AI agent.
|
||||
It uses the Azure AI client to setup the telemetry, this calls out to
|
||||
Azure AI for the connection string of the attached Application Insights
|
||||
instance.
|
||||
@@ -29,7 +29,7 @@ for this sample to work.
|
||||
dotenv.load_dotenv()
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
async def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
+3
-3
@@ -17,7 +17,7 @@ if TYPE_CHECKING:
|
||||
from agent_framework import SupportsChatGetResponse
|
||||
|
||||
"""
|
||||
This sample, show how you can configure observability of an application via the
|
||||
This sample shows how you can configure observability of an application via the
|
||||
`configure_otel_providers` function with environment variables.
|
||||
|
||||
When you run this sample with an OTLP endpoint or an Application Insights connection string,
|
||||
@@ -31,7 +31,7 @@ output traces, logs, and metrics to the console.
|
||||
SCENARIOS = ["client", "client_stream", "tool", "all"]
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
async def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
@@ -104,7 +104,7 @@ async def main(scenario: Literal["client", "client_stream", "tool", "all"] = "al
|
||||
# based on environment variables. See the .env.example file for the available configuration options.
|
||||
configure_otel_providers()
|
||||
|
||||
with get_tracer().start_as_current_span("Sample Scenario's", kind=trace.SpanKind.CLIENT) as current_span:
|
||||
with get_tracer().start_as_current_span("Sample Scenarios", kind=trace.SpanKind.CLIENT) as current_span:
|
||||
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
|
||||
|
||||
client = OpenAIResponsesClient()
|
||||
+2
-2
@@ -31,7 +31,7 @@ Use this approach when you need custom exporter configuration beyond what enviro
|
||||
SCENARIOS = ["client", "client_stream", "tool", "all"]
|
||||
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/02-agents/tools/function_tool_with_approval.py and samples/02-agents/tools/function_tool_with_approval_and_threads.py.
|
||||
@tool(approval_mode="never_require")
|
||||
async def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
@@ -139,7 +139,7 @@ async def main(scenario: Literal["client", "client_stream", "tool", "all"] = "al
|
||||
exporters=custom_exporters,
|
||||
)
|
||||
|
||||
with get_tracer().start_as_current_span("Sample Scenario's", kind=trace.SpanKind.CLIENT) as current_span:
|
||||
with get_tracer().start_as_current_span("Sample Scenarios", kind=trace.SpanKind.CLIENT) as current_span:
|
||||
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
|
||||
|
||||
client = OpenAIResponsesClient()
|
||||
@@ -0,0 +1,67 @@
|
||||
# Orchestration Getting Started Samples
|
||||
|
||||
## Installation
|
||||
|
||||
The orchestrations package is included when you install `agent-framework` (which pulls in all optional packages):
|
||||
|
||||
```bash
|
||||
pip install agent-framework
|
||||
```
|
||||
|
||||
Or install the orchestrations package directly:
|
||||
|
||||
```bash
|
||||
pip install agent-framework-orchestrations
|
||||
```
|
||||
|
||||
Orchestration builders are available via the `agent_framework.orchestrations` submodule:
|
||||
|
||||
```python
|
||||
from agent_framework.orchestrations import (
|
||||
SequentialBuilder,
|
||||
ConcurrentBuilder,
|
||||
HandoffBuilder,
|
||||
GroupChatBuilder,
|
||||
MagenticBuilder,
|
||||
)
|
||||
```
|
||||
|
||||
## Samples Overview
|
||||
|
||||
| Sample | File | Concepts |
|
||||
| ------------------------------------------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| Concurrent Orchestration (Default Aggregator) | [concurrent_agents.py](./concurrent_agents.py) | Fan-out to multiple agents; fan-in with default aggregator returning combined Messages |
|
||||
| Concurrent Orchestration (Custom Aggregator) | [concurrent_custom_aggregator.py](./concurrent_custom_aggregator.py) | Override aggregator via callback; summarize results with an LLM |
|
||||
| Concurrent Orchestration (Custom Agent Executors) | [concurrent_custom_agent_executors.py](./concurrent_custom_agent_executors.py) | Child executors own Agents; concurrent fan-out/fan-in via ConcurrentBuilder |
|
||||
| Group Chat with Agent Manager | [group_chat_agent_manager.py](./group_chat_agent_manager.py) | Agent-based manager using `with_orchestrator(agent=)` to select next speaker |
|
||||
| Group Chat Philosophical Debate | [group_chat_philosophical_debate.py](./group_chat_philosophical_debate.py) | Agent manager moderates long-form, multi-round debate across diverse participants |
|
||||
| Group Chat with Simple Function Selector | [group_chat_simple_selector.py](./group_chat_simple_selector.py) | Group chat with a simple function selector for next speaker |
|
||||
| Handoff (Simple) | [handoff_simple.py](./handoff_simple.py) | Single-tier routing: triage agent routes to specialists, control returns to user after each specialist response |
|
||||
| Handoff (Autonomous) | [handoff_autonomous.py](./handoff_autonomous.py) | Autonomous mode: specialists iterate independently until invoking a handoff tool using `.with_autonomous_mode()` |
|
||||
| Handoff with Code Interpreter | [handoff_with_code_interpreter_file.py](./handoff_with_code_interpreter_file.py) | Retrieve file IDs from code interpreter output in handoff workflow |
|
||||
| Magentic Workflow (Multi-Agent) | [magentic.py](./magentic.py) | Orchestrate multiple agents with Magentic manager and streaming |
|
||||
| Magentic + Human Plan Review | [magentic_human_plan_review.py](./magentic_human_plan_review.py) | Human reviews/updates the plan before execution |
|
||||
| Magentic + Checkpoint Resume | [magentic_checkpoint.py](./magentic_checkpoint.py) | Resume Magentic orchestration from saved checkpoints |
|
||||
| Sequential Orchestration (Agents) | [sequential_agents.py](./sequential_agents.py) | Chain agents sequentially with shared conversation context |
|
||||
| Sequential Orchestration (Custom Executor) | [sequential_custom_executors.py](./sequential_custom_executors.py) | Mix agents with a summarizer that appends a compact summary |
|
||||
|
||||
## Tips
|
||||
|
||||
**Magentic checkpointing tip**: Treat `MagenticBuilder.participants` keys as stable identifiers. When resuming from a checkpoint, the rebuilt workflow must reuse the same participant names; otherwise the checkpoint cannot be applied and the run will fail fast.
|
||||
|
||||
**Handoff workflow tip**: Handoff workflows maintain the full conversation history including any `Message.additional_properties` emitted by your agents. This ensures routing metadata remains intact across all agent transitions. For specialist-to-specialist handoffs, use `.add_handoff(source, targets)` to configure which agents can route to which others with a fluent, type-safe API.
|
||||
|
||||
**Sequential orchestration note**: Sequential orchestration uses a few small adapter nodes for plumbing:
|
||||
- `input-conversation` normalizes input to `list[Message]`
|
||||
- `to-conversation:<participant>` converts agent responses into the shared conversation
|
||||
- `complete` publishes the final output event (type='output')
|
||||
|
||||
These may appear in event streams (executor_invoked/executor_completed). They're analogous to concurrent's dispatcher and aggregator and can be ignored if you only care about agent activity.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
- **AzureOpenAIChatClient**: Set Azure OpenAI environment variables as documented [here](https://github.com/microsoft/agent-framework/blob/main/python/samples/02-agents/chat_client/README.md#environment-variables).
|
||||
|
||||
- **OpenAI** (used in some orchestration samples):
|
||||
- [OpenAIChatClient env vars](https://github.com/microsoft/agent-framework/blob/main/python/samples/02-agents/providers/openai/README.md)
|
||||
- [OpenAIResponsesClient env vars](https://github.com/microsoft/agent-framework/blob/main/python/samples/02-agents/providers/openai/README.md)
|
||||
+4
-10
@@ -1,11 +1,10 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import Message
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
from agent_framework.azure import AzureOpenAIChatClient
|
||||
from agent_framework.orchestrations import ConcurrentBuilder
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
@@ -23,19 +22,14 @@ Demonstrates:
|
||||
- Workflow completion when idle with no pending work
|
||||
|
||||
Prerequisites:
|
||||
- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint.
|
||||
- Azure OpenAI access configured for AzureOpenAIResponsesClient (use az login + env vars)
|
||||
- Azure OpenAI access configured for AzureOpenAIChatClient (use az login + env vars)
|
||||
- Familiarity with Workflow events (WorkflowEvent)
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# 1) Create three domain agents using AzureOpenAIResponsesClient
|
||||
client = AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
# 1) Create three domain agents using AzureOpenAIChatClient
|
||||
client = AzureOpenAIChatClient(credential=AzureCliCredential())
|
||||
|
||||
researcher = client.as_agent(
|
||||
instructions=(
|
||||
+7
-13
@@ -1,7 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import (
|
||||
@@ -13,7 +12,7 @@ from agent_framework import (
|
||||
WorkflowContext,
|
||||
handler,
|
||||
)
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
from agent_framework.azure import AzureOpenAIChatClient
|
||||
from agent_framework.orchestrations import ConcurrentBuilder
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
@@ -26,22 +25,21 @@ and emit AgentExecutorResponse outputs, which allows reuse of the high-level
|
||||
ConcurrentBuilder API and the default aggregator.
|
||||
|
||||
Demonstrates:
|
||||
- Executors that create their Agent in __init__ (via AzureOpenAIResponsesClient)
|
||||
- Executors that create their Agent in __init__ (via AzureOpenAIChatClient)
|
||||
- A @handler that converts AgentExecutorRequest -> AgentExecutorResponse
|
||||
- ConcurrentBuilder(participants=[...]) to build fan-out/fan-in
|
||||
- Default aggregator returning list[Message] (one user + one assistant per agent)
|
||||
- Workflow completion when all participants become idle
|
||||
|
||||
Prerequisites:
|
||||
- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint.
|
||||
- Azure OpenAI configured for AzureOpenAIResponsesClient (az login + required env vars)
|
||||
- Azure OpenAI configured for AzureOpenAIChatClient (az login + required env vars)
|
||||
"""
|
||||
|
||||
|
||||
class ResearcherExec(Executor):
|
||||
agent: Agent
|
||||
|
||||
def __init__(self, client: AzureOpenAIResponsesClient, id: str = "researcher"):
|
||||
def __init__(self, client: AzureOpenAIChatClient, id: str = "researcher"):
|
||||
self.agent = client.as_agent(
|
||||
instructions=(
|
||||
"You're an expert market and product researcher. Given a prompt, provide concise, factual insights,"
|
||||
@@ -61,7 +59,7 @@ class ResearcherExec(Executor):
|
||||
class MarketerExec(Executor):
|
||||
agent: Agent
|
||||
|
||||
def __init__(self, client: AzureOpenAIResponsesClient, id: str = "marketer"):
|
||||
def __init__(self, client: AzureOpenAIChatClient, id: str = "marketer"):
|
||||
self.agent = client.as_agent(
|
||||
instructions=(
|
||||
"You're a creative marketing strategist. Craft compelling value propositions and target messaging"
|
||||
@@ -81,7 +79,7 @@ class MarketerExec(Executor):
|
||||
class LegalExec(Executor):
|
||||
agent: Agent
|
||||
|
||||
def __init__(self, client: AzureOpenAIResponsesClient, id: str = "legal"):
|
||||
def __init__(self, client: AzureOpenAIChatClient, id: str = "legal"):
|
||||
self.agent = client.as_agent(
|
||||
instructions=(
|
||||
"You're a cautious legal/compliance reviewer. Highlight constraints, disclaimers, and policy concerns"
|
||||
@@ -99,11 +97,7 @@ class LegalExec(Executor):
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
client = AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
client = AzureOpenAIChatClient(credential=AzureCliCredential())
|
||||
|
||||
researcher = ResearcherExec(client)
|
||||
marketer = MarketerExec(client)
|
||||
+7
-11
@@ -1,11 +1,10 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import Message
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
from agent_framework.azure import AzureOpenAIChatClient
|
||||
from agent_framework.orchestrations import ConcurrentBuilder
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
@@ -14,7 +13,7 @@ Sample: Concurrent Orchestration with Custom Aggregator
|
||||
|
||||
Build a concurrent workflow with ConcurrentBuilder that fans out one prompt to
|
||||
multiple domain agents and fans in their responses. Override the default
|
||||
aggregator with a custom async callback that uses AzureOpenAIResponsesClient.get_response()
|
||||
aggregator with a custom async callback that uses AzureOpenAIChatClient.get_response()
|
||||
to synthesize a concise, consolidated summary from the experts' outputs.
|
||||
The workflow completes when all participants become idle.
|
||||
|
||||
@@ -25,17 +24,12 @@ Demonstrates:
|
||||
- Workflow output yielded with the synthesized summary string
|
||||
|
||||
Prerequisites:
|
||||
- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint.
|
||||
- Azure OpenAI configured for AzureOpenAIResponsesClient (az login + required env vars)
|
||||
- Azure OpenAI configured for AzureOpenAIChatClient (az login + required env vars)
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
client = AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
client = AzureOpenAIChatClient(credential=AzureCliCredential())
|
||||
|
||||
researcher = client.as_agent(
|
||||
instructions=(
|
||||
@@ -92,7 +86,9 @@ async def main() -> None:
|
||||
# • Default aggregator -> returns list[Message] (one user + one assistant per agent)
|
||||
# • Custom callback -> return value becomes workflow output (string here)
|
||||
# The callback can be sync or async; it receives list[AgentExecutorResponse].
|
||||
workflow = ConcurrentBuilder(participants=[researcher, marketer, legal]).with_aggregator(summarize_results).build()
|
||||
workflow = (
|
||||
ConcurrentBuilder(participants=[researcher, marketer, legal]).with_aggregator(summarize_results).build()
|
||||
)
|
||||
|
||||
events = await workflow.run("We are launching a new budget-friendly electric bike for urban commuters.")
|
||||
outputs = events.get_outputs()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user