chore: import upstream snapshot with attribution
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
# Bring in the `uv` binary from a pinned Astral image. Update this tag intentionally;
|
||||
# `latest` would make rebuilds non-deterministic.
|
||||
COPY --from=ghcr.io/astral-sh/uv:0.11.6 /uv /uvx /usr/local/bin/
|
||||
|
||||
ENV UV_LINK_MODE=copy \
|
||||
UV_COMPILE_BYTECODE=1 \
|
||||
UV_PROJECT_ENVIRONMENT=/app/.venv \
|
||||
PATH="/app/.venv/bin:${PATH}"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Sync dependencies first to maximize Docker layer caching.
|
||||
COPY pyproject.toml ./
|
||||
RUN uv sync --no-install-project --no-cache
|
||||
|
||||
# Now copy the rest of the agent and finalize the environment.
|
||||
COPY . ./
|
||||
RUN uv sync --no-cache
|
||||
|
||||
EXPOSE 8088
|
||||
|
||||
CMD ["uv", "run", "--no-sync", "python", "main.py"]
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
# What this sample demonstrates
|
||||
|
||||
An [Agent Framework](https://github.com/microsoft/agent-framework) agent with a
|
||||
**Monty-backed CodeAct context provider** hosted using the **Responses protocol**.
|
||||
The model receives one tool (`execute_code`) and runs Python inside a
|
||||
[Monty](https://github.com/pydantic/monty) interpreter; the registered host
|
||||
tools (`compute`, `fetch_data`) are only reachable from inside the sandbox via
|
||||
typed `await compute(...)` calls or the generic `call_tool(...)` fallback.
|
||||
|
||||
> [!NOTE]
|
||||
> `agent-framework-monty` is an **alpha** package, so the `pyproject.toml`
|
||||
> sets `[tool.uv] prerelease = "allow"` to let `uv sync` pick up the
|
||||
> `1.0.0a*` release from PyPI.
|
||||
|
||||
## How It Works
|
||||
|
||||
### Model Integration
|
||||
|
||||
The agent uses `FoundryChatClient` to create a Responses client from the project
|
||||
endpoint and the model deployment. The agent supports both streaming (SSE
|
||||
events) and non-streaming (JSON) response modes.
|
||||
|
||||
See [main.py](main.py) for the full implementation.
|
||||
|
||||
### CodeAct context provider
|
||||
|
||||
`MontyCodeActProvider` is added to the agent via `context_providers=[...]`. On
|
||||
every run it injects:
|
||||
|
||||
- An `execute_code` tool that runs Python in the Monty interpreter.
|
||||
- Dynamic CodeAct instructions describing the available host tools and DSL.
|
||||
|
||||
The host tools (`compute`, `fetch_data`) are **not** exposed as direct agent
|
||||
tools — the model can only call them from inside `execute_code`, either as
|
||||
typed async functions (`await compute(operation="multiply", a=6, b=7)`) or via
|
||||
the generic `call_tool("compute", operation="multiply", a=6, b=7)` fallback.
|
||||
Code is type-checked against the host tool signatures using
|
||||
[ty](https://docs.astral.sh/ty/) before any tool runs.
|
||||
|
||||
OS-level access (filesystem, network, subprocess) is blocked inside the
|
||||
sandbox; the registered host tools retain full Python access.
|
||||
|
||||
### Observability
|
||||
|
||||
Agent Framework's [native OpenTelemetry instrumentation](https://learn.microsoft.com/en-us/agent-framework/agents/observability?pivots=programming-language-python) is enabled by setting these env vars in `agent.yaml` / `agent.manifest.yaml`:
|
||||
|
||||
- `ENABLE_INSTRUMENTATION=true` — turns on the framework's span/metric/log emitters.
|
||||
- `ENABLE_SENSITIVE_DATA=true` — includes prompts, tool inputs, tool outputs, and completions in telemetry. **Dev/test only.**
|
||||
|
||||
`main.py` wires Azure Monitor at startup:
|
||||
|
||||
1. Reads `APPLICATIONINSIGHTS_CONNECTION_STRING` (Foundry hosting injects this automatically for the project's attached Application Insights resource; set it yourself when running locally).
|
||||
2. Calls `azure.monitor.opentelemetry.configure_azure_monitor(connection_string=...)` to register Azure Monitor exporters with the global OTel tracer/meter/logger providers.
|
||||
3. Calls `agent_framework.observability.enable_instrumentation()` so Agent Framework emits its `invoke_agent`, `chat`, `execute_tool`, and `execute_code` spans on those providers.
|
||||
|
||||
Trace linking happens automatically: the Foundry hosting layer's incoming `Responses` request becomes the **parent span**, and every framework / tool span (including the `execute_code` invocation that runs Monty) becomes a child via OpenTelemetry context propagation since both layers share the same global tracer provider. In Application Insights you can click any operation and see the full tree from inbound HTTP all the way down to individual `compute(...)` / `fetch_data(...)` calls inside the Monty sandbox.
|
||||
|
||||
## Running the Agent Host
|
||||
|
||||
This sample uses `pyproject.toml` + `uv sync` rather than the parent
|
||||
README's `requirements.txt` flow. To run locally:
|
||||
|
||||
1. Install dependencies into a local virtual environment:
|
||||
|
||||
```bash
|
||||
uv sync
|
||||
```
|
||||
|
||||
2. Set the environment variables described in the
|
||||
[parent README](../../README.md#running-the-agent-host-locally) (Foundry
|
||||
project endpoint, model deployment, optional Application Insights), then
|
||||
start the host:
|
||||
|
||||
```bash
|
||||
uv run python main.py
|
||||
```
|
||||
|
||||
Refer to the parent README for the shared `azd` / Docker / invocation /
|
||||
deployment guidance.
|
||||
|
||||
## 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. Try queries that benefit from combining Python with multiple tool calls:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8088/responses \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"input": "Fetch all users, find the admins, then multiply the count by 7. Use a single execute_code call."}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8088/responses \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"input": "Compute the total price for one of every product in the products table. Use execute_code."}'
|
||||
```
|
||||
|
||||
The model should respond with one `execute_code` call whose code looks like:
|
||||
|
||||
```python
|
||||
users = await fetch_data(table="users")
|
||||
admins = [u for u in users if u["role"] == "admin"]
|
||||
result = await compute(operation="multiply", a=len(admins), b=7)
|
||||
print(result)
|
||||
```
|
||||
|
||||
## 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.
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
name: agent-framework-agent-monty-codeact-responses
|
||||
description: >
|
||||
An Agent Framework agent with a Monty-backed CodeAct context provider hosted by Foundry.
|
||||
metadata:
|
||||
tags:
|
||||
- Agent Framework
|
||||
- AI Agent Hosting
|
||||
- Azure AI AgentServer
|
||||
- Responses Protocol
|
||||
- CodeAct
|
||||
- Monty
|
||||
template:
|
||||
name: agent-framework-agent-monty-codeact-responses
|
||||
kind: hosted
|
||||
protocols:
|
||||
- protocol: responses
|
||||
version: 2.0.0
|
||||
environment_variables:
|
||||
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
|
||||
value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}"
|
||||
- name: ENABLE_INSTRUMENTATION
|
||||
value: "true"
|
||||
- name: ENABLE_SENSITIVE_DATA
|
||||
value: "true"
|
||||
resources:
|
||||
- kind: model
|
||||
id: gpt-4.1-mini
|
||||
name: AZURE_AI_MODEL_DEPLOYMENT_NAME
|
||||
@@ -0,0 +1,15 @@
|
||||
kind: hosted
|
||||
name: agent-framework-agent-monty-codeact-responses
|
||||
protocols:
|
||||
- protocol: responses
|
||||
version: 2.0.0
|
||||
resources:
|
||||
cpu: "0.25"
|
||||
memory: 0.5Gi
|
||||
environment_variables:
|
||||
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
|
||||
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
|
||||
- name: ENABLE_INSTRUMENTATION
|
||||
value: "true"
|
||||
- name: ENABLE_SENSITIVE_DATA
|
||||
value: "true"
|
||||
@@ -0,0 +1,92 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import os
|
||||
from typing import Annotated, Any, Literal
|
||||
|
||||
from agent_framework import Agent, tool
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from agent_framework_foundry_hosting import ResponsesHostServer
|
||||
from agent_framework_monty import MontyCodeActProvider
|
||||
from azure.identity import DefaultAzureCredential
|
||||
from dotenv import load_dotenv
|
||||
from pydantic import Field
|
||||
|
||||
# Load environment variables from .env file (no-op when injected by Foundry).
|
||||
load_dotenv()
|
||||
|
||||
|
||||
@tool(approval_mode="never_require")
|
||||
def compute(
|
||||
operation: Annotated[
|
||||
Literal["add", "subtract", "multiply", "divide"],
|
||||
Field(description="Math operation: add, subtract, multiply, or divide."),
|
||||
],
|
||||
a: Annotated[float, Field(description="First numeric operand.")],
|
||||
b: Annotated[float, Field(description="Second numeric operand.")],
|
||||
) -> float:
|
||||
"""Perform a math operation used by sandboxed code."""
|
||||
operations = {
|
||||
"add": a + b,
|
||||
"subtract": a - b,
|
||||
"multiply": a * b,
|
||||
"divide": a / b if b else float("inf"),
|
||||
}
|
||||
return operations[operation]
|
||||
|
||||
|
||||
@tool(approval_mode="never_require")
|
||||
def fetch_data(
|
||||
table: Annotated[str, Field(description="Name of the simulated table to query.")],
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Fetch simulated records from a named table."""
|
||||
data: dict[str, list[dict[str, Any]]] = {
|
||||
"users": [
|
||||
{"id": 1, "name": "Alice", "role": "admin"},
|
||||
{"id": 2, "name": "Bob", "role": "user"},
|
||||
{"id": 3, "name": "Charlie", "role": "admin"},
|
||||
],
|
||||
"products": [
|
||||
{"id": 101, "name": "Widget", "price": 9.99},
|
||||
{"id": 102, "name": "Gadget", "price": 19.99},
|
||||
],
|
||||
}
|
||||
return data.get(table, [])
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Host a Monty CodeAct agent over the Responses protocol."""
|
||||
client = FoundryChatClient(
|
||||
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
|
||||
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
credential=DefaultAzureCredential(),
|
||||
)
|
||||
|
||||
# MontyCodeActProvider injects a sandboxed `execute_code` tool into every
|
||||
# agent run, plus dynamic instructions describing the registered host tools.
|
||||
# The host tools are hidden from the model - they can only be invoked from
|
||||
# inside the sandbox (`await compute(...)` or `call_tool(...)`).
|
||||
codeact = MontyCodeActProvider(
|
||||
tools=[compute, fetch_data],
|
||||
approval_mode="never_require",
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
client=client,
|
||||
instructions=(
|
||||
"You are a friendly assistant. Use `execute_code` to combine "
|
||||
"Python control flow with the provided host tools whenever the "
|
||||
"task requires lookups, transformations, or computation."
|
||||
),
|
||||
context_providers=[codeact],
|
||||
# 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)
|
||||
server.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
[project]
|
||||
name = "agent-framework-agent-monty-codeact-responses"
|
||||
version = "0.1.0"
|
||||
description = "Foundry-hosted Agent Framework agent with a Monty-backed CodeAct context provider."
|
||||
requires-python = ">=3.12,<3.14"
|
||||
dependencies = [
|
||||
"agent-framework-foundry",
|
||||
"agent-framework-foundry-hosting>=1.0.0a260630",
|
||||
# agent-framework-monty is an alpha (1.0.0a*) release on PyPI.
|
||||
"agent-framework-monty",
|
||||
]
|
||||
|
||||
[tool.uv]
|
||||
# `agent-framework-monty` is an alpha package; allow the prerelease resolver
|
||||
# to pick up 1.0.0a* releases from PyPI.
|
||||
prerelease = "allow"
|
||||
|
||||
Reference in New Issue
Block a user