diff --git a/python/packages/azurefunctions/tests/integration_tests/.env.example b/python/packages/azurefunctions/tests/integration_tests/.env.example index c11ac20e64..a8dc5d88b4 100644 --- a/python/packages/azurefunctions/tests/integration_tests/.env.example +++ b/python/packages/azurefunctions/tests/integration_tests/.env.example @@ -1,7 +1,6 @@ # Azure OpenAI Configuration AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/ AZURE_OPENAI_CHAT_DEPLOYMENT_NAME=your-deployment-name -AZURE_OPENAI_API_KEY=your-api-key-here FUNCTIONS_WORKER_RUNTIME=python RUN_INTEGRATION_TESTS=true diff --git a/python/packages/azurefunctions/tests/integration_tests/testutils.py b/python/packages/azurefunctions/tests/integration_tests/testutils.py index f9da04e4b7..75deb352bd 100644 --- a/python/packages/azurefunctions/tests/integration_tests/testutils.py +++ b/python/packages/azurefunctions/tests/integration_tests/testutils.py @@ -64,10 +64,6 @@ def _should_skip_azure_functions_integration_tests() -> tuple[bool, str]: if not deployment_name or deployment_name == "your-deployment-name": return True, "No real AZURE_OPENAI_CHAT_DEPLOYMENT_NAME provided; skipping integration tests." - api_key = os.getenv("AZURE_OPENAI_API_KEY", "").strip() - if not api_key or api_key == "your-api-key-here": - return True, "No real AZURE_OPENAI_API_KEY provided; skipping integration tests." - return False, "Integration tests enabled." diff --git a/python/samples/getting_started/azure_functions/01_single_agent/README.md b/python/samples/getting_started/azure_functions/01_single_agent/README.md index 30bf298d4d..e80750779e 100644 --- a/python/samples/getting_started/azure_functions/01_single_agent/README.md +++ b/python/samples/getting_started/azure_functions/01_single_agent/README.md @@ -10,34 +10,13 @@ This sample demonstrates how to use the Durable Extension for Agent Framework to - Managing conversation state with session identifiers, so multiple clients can interact with the agent concurrently without sharing context. -## Environment Setup +## Prerequisites -### 1. Create and activate a virtual environment - -**Windows (PowerShell):** -```powershell -python -m venv .venv -.venv\Scripts\Activate.ps1 -``` - -**Linux/macOS:** -```bash -python -m venv .venv -source .venv/bin/activate -``` - -### 2. Install dependencies - -- [Azure Functions Core Tools 4.x](https://learn.microsoft.com/azure/azure-functions/functions-run-local?tabs=windows%2Cpython%2Cv2&pivots=programming-language-python#install-the-azure-functions-core-tools) – install so you can run `func start` locally. -- [Azurite storage emulator](https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio) – install and start Azurite before launching the app (the sample uses `AzureWebJobsStorage=UseDevelopmentStorage=true`). -- Python dependencies – from this folder, run `pip install -r requirements.txt` (or the equivalent in your active virtual environment). -- Copy `local.settings.json.template` to `local.settings.json`, then update `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`, and `AZURE_OPENAI_API_KEY` so the Azure OpenAI SDK can authenticate; keep `TASKHUB_NAME` set to `default` unless you plan to change the durable task hub name. +Follow the common setup steps in `../README.md` to install tooling, configure Azure OpenAI credentials, and install the Python dependencies for this sample. ## Running the Sample -With the environment configured and the Functions host running, you can interact -with the Joker agent using the provided `demo.http` file or any HTTP client. For -example: +Send a prompt to the Joker agent: ```bash curl -X POST http://localhost:7071/api/agents/Joker/run \ @@ -45,11 +24,7 @@ curl -X POST http://localhost:7071/api/agents/Joker/run \ -d "Tell me a short joke about cloud computing." ``` -The agent responds with a JSON payload that includes the generated joke. - -## Expected Output - -When you send a POST request with plain-text input, the Functions host responds with an HTTP 202 and queues the request for the durable agent entity. A typical response body looks like the following: +Expected HTTP 202 payload: ```json { diff --git a/python/samples/getting_started/azure_functions/01_single_agent/function_app.py b/python/samples/getting_started/azure_functions/01_single_agent/function_app.py index b16bb20c68..dc1f7e8a2e 100644 --- a/python/samples/getting_started/azure_functions/01_single_agent/function_app.py +++ b/python/samples/getting_started/azure_functions/01_single_agent/function_app.py @@ -10,12 +10,12 @@ from agent_framework.azure import AzureOpenAIChatClient from agent_framework.azurefunctions import AgentFunctionApp - +from azure.identity import AzureCliCredential # 1. Instantiate the agent with the chosen deployment and instructions. def _create_agent() -> Any: """Create the Joker agent.""" - return AzureOpenAIChatClient().create_agent( + return AzureOpenAIChatClient(credential=AzureCliCredential()).create_agent( name="Joker", instructions="You are good at telling jokes.", ) diff --git a/python/samples/getting_started/azure_functions/01_single_agent/requirements.txt b/python/samples/getting_started/azure_functions/01_single_agent/requirements.txt index a9774236bb..39ad8a124f 100644 --- a/python/samples/getting_started/azure_functions/01_single_agent/requirements.txt +++ b/python/samples/getting_started/azure_functions/01_single_agent/requirements.txt @@ -1,3 +1,2 @@ agent-framework-azurefunctions azure-identity -packaging diff --git a/python/samples/getting_started/azure_functions/02_multi_agent/README.md b/python/samples/getting_started/azure_functions/02_multi_agent/README.md index a8108fcd89..e315803dc4 100644 --- a/python/samples/getting_started/azure_functions/02_multi_agent/README.md +++ b/python/samples/getting_started/azure_functions/02_multi_agent/README.md @@ -9,41 +9,13 @@ This sample demonstrates how to use the Durable Extension for Agent Framework to - Conversation management (via session IDs) for isolated interactions per agent. - Two different methods for registering agents: list-based initialization and incremental addition. -## Environment Setup +## Prerequisites -### 1. Create and activate a virtual environment - -**Windows (PowerShell):** -```powershell -python -m venv .venv -.venv\Scripts\Activate.ps1 -``` - -**Linux/macOS:** -```bash -python -m venv .venv -source .venv/bin/activate -``` - -### 2. Install dependencies - -- [Azure Functions Core Tools 4.x](https://learn.microsoft.com/azure/azure-functions/functions-run-local?tabs=windows%2Cpython%2Cv2&pivots=programming-language-python#install-the-azure-functions-core-tools) – install so you can run `func start` locally. -- [Azurite storage emulator](https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio) – install and start Azurite before launching the app; the sample expects `AzureWebJobsStorage=UseDevelopmentStorage=true`. -- Python dependencies – from this folder, run `pip install -r requirements.txt` (or use the equivalent command in your active virtual environment). - -### 3. Configure local settings - -- Copy `local.settings.json.template` to `local.settings.json`, then set the Azure OpenAI values (`AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`, and `AZURE_OPENAI_API_KEY`) so the SDK can authenticate, and keep `TASKHUB_NAME` set to `default` unless you intend to change the durable task hub name. +Complete the common environment preparation steps described in `../README.md`, including installing Azure Functions Core Tools, starting Azurite, configuring Azure OpenAI settings, and installing this sample's requirements. ## Running the Sample -With the environment setup and function app running, you can test the sample by sending HTTP requests to the different agent endpoints. - -You can use the `demo.http` file to send messages to the agents, or a command line tool like `curl` as shown below: - -### Test the Weather Agent - -Bash (Linux/macOS/WSL): +Weather agent request: ```bash curl -X POST http://localhost:7071/api/agents/WeatherAgent/run \ @@ -51,16 +23,8 @@ curl -X POST http://localhost:7071/api/agents/WeatherAgent/run \ -d '{"message": "What is the weather in Seattle?"}' ``` -PowerShell: +Expected HTTP 202 payload: -```powershell -Invoke-RestMethod -Method Post ` - -Uri http://localhost:7071/api/agents/WeatherAgent/run ` - -ContentType application/json ` - -Body '{"message": "What is the weather in Seattle?"}' -``` - -Expected response: ```json { "status": "accepted", @@ -71,9 +35,7 @@ Expected response: } ``` -### Test the Math Agent - -Bash (Linux/macOS/WSL): +Math agent request: ```bash curl -X POST http://localhost:7071/api/agents/MathAgent/run \ @@ -81,16 +43,8 @@ curl -X POST http://localhost:7071/api/agents/MathAgent/run \ -d '{"message": "Calculate a 20% tip on a $50 bill"}' ``` -PowerShell: - -```powershell -Invoke-RestMethod -Method Post ` - -Uri http://localhost:7071/api/agents/MathAgent/run ` - -ContentType application/json ` - -Body '{"message": "Calculate a 20% tip on a $50 bill"}' -``` +Expected HTTP 202 payload: -Expected response: ```json { "status": "accepted", @@ -101,21 +55,14 @@ Expected response: } ``` -### Check Health - -Bash (Linux/macOS/WSL): +Health check (optional): ```bash curl http://localhost:7071/api/health ``` -PowerShell: - -```powershell -Invoke-RestMethod -Uri http://localhost:7071/api/health -``` - Expected response: + ```json { "status": "healthy", diff --git a/python/samples/getting_started/azure_functions/02_multi_agent/function_app.py b/python/samples/getting_started/azure_functions/02_multi_agent/function_app.py index 6c1dcf9db2..4a5c47279a 100644 --- a/python/samples/getting_started/azure_functions/02_multi_agent/function_app.py +++ b/python/samples/getting_started/azure_functions/02_multi_agent/function_app.py @@ -13,7 +13,7 @@ from agent_framework.azure import AzureOpenAIChatClient from agent_framework.azurefunctions import AgentFunctionApp - +from azure.identity import AzureCliCredential logger = logging.getLogger(__name__) @@ -51,7 +51,7 @@ def calculate_tip(bill_amount: float, tip_percentage: float = 15.0) -> dict[str, # 1. Create multiple agents, each with its own instruction set and tools. -chat_client = AzureOpenAIChatClient() +chat_client = AzureOpenAIChatClient(credential=AzureCliCredential()) weather_agent = chat_client.create_agent( name="WeatherAgent", diff --git a/python/samples/getting_started/azure_functions/02_multi_agent/requirements.txt b/python/samples/getting_started/azure_functions/02_multi_agent/requirements.txt index cc22a4fec4..8aa2c75d80 100644 --- a/python/samples/getting_started/azure_functions/02_multi_agent/requirements.txt +++ b/python/samples/getting_started/azure_functions/02_multi_agent/requirements.txt @@ -1,3 +1,2 @@ agent-framework-azurefunctions -packaging azure-identity \ No newline at end of file diff --git a/python/samples/getting_started/azure_functions/03_callbacks/README.md b/python/samples/getting_started/azure_functions/03_callbacks/README.md index 6ab17ae52f..08159552ea 100644 --- a/python/samples/getting_started/azure_functions/03_callbacks/README.md +++ b/python/samples/getting_started/azure_functions/03_callbacks/README.md @@ -17,62 +17,33 @@ an HTTP API that can be polled by a web client or dashboard. ## Prerequisites -- Python 3.10+ -- [Azure Functions Core Tools 4.x](https://learn.microsoft.com/azure/azure-functions/functions-run-local?tabs=windows%2Cpython%2Cv2&pivots=programming-language-python#install-the-azure-functions-core-tools) -- [Azurite storage emulator](https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio) running locally so the sample can use `AzureWebJobsStorage=UseDevelopmentStorage=true` -- Access to an Azure OpenAI deployment with `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`, and `AZURE_OPENAI_API_KEY` configured (either in `local.settings.json` or exported in your shell) -- Dependencies from `requirements.txt` installed in your environment +Complete the shared environment setup steps in `../README.md`, including creating a virtual environment, installing dependencies, and configuring Azure OpenAI credentials and storage settings. > **Note:** The sample stores callback events in memory for simplicity. For production scenarios you > should persist events to Application Insights, Azure Storage, Cosmos DB, or another durable store. ## Running the Sample -1. Create and activate a virtual environment: +Send a prompt to the agent: - **Windows (PowerShell):** - ```powershell - python -m venv .venv - .venv\Scripts\Activate.ps1 - ``` - - **Linux/macOS:** - ```bash - python -m venv .venv - source .venv/bin/activate - ``` - -2. Install dependencies (from the repository root or this directory): - - ```powershell - pip install -r requirements.txt - ``` - -3. Copy `local.settings.json.template` to `local.settings.json` and update `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`, and `AZURE_OPENAI_API_KEY` (or export them as environment variables) for your Azure resources, making sure `TASKHUB_NAME` remains `default` unless you have changed the durable task hub name. - -4. Start the Functions host: +```bash +curl -X POST http://localhost:7071/api/agents/CallbackAgent/run \ + -H "Content-Type: application/json" \ + -d '{"message": "Tell me a short joke"}' +``` - ```powershell - func start - ``` +Poll callback telemetry (replace `` with the value from the POST response): -5. Use the [`demo.http`](./demo.http) file (VS Code REST Client) or any HTTP client to: - - Send a message to the agent: `POST /api/agents/CallbackAgent/run` - - Query callback telemetry: `GET /api/agents/CallbackAgent/callbacks/{conversationId}` - - Clear stored events: `DELETE /api/agents/CallbackAgent/callbacks/{conversationId}` +```bash +curl http://localhost:7071/api/agents/CallbackAgent/callbacks/ +``` -Example workflow after the host starts: +Reset stored events: -```text -POST /api/agents/CallbackAgent/run # send a conversation message -GET /api/agents/CallbackAgent/callbacks/test-session # inspect streaming + final events -DELETE /api/agents/CallbackAgent/callbacks/test-session # reset telemetry for the session +```bash +curl -X DELETE http://localhost:7071/api/agents/CallbackAgent/callbacks/ ``` -The GET endpoint returns an array of events captured by the callback, including timestamps, -streaming chunk previews, and the final response metadata. This makes it easy to build real-time -UI updates or audit logs on top of Durable Agents. - ## Expected Output When you call `GET /api/agents/CallbackAgent/callbacks/{conversationId}` after sending a request to the agent, diff --git a/python/samples/getting_started/azure_functions/03_callbacks/function_app.py b/python/samples/getting_started/azure_functions/03_callbacks/function_app.py index ffbb2f387a..bc510e249e 100644 --- a/python/samples/getting_started/azure_functions/03_callbacks/function_app.py +++ b/python/samples/getting_started/azure_functions/03_callbacks/function_app.py @@ -17,6 +17,7 @@ import azure.functions as func from agent_framework import AgentRunResponseUpdate from agent_framework.azure import AzureOpenAIChatClient +from azure.identity import AzureCliCredential from agent_framework.azurefunctions import AgentFunctionApp, AgentCallbackContext, AgentResponseCallbackProtocol @@ -105,7 +106,7 @@ def _build_base_event(context: AgentCallbackContext) -> dict[str, Any]: # 2. Create the agent that will emit streaming updates and final responses. -callback_agent = AzureOpenAIChatClient().create_agent( +callback_agent = AzureOpenAIChatClient(credential=AzureCliCredential()).create_agent( name="CallbackAgent", instructions=( "You are a friendly assistant that narrates actions while responding. " diff --git a/python/samples/getting_started/azure_functions/03_callbacks/requirements.txt b/python/samples/getting_started/azure_functions/03_callbacks/requirements.txt index 6ebb9ede5f..8aa2c75d80 100644 --- a/python/samples/getting_started/azure_functions/03_callbacks/requirements.txt +++ b/python/samples/getting_started/azure_functions/03_callbacks/requirements.txt @@ -1,3 +1,2 @@ agent-framework-azurefunctions -azure-identity -packaging \ No newline at end of file +azure-identity \ No newline at end of file diff --git a/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/README.md b/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/README.md index 1e2ee42b8b..9fb4a6ce93 100644 --- a/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/README.md +++ b/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/README.md @@ -9,27 +9,21 @@ preserving the conversation state between runs. - HTTP endpoints for starting the orchestration and polling for status/output ## Prerequisites -- Python 3.10+ -- [Azure Functions Core Tools 4.x](https://learn.microsoft.com/azure/azure-functions/functions-run-local?tabs=windows%2Cpython%2Cv2&pivots=programming-language-python#install-the-azure-functions-core-tools) -- [Azurite storage emulator](https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio) running locally so the sample can use `AzureWebJobsStorage=UseDevelopmentStorage=true` -- Environment variables configured: - - `AZURE_OPENAI_ENDPOINT` - - `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME` - - `AZURE_OPENAI_API_KEY` (required for key-based auth; ensure Azure CLI is logged in if you prefer token-based auth) -- Keep `TASKHUB_NAME` set to `default` unless you intend to change the durable task hub name. -- Copy `local.settings.json.template` to `local.settings.json` and populate those keys—including `AZURE_OPENAI_API_KEY`—along with any storage settings before running the Functions host. -- Install dependencies with `pip install -r requirements.txt` + +Start with the shared setup instructions in `../README.md` to create a virtual environment, install dependencies, and configure Azure OpenAI and storage settings. ## Running the Sample -1. Start the Functions host: `func start`. -2. Kick off the orchestration: - ```bash - curl -X POST http://localhost:7071/api/singleagent/run - ``` -3. Copy the `statusQueryGetUri` from the response and poll until the orchestration completes: - ```bash - curl http://localhost:7071/api/singleagent/status/ - ``` +Start the orchestration: + +```bash +curl -X POST http://localhost:7071/api/singleagent/run +``` + +Poll the returned `statusQueryGetUri` until completion: + +```bash +curl http://localhost:7071/api/singleagent/status/ +``` The orchestration first requests an inspirational sentence from the agent, then refines the initial response while keeping it under 25 words—mirroring the behaviour of the corresponding .NET sample. diff --git a/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/function_app.py b/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/function_app.py index e271082e54..2f8fa1be42 100644 --- a/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/function_app.py +++ b/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/function_app.py @@ -16,6 +16,7 @@ import azure.functions as func from agent_framework.azure import AzureOpenAIChatClient from azure.durable_functions import DurableOrchestrationContext +from azure.identity import AzureCliCredential from agent_framework.azurefunctions import AgentFunctionApp, get_agent logger = logging.getLogger(__name__) @@ -33,7 +34,7 @@ def _create_writer_agent() -> Any: "when given an improved sentence you polish it further." ) - return AzureOpenAIChatClient().create_agent( + return AzureOpenAIChatClient(credential=AzureCliCredential()).create_agent( name=WRITER_AGENT_NAME, instructions=instructions, ) diff --git a/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/requirements.txt b/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/requirements.txt index a9774236bb..8aa2c75d80 100644 --- a/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/requirements.txt +++ b/python/samples/getting_started/azure_functions/04_single_agent_orchestration_chaining/requirements.txt @@ -1,3 +1,2 @@ agent-framework-azurefunctions -azure-identity -packaging +azure-identity \ No newline at end of file diff --git a/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/README.md b/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/README.md index fc8533a3f2..266f1a1f39 100644 --- a/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/README.md +++ b/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/README.md @@ -8,30 +8,24 @@ This sample starts a Durable Functions orchestration that runs two agents in par - HTTP routes (`/api/multiagent/run` and `/api/multiagent/status/{instanceId}`) mirror the .NET sample for parity. ## Prerequisites -- Python 3.10+ -- [Azure Functions Core Tools 4.x](https://learn.microsoft.com/azure/azure-functions/functions-run-local?tabs=windows%2Cpython%2Cv2&pivots=programming-language-python#install-the-azure-functions-core-tools) -- [Azurite storage emulator](https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio) running locally so the sample can use `AzureWebJobsStorage=UseDevelopmentStorage=true` -- Environment variables configured: - - `AZURE_OPENAI_ENDPOINT` - - `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME` - - `AZURE_OPENAI_API_KEY` (required for key-based auth; ensure the Azure CLI is logged in if you rely on token-based auth) -- Keep `TASKHUB_NAME` set to `default` unless you intend to change the durable task hub name. -- Copy `local.settings.json.template` to `local.settings.json` and fill in those Azure OpenAI values—including `AZURE_OPENAI_API_KEY`—along with storage settings before starting the Functions host. -- Install dependencies with `pip install -r requirements.txt` + +Use the shared setup instructions in `../README.md` to prepare the environment, install dependencies, and configure Azure OpenAI and storage settings before running this sample. ## Running the Sample -1. Start the Functions host: `func start`. -2. Send a prompt to start the orchestration: - ```bash - curl -X POST \ - -H "Content-Type: text/plain" \ - --data "What is temperature?" \ - http://localhost:7071/api/multiagent/run - ``` -3. Poll the returned `statusQueryGetUri` until the orchestration completes: - ```bash - curl http://localhost:7071/api/multiagent/status/ - ``` +Start the orchestration: + +```bash +curl -X POST \ + -H "Content-Type: text/plain" \ + --data "What is temperature?" \ + http://localhost:7071/api/multiagent/run +``` + +Poll the returned `statusQueryGetUri` until completion: + +```bash +curl http://localhost:7071/api/multiagent/status/ +``` The orchestration launches both agents simultaneously so their domain-specific answers can be combined for the caller. diff --git a/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/function_app.py b/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/function_app.py index fe3e558364..7f05d6fcb1 100644 --- a/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/function_app.py +++ b/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/function_app.py @@ -16,6 +16,7 @@ import azure.functions as func from agent_framework.azure import AzureOpenAIChatClient from azure.durable_functions import DurableOrchestrationContext +from azure.identity import AzureCliCredential from agent_framework.azurefunctions import AgentFunctionApp, get_agent logger = logging.getLogger(__name__) @@ -27,7 +28,7 @@ # 2. Instantiate both agents that the orchestration will run concurrently. def _create_agents() -> list[Any]: - chat_client = AzureOpenAIChatClient() + chat_client = AzureOpenAIChatClient(credential=AzureCliCredential()) physicist = chat_client.create_agent( name=PHYSICIST_AGENT_NAME, diff --git a/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/requirements.txt b/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/requirements.txt index a9774236bb..8aa2c75d80 100644 --- a/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/requirements.txt +++ b/python/samples/getting_started/azure_functions/05_multi_agent_orchestration_concurrency/requirements.txt @@ -1,3 +1,2 @@ agent-framework-azurefunctions -azure-identity -packaging +azure-identity \ No newline at end of file diff --git a/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/README.md b/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/README.md index a42bd35899..db527a2b16 100644 --- a/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/README.md +++ b/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/README.md @@ -4,23 +4,28 @@ This sample evaluates incoming emails with a spam detector agent and, when appropriate, drafts a response using an email assistant agent. ## Prerequisites -- Python 3.10+ environment with dependencies from `requirements.txt` installed. -- [Azure Functions Core Tools 4.x](https://learn.microsoft.com/azure/azure-functions/functions-run-local?tabs=windows%2Cpython%2Cv2&pivots=programming-language-python#install-the-azure-functions-core-tools) available on the PATH. -- [Azurite storage emulator](https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio) running locally so the sample can use `AzureWebJobsStorage=UseDevelopmentStorage=true`. -- Environment variables `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`, and `AZURE_OPENAI_API_KEY`. -- Keep `TASKHUB_NAME` set to `default` unless you intend to change the durable task hub name. -- Copy `local.settings.json.template` to `local.settings.json` and populate those Azure OpenAI settings—including `AZURE_OPENAI_API_KEY`—along with storage values before starting the host. + +Set up the shared prerequisites outlined in `../README.md`, including the virtual environment, dependency installation, and Azure OpenAI and storage configuration. ## Scenario Overview - Two Azure OpenAI agents share a single deployment: one flags spam, the other drafts replies. - Structured responses (`is_spam` and `reason`, or `response`) determine which orchestration branch runs. - Activity functions handle the side effects of spam handling and email sending. -## Run the Sample -1. Configure the environment variables and install dependencies with `pip install -r requirements.txt`. -2. Launch the Functions host from this directory using `func start`. -3. Send an email payload to `/api/spamdetection/run` (see `demo.http`). -4. Poll the provided `statusQueryGetUri` or call `/api/spamdetection/status/{instanceId}` to monitor results. +## Running the Sample +Submit an email payload: + +```bash +curl -X POST http://localhost:7071/api/spamdetection/run \ + -H "Content-Type: application/json" \ + -d '{"subject": "Sale now on", "body": "Limited time offer"}' +``` + +Poll the returned `statusQueryGetUri` or call the status route directly: + +```bash +curl http://localhost:7071/api/spamdetection/status/ +``` ## Expected Responses - Spam payloads return `Email marked as spam: ` by invoking the `handle_spam_email` activity. diff --git a/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/function_app.py b/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/function_app.py index 0e1c1ef677..fe4e3dbd75 100644 --- a/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/function_app.py +++ b/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/function_app.py @@ -18,6 +18,7 @@ import azure.functions as func from agent_framework.azure import AzureOpenAIChatClient from azure.durable_functions import DurableOrchestrationContext +from azure.identity import AzureCliCredential from agent_framework.azurefunctions import AgentFunctionApp, get_agent from pydantic import BaseModel, ValidationError @@ -43,7 +44,7 @@ class EmailPayload(BaseModel): # 2. Instantiate both agents so they can be registered with AgentFunctionApp. def _create_agents() -> list[Any]: - chat_client = AzureOpenAIChatClient() + chat_client = AzureOpenAIChatClient(credential=AzureCliCredential()) spam_agent = chat_client.create_agent( name=SPAM_AGENT_NAME, diff --git a/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/requirements.txt b/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/requirements.txt index a9774236bb..8aa2c75d80 100644 --- a/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/requirements.txt +++ b/python/samples/getting_started/azure_functions/06_multi_agent_orchestration_conditionals/requirements.txt @@ -1,3 +1,2 @@ agent-framework-azurefunctions -azure-identity -packaging +azure-identity \ No newline at end of file diff --git a/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/README.md b/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/README.md index e47b4ffdaf..9b73ac3722 100644 --- a/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/README.md +++ b/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/README.md @@ -5,12 +5,8 @@ A single writer agent iterates on content until a human reviewer approves the output or a maximum number of attempts is reached. ## Prerequisites -- Python 3.10+ environment with the packages from `requirements.txt` installed. -- [Azure Functions Core Tools 4.x](https://learn.microsoft.com/azure/azure-functions/functions-run-local?tabs=windows%2Cpython%2Cv2&pivots=programming-language-python#install-the-azure-functions-core-tools) available on the PATH. -- [Azurite storage emulator](https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio) running locally so the sample can use `AzureWebJobsStorage=UseDevelopmentStorage=true`. -- Environment variables `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`, and `AZURE_OPENAI_API_KEY`. -- Keep `TASKHUB_NAME` set to `default` unless you intend to change the durable task hub name. -- Copy `local.settings.json.template` to `local.settings.json` and configure those keys—including `AZURE_OPENAI_API_KEY`—plus storage settings before starting the Functions host. + +Complete the common setup instructions in `../README.md` to prepare the virtual environment, install dependencies, and configure Azure OpenAI and storage settings. ## What It Shows - Identical environment variable usage (`AZURE_OPENAI_ENDPOINT`, @@ -20,12 +16,28 @@ output or a maximum number of attempts is reached. - Activity functions that encapsulate the out-of-band operations such as notifying a reviewer and publishing content. -## Run the Sample -1. Configure the environment variables and install dependencies with `pip install -r requirements.txt`. -2. Start the Functions host in this directory using `func start`. -3. Trigger the orchestration with `demo.http` (or another HTTP client) by POSTing to `/api/hitl/run`. -4. Poll the `statusQueryGetUri` or call `/api/hitl/status/{instanceId}` to monitor progress. -5. POST an approval or rejection payload to `/api/hitl/approve/{instanceId}` to complete the review loop. +## Running the Sample +Start the HITL orchestration: + +```bash +curl -X POST http://localhost:7071/api/hitl/run \ + -H "Content-Type: application/json" \ + -d '{"topic": "Write a friendly release note"}' +``` + +Poll the returned `statusQueryGetUri` or call the status route directly: + +```bash +curl http://localhost:7071/api/hitl/status/ +``` + +Approve or reject the draft: + +```bash +curl -X POST http://localhost:7071/api/hitl/approve/ \ + -H "Content-Type: application/json" \ + -d '{"approved": true, "feedback": "Looks good"}' +``` ## Expected Responses - `POST /api/hitl/run` returns a 202 Accepted payload with the Durable Functions instance ID. diff --git a/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/function_app.py b/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/function_app.py index ea120942c3..3df3dfc472 100644 --- a/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/function_app.py +++ b/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/function_app.py @@ -18,6 +18,7 @@ import azure.functions as func from agent_framework.azure import AzureOpenAIChatClient from azure.durable_functions import DurableOrchestrationContext +from azure.identity import AzureCliCredential from agent_framework.azurefunctions import AgentFunctionApp, get_agent from pydantic import BaseModel, ValidationError @@ -52,7 +53,7 @@ def _create_writer_agent() -> Any: "Return your response as JSON with 'title' and 'content' fields." ) - return AzureOpenAIChatClient().create_agent( + return AzureOpenAIChatClient(credential=AzureCliCredential()).create_agent( name=WRITER_AGENT_NAME, instructions=instructions, ) diff --git a/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/requirements.txt b/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/requirements.txt index a9774236bb..8aa2c75d80 100644 --- a/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/requirements.txt +++ b/python/samples/getting_started/azure_functions/07_single_agent_orchestration_hitl/requirements.txt @@ -1,3 +1,2 @@ agent-framework-azurefunctions -azure-identity -packaging +azure-identity \ No newline at end of file diff --git a/python/samples/getting_started/azure_functions/README.md b/python/samples/getting_started/azure_functions/README.md index 1ec9dbde3d..3839d600a0 100644 --- a/python/samples/getting_started/azure_functions/README.md +++ b/python/samples/getting_started/azure_functions/README.md @@ -1,5 +1,5 @@ -These are common starting instructions for how to set up your environment for all the samples in this directory. -These samples are for illustrating the use of the Durable extensibility to Agent Framework running in Azure Functions. +These are common instructions for setting up your environment for every sample in this directory. +These samples illustrate the Durable extensibility for Agent Framework running in Azure Functions. All of these samples are set up to run in Azure Functions. Azure Functions has a local development tool called [CoreTools](https://learn.microsoft.com/azure/azure-functions/functions-run-local?tabs=windows%2Cpython%2Cv2&pivots=programming-language-python#install-the-azure-functions-core-tools) which we will set up to run these samples locally. @@ -11,7 +11,7 @@ All of these samples are set up to run in Azure Functions. Azure Functions has a - Install [Azurite storage emulator](https://learn.microsoft.com/en-us/azure/storage/common/storage-install-azurite?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json&bc=%2Fazure%2Fstorage%2Fblobs%2Fbreadcrumb%2Ftoc.json&tabs=visual-studio%2Cblob-storage) -- Create an [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-foundry/models/openai) resource. Note the Azure OpenAI endpoint, deployment name and the Key. +- Create an [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-foundry/models/openai) resource. Note the Azure OpenAI endpoint, deployment name, and the key (or ensure you can authenticate with `AzureCliCredential`). - Install a tool to execute HTTP calls, for example the [REST Client extension](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) @@ -37,11 +37,12 @@ source .venv/bin/activate - Inside each sample: - - Install Python dependencies – from this folder, run `pip install -r requirements.txt` (or the equivalent in your active virtual environment). + - Install Python dependencies – from the sample directory, run `pip install -r requirements.txt` (or the equivalent in your active virtual environment). - - Copy `local.settings.json.template` to `local.settings.json`, then update `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`, and `AZURE_OPENAI_API_KEY` so the Azure OpenAI SDK can authenticate; keep `TASKHUB_NAME` set to `default` unless you plan to change the durable task hub name. + - Copy `local.settings.json.template` to `local.settings.json`, then update `AZURE_OPENAI_ENDPOINT` and `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME` for Azure OpenAI authentication. The samples use `AzureCliCredential` by default, so ensure you're logged in via `az login`. + - Alternatively, you can use API key authentication by setting `AZURE_OPENAI_API_KEY` and updating the code to use `AzureOpenAIChatClient()` without the credential parameter. + - Keep `TASKHUB_NAME` set to `default` unless you plan to change the durable task hub name. + - Run the command `func start` from the root of the sample -- Run the command `func start` from the root of the sample - -- Follow the specific instructions/requests for each sample + - Follow each sample's README for scenario-specific steps, and use its `demo.http` file (or provided curl examples) to trigger the hosted HTTP endpoints.