Python: Add sample for hosted agent with files (#5596)

* Add sample for hosted agent with files

* Update python/samples/04-hosting/foundry-hosted-agents/responses/06_files/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update python/samples/04-hosting/foundry-hosted-agents/responses/06_files/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update python/samples/04-hosting/foundry-hosted-agents/responses/06_files/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update python/samples/04-hosting/foundry-hosted-agents/responses/04_foundry_toolbox/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update python/samples/04-hosting/foundry-hosted-agents/responses/06_files/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Improve README

* Address comments

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Tao Chen
2026-05-01 11:40:42 -07:00
committed by GitHub
Unverified
parent c1cc6ee6df
commit 18293ffb31
21 changed files with 432 additions and 8 deletions
@@ -13,7 +13,8 @@ This directory contains samples that demonstrate how to use hosted [Agent Framew
| 3 | [MCP](responses/03_mcp/) | An agent connected to a remote MCP server (GitHub), demonstrating external MCP tool provider integration. |
| 4 | [Foundry Toolbox](responses/04_foundry_toolbox/) | An agent using Azure Foundry Toolbox, demonstrating toolbox provisioning and querying available tools at runtime. |
| 5 | [Workflows](responses/05_workflows/) | An agent with a multi-step orchestrated workflow, demonstrating chaining prompts through an orchestrated flow. |
| 6 | [Using deployed agent](responses/using_deployed_agent.py) | A sample demonstrating how to invoke an agent that has already been deployed to Foundry, showing how to interact with a hosted agent in code. |
| 6 | [Files](responses/06_files/) | An agent demonstrating how to work with files in a hosted agent session, including uploading files to a hosted agent session and having the agent read and manipulate those files at runtime. |
| 7 | [Using deployed agent](responses/using_deployed_agent.py) | A sample demonstrating how to invoke an agent that has already been deployed to Foundry, showing how to interact with a hosted agent in code. |
### Invocations API
@@ -14,6 +14,10 @@ See [main.py](main.py) for the full implementation.
The agent is hosted using the [Agent Framework](https://github.com/microsoft/agent-framework) with the `ResponsesHostServer`, which provisions a REST API endpoint compatible with the OpenAI Responses protocol.
## Running the Agent Host
Follow the instructions in the [Running the Agent Host Locally](../../README.md#running-the-agent-host-locally) section of the README in the parent directory to run the agent host.
## Interacting with the agent
> Depending on how you run the agent host, you can invoke the agent using `curl` (`Invoke-WebRequest` in PowerShell) or `azd`. Please refer to the [parent README](../../README.md) for more details. Use this README for sample queries you can send to the agent.
@@ -6,4 +6,7 @@ protocols:
version: 1.0.0
resources:
cpu: '0.25'
memory: '0.5Gi'
memory: '0.5Gi'
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
@@ -5,4 +5,7 @@ protocols:
version: 1.0.0
resources:
cpu: "0.25"
memory: 0.5Gi
memory: 0.5Gi
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
@@ -25,7 +25,7 @@ def get_weather(
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
@tool(approval_mode="always_require")
@tool(approval_mode="never_require")
def run_bash(command: str) -> str:
"""Execute a shell command locally and return stdout, stderr, and exit code."""
try:
@@ -7,5 +7,7 @@ resources:
cpu: "0.25"
memory: 0.5Gi
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
- name: GITHUB_PAT
value: ${GITHUB_PAT}
@@ -16,8 +16,6 @@ You can also create a Foundry Toolbox in the Foundry portal. Read more about it
The agent uses `FoundryChatClient` from the Agent Framework to create an OpenAI-compatible Responses client. It loads a named Foundry Toolbox via `client.get_toolbox(name)` — the toolbox is a server-side bundle of tool configurations (e.g., `code_interpreter`, `web_search`) defined in the Foundry portal or by `azd provision`. Omitting `version` resolves the toolbox's current default version at runtime.
The sample then narrows the toolbox to a subset of tool types via `select_toolbox_tools(toolbox, include_types=[...])` before handing it to the agent. This demonstrates how one toolbox can be reused across agents that each expose only the tools they need — here, the agent only sees `code_interpreter` even though the toolbox also includes `web_search`.
See [main.py](main.py) for the full implementation.
### Agent Hosting
@@ -28,6 +26,18 @@ The agent is hosted using the [Agent Framework](https://github.com/microsoft/age
Follow the instructions in the [Running the Agent Host Locally](../../README.md#running-the-agent-host-locally) section of the README in the parent directory to run the agent host.
An extra environment variable `TOOLBOX_NAME` must be set to the name of the Foundry Toolbox that the agent should load at runtime. This allows the agent host to dynamically retrieve the correct toolbox from Foundry when it starts. Run the following:
```bash
export TOOLBOX_NAME="<your-toolbox-name>"
```
Or in PowerShell:
```powershell
$env:TOOLBOX_NAME="<your-toolbox-name>"
```
## Interacting with the agent
> Depending on how you run the agent host, you can invoke the agent using `curl` (`Invoke-WebRequest` in PowerShell) or `azd`. Please refer to the [parent README](../../README.md) for more details. Use this README for sample queries you can send to the agent.
@@ -5,4 +5,9 @@ protocols:
version: 1.0.0
resources:
cpu: "0.25"
memory: 0.5Gi
memory: 0.5Gi
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
- name: TOOLBOX_NAME
value: "agent-tools"
@@ -5,4 +5,7 @@ protocols:
version: 1.0.0
resources:
cpu: "0.25"
memory: 0.5Gi
memory: 0.5Gi
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
@@ -0,0 +1,9 @@
.venv
__pycache__
*.pyc
*.pyo
*.pyd
.Python
# Local-only client tooling and sample data; not needed inside the agent image.
resources/
@@ -0,0 +1,3 @@
FOUNDRY_PROJECT_ENDPOINT="..."
AZURE_AI_MODEL_DEPLOYMENT_NAME="..."
TOOLBOX_NAME="..."
@@ -0,0 +1,16 @@
FROM python:3.12-slim
WORKDIR /app
COPY . user_agent/
WORKDIR /app/user_agent
RUN if [ -f requirements.txt ]; then \
pip install -r requirements.txt; \
else \
echo "No requirements.txt found"; \
fi
EXPOSE 8088
CMD ["python", "main.py"]
@@ -0,0 +1,115 @@
# What this sample demonstrates
An [Agent Framework](https://github.com/microsoft/agent-framework) agent that uses a local shell tool and a code interpreter tool for working with files, and hosted using the **Responses protocol**.
## How It Works
### Model Integration
The agent uses `FoundryChatClient` from the Agent Framework to create a Responses client from the project endpoint and model deployment. The agent supports both streaming (SSE events) and non-streaming (JSON) response modes.
See [main.py](main.py) for the full implementation.
### Agent Hosting
The agent is hosted using the [Agent Framework](https://github.com/microsoft/agent-framework) with the `ResponsesHostServer`, which provisions a REST API endpoint compatible with the OpenAI Responses protocol.
### Tools
This agent uses four tools:
1. **Get Current Working Directory Tool (`get_cwd`)** Returns the current working directory of the agent host process.
2. **List Files Tool (`list_files`)** Lists the files in a specified directory.
3. **Read File Tool (`read_file`)** Reads the contents of a specified file.
4. **Code Interpreter Tool (`code_interpreter`)** Allows the agent to execute Python code in a safe.
> In this sample, the filesystem tools are function tools defined in Python using the `@tool` decorator from the Agent Framework. The code interpreter tool is a managed tool provided by [Foundry Toolbox](https://learn.microsoft.com/en-us/azure/foundry/agents/how-to/tools/toolbox). Learn more about foundry toolbox integration with hosted agents with this [sample](../04_foundry_toolbox/).
## Running the Agent Host
Follow the instructions in the [Running the Agent Host Locally](../../README.md#running-the-agent-host-locally) section of the README in the parent directory to run the agent host.
An extra environment variable `TOOLBOX_NAME` must be set to the name of the Foundry Toolbox that the agent should load at runtime. This allows the agent host to dynamically retrieve the correct toolbox from Foundry when it starts. Run the following:
```bash
export TOOLBOX_NAME="<your-toolbox-name>"
```
Or in PowerShell:
```powershell
$env:TOOLBOX_NAME="<your-toolbox-name>"
```
## Interacting with the agent
> Depending on how you run the agent host, you can invoke the agent using `curl` (`Invoke-WebRequest` in PowerShell) or `azd`. Please refer to the [parent README](../../README.md) for more details. Use this README for sample queries you can send to the agent.
Send a POST request to the server with a JSON body containing an `"input"` field to interact with the agent. For example:
```bash
curl -X POST http://localhost:8088/responses -H "Content-Type: application/json" -d '{"input": "Find the quarterly report under `{cwd}/resources` and tell me the difference of revenue between q1 2026 and q1 2025?"}'
```
> When ruuning locally, it runs within the project directory, which contains the entire sample, so the `{cwd}/resources` path in the query above will allow the agent to locate the `resources` folder included with this sample and read the `contoso_q1_2026_report.txt` file from that folder.
The server will respond with a JSON object containing the response text and a response ID. You can use this response ID to continue the conversation in subsequent requests.
## Deploying the Agent to Foundry
To host the agent on Foundry, follow the instructions in the [Deploying the Agent to Foundry](../../README.md#deploying-the-agent-to-foundry) section of the README in the parent directory.
## Uploading a file to a session
Deploying the agent won't automatically upload the files included with this sample to Foundry. To make these files available to the agent at runtime, you must upload them to a [hosted agent session](https://learn.microsoft.com/azure/foundry/agents/how-to/manage-hosted-sessions). Files are tied to a specific hosted agent session, so each time you start a new session you will need to upload the files again if the agent needs access to them during that session.
After you deploy the agent to Foundry, you have two ways to interact with the agent:
1. Using `azd ai agent invoke`.
2. Through the Foundry portal.
### Using `azd ai agent invoke`
After successfully deploying the agent to Foundry, run the following command:
> You must remain in the directory where your `azd` project is initialized so that the CLI can locate the deployed agent configuration.
```bash
azd ai agent invoke "Hi!"
```
The command will invoke the agent and the server will create a new session if one does not already exist for this interaction, returning the agent's response from the hosted agent session. Run the following if you want to force a new session:
```bash
azd ai agent invoke --new-session "Hi!"
```
Run the following command to upload a file to the hosted agent session:
```bash
azd ai agent files upload -f <path-to-contoso_q1_2026_report.txt>
```
> The above command will automatically detect the last active session and upload the file to that session without requiring you to explicitly provide a session ID. It is also possible to specify a particular session ID to upload the file to a specific hosted agent session by using the `--session-id` flag. Run `azd ai agent files upload -h` to see the full list of options and flags available for the `upload` command.
Once the file is uploaded to the hosted agent session, the agent will be able to access it during that session and use it to respond to queries that reference the uploaded file.
Invoke the agent again with a query that references the uploaded file to see how it can now use the file in its responses. For example:
```bash
azd ai agent invoke "Find the quarterly report under the home directory and tell me the difference of revenue between q1 2026 and q1 2025?"
```
### Using the Foundry Portal
Similar to using the `azd` CLI, you must invoke the agent first to create a session:
![alt text](./resources/start-a-session.png)
Once the session is created, you can grab the session ID and use `azd ai agent files upload --session-id <session-id>` to upload files to that specific hosted agent session.
![alt text](./resources/session-started.png)
Or you can upload files directly through the Foundry portal by navigating to Files tab in the agent playground:
![alt text](./resources/file-upload-portal.png)
@@ -0,0 +1,32 @@
name: agent-framework-agent-files-responses
description: >
An Agent Framework agent that can work with files hosted by Foundry.
metadata:
tags:
- Agent Framework
- AI Agent Hosting
- Azure AI AgentServer
- Responses Protocol
- Streaming
template:
name: agent-framework-agent-files-responses
kind: hosted
protocols:
- protocol: responses
version: 1.0.0
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}"
- name: TOOLBOX_NAME
value: "agent-tools"
resources:
- kind: model
id: gpt-4.1-mini
name: AZURE_AI_MODEL_DEPLOYMENT_NAME
- kind: toolbox
name: agent-tools
tools:
- type: web_search
name: web_search
- type: code_interpreter
name: code_interpreter
@@ -0,0 +1,12 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/microsoft/AgentSchema/refs/heads/main/schemas/v1.0/ContainerAgent.yaml
kind: hosted
name: agent-framework-agent-files-responses
protocols:
- protocol: responses
version: 1.0.0
resources:
cpu: '0.25'
memory: '0.5Gi'
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
@@ -0,0 +1,83 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from agent_framework import Agent, tool
from agent_framework.foundry import FoundryChatClient
from agent_framework_foundry import select_toolbox_tools
from agent_framework_foundry_hosting import ResponsesHostServer
from azure.identity import DefaultAzureCredential
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
@tool(description="Get the current working directory.", approval_mode="never_require")
def get_cwd() -> str:
"""Get the current working directory."""
try:
return os.getcwd()
except Exception as e:
return f"Error getting current working directory: {e}"
@tool(description="List files in a directory.", approval_mode="never_require")
def list_files(directory: str) -> list[str]:
"""List files in a directory."""
try:
return os.listdir(directory)
except Exception as e:
return [f"Error listing files in {directory}: {e}"]
@tool(description="Read the contents of a file.", approval_mode="never_require")
def read_file(file_path: str) -> str:
"""Read the contents of a file."""
try:
with open(file_path) as f:
return f.read()
except Exception as e:
return f"Error reading file {file_path}: {e}"
async def main():
client = FoundryChatClient(
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
credential=DefaultAzureCredential(),
)
# Load the named toolbox from the Foundry project. Omitting `version`
# resolves the toolbox's current default version at runtime.
toolbox = await client.get_toolbox(os.environ["TOOLBOX_NAME"])
# The toolbox deployed has two tools: (see agent.manifest.yaml)
# - `code_interpreter`
# - `web_search`
# We only need the `code_interpreter` tool for this sample
selected_tools = select_toolbox_tools(
toolbox,
include_names=["code_interpreter"],
)
agent = Agent(
client=client,
instructions=(
"You are a friendly assistant. Keep your answers brief. "
"Make sure all mathematical calculations are performed using the code interpreter "
"instead of mental arithmetic."
),
tools=[get_cwd, list_files, read_file] + selected_tools,
# History will be managed by the hosting infrastructure, thus there
# is no need to store history by the service. Learn more at:
# https://developers.openai.com/api/reference/resources/responses/methods/create
default_options={"store": False},
)
server = ResponsesHostServer(agent)
await server.run_async()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,2 @@
agent-framework
agent-framework-foundry-hosting
@@ -0,0 +1,121 @@
Contoso Corporation
Quarterly Report — Q1 2026 (Three months ended March 31, 2026)
DISCLAIMER
This document contains fictional data for sample/demo purposes only.
Contoso is a fictional company; all figures below are fabricated.
------------------------------------------------------------
1. EXECUTIVE SUMMARY
------------------------------------------------------------
Contoso delivered a solid first quarter, with total revenue of
$1,482.6M, up 11.4% year-over-year. Growth was led by the Cloud
Services segment (+22.7% YoY) and continued double-digit expansion
in International markets. Operating margin expanded 140 basis points
to 23.8% on disciplined cost management and improved gross margin.
Key highlights:
- Revenue: $1,482.6M (YoY +11.4%)
- Gross profit: $912.0M (gross margin 61.5%)
- Operating income: $352.9M (operating margin 23.8%)
- Net income: $268.4M (net margin 18.1%)
- Diluted EPS: $1.27 (vs. $1.04 prior year)
- Free cash flow: $311.5M
- Cash & equivalents: $2,140.8M
------------------------------------------------------------
2. INCOME STATEMENT (USD millions, unaudited)
------------------------------------------------------------
Q1 2026 Q1 2025 YoY %
Revenue 1,482.6 1,330.7 +11.4%
Cost of revenue 570.6 538.9 +5.9%
Gross profit 912.0 791.8 +15.2%
Gross margin 61.5% 59.5% +200 bps
Operating expenses
Research & development 241.4 220.5 +9.5%
Sales & marketing 218.7 205.1 +6.6%
General & administrative 99.0 88.6 +11.7%
Total operating expenses 559.1 514.2 +8.7%
Operating income 352.9 277.6 +27.1%
Operating margin 23.8% 20.9% +290 bps
Other income / (expense), net 8.4 5.1
Income before taxes 361.3 282.7
Provision for income taxes 92.9 72.6
Net income 268.4 210.1 +27.7%
Diluted EPS (USD) 1.27 1.04 +22.1%
------------------------------------------------------------
3. REVENUE BY SEGMENT (USD millions)
------------------------------------------------------------
Segment Q1 2026 Q1 2025 YoY %
Cloud Services 612.4 499.1 +22.7%
Productivity Software 448.9 422.6 +6.2%
Devices & Hardware 267.0 260.4 +2.5%
Professional Services 154.3 148.6 +3.8%
Total revenue 1,482.6 1,330.7 +11.4%
------------------------------------------------------------
4. REVENUE BY GEOGRAPHY (USD millions)
------------------------------------------------------------
Region Q1 2026 Q1 2025 YoY %
North America 812.1 756.0 +7.4%
EMEA 388.5 340.2 +14.2%
Asia-Pacific 221.7 183.4 +20.9%
Latin America 60.3 51.1 +18.0%
Total revenue 1,482.6 1,330.7 +11.4%
------------------------------------------------------------
5. SELECTED BALANCE SHEET ITEMS (USD millions)
------------------------------------------------------------
Mar 31, Dec 31,
2026 2025
Cash & equivalents 2,140.8 1,902.3
Short-term investments 845.6 820.4
Accounts receivable, net 1,012.7 988.5
Total current assets 4,510.2 4,190.6
Goodwill & intangibles 2,330.1 2,338.9
Total assets 9,884.5 9,512.0
Total current liabilities 2,118.4 2,054.7
Long-term debt 1,750.0 1,750.0
Total liabilities 4,402.6 4,310.5
Total stockholders' equity 5,481.9 5,201.5
------------------------------------------------------------
6. CASH FLOW HIGHLIGHTS (USD millions)
------------------------------------------------------------
Q1 2026 Q1 2025
Net cash from operating activities 382.0 298.7
Capital expenditures (70.5) (62.1)
Free cash flow 311.5 236.6
Share repurchases (120.0) (90.0)
Dividends paid (54.2) (48.6)
------------------------------------------------------------
7. KEY OPERATING METRICS
------------------------------------------------------------
Cloud paid seats (millions) 48.6 39.7 +22.4%
Cloud net revenue retention 118% 114%
Active enterprise customers 18,420 16,905 +9.0%
Headcount (end of period) 22,140 20,610 +7.4%
------------------------------------------------------------
8. OUTLOOK — Q2 2026 GUIDANCE
------------------------------------------------------------
Revenue: $1,520M $1,560M (YoY +10% to +13%)
Operating margin: 23.5% 24.5%
Diluted EPS: $1.30 $1.36
Capital expenditures: ~$80M
Management remains confident in the full-year plan and reiterates
fiscal-year 2026 revenue growth of 1012% and operating-margin
expansion of 100150 basis points versus FY 2025.
------------------------------------------------------------
9. NOTES
------------------------------------------------------------
- All figures are unaudited and rounded to one decimal place.
- Year-over-year comparisons are versus the same period in 2025.
- "Free cash flow" is defined as net cash from operating activities
less capital expenditures, and is a non-GAAP measure.
- This sample report is intended solely for demonstration of an
agent-driven document analysis pipeline.
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB