Host and deploy on Foundry
Serve an agent or workflow with ResponsesHostServer, package it, deploy it as a Foundry hosted agent version, and call it from a client.
Before you start
- Region: Foundry hosted agents are region-limited, and an account's region is fixed when it is created. Check Microsoft's hosted agents region list. An unsupported region fails with
bad_request: Unsupported region for Foundry Hosted Agents. - Model: the project needs a deployed chat model.
- Role: creating and invoking agent versions needs a data-plane role on the project, such as Foundry User. Control-plane Owner or Contributor alone is not enough.
- Tooling: locally you only need
azure-ai-projects>=2.3.0andazure-identityto drive the deploy. Foundry installsrequirements.txtitself in a remote build.
Write main.py
ResponsesHostServer serves the Responses protocol (/responses) and a health probe on port 8088, which is the runtime contract Foundry expects. A single agent is served directly:
from agent_framework_foundry_hosting import ResponsesHostServer
from agent import create_agent
def main() -> None:
ResponsesHostServer(create_agent()).run()
if __name__ == "__main__":
main()A workflow is wrapped with as_agent() first. Passing a raw Workflow makes the host call Workflow.run(messages=...), which fails. This version also turns on process-loss recovery and allow-lists the checkpoint types; Harden an agent or workflow for AMC explains both.
from agent_framework_foundry_hosting import CheckpointStoreProvider, ResponsesHostServer
from azure.ai.agentserver.responses import ResponsesServerOptions
from workflow import build_workflow, create_agents
def main() -> None:
workflow = build_workflow(*create_agents())
server = ResponsesHostServer(
workflow.as_agent(name="contoso-content-pipeline"),
options=ResponsesServerOptions(resilient_background=True),
checkpoint_store_provider=CheckpointStoreProvider(
allowed_checkpoint_types=["workflow:Draft"],
),
)
server.run()
if __name__ == "__main__":
main()Container
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN useradd -m appuser
USER appuser
EXPOSE 8088
CMD ["python", "main.py"]Keep .env, virtual environments and the deploy script out of the image and the deploy package.
Deploy with the Python SDK
This script zips the folder, creates a new code version with a remote build, waits for it to go active, routes all traffic to it, and smoke-tests it. Each run creates a new immutable version.
import sys, tempfile, time, zipfile
from pathlib import Path
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
AgentEndpointConfig, CodeConfiguration, CodeDependencyResolution,
FixedRatioVersionSelectionRule, HostedAgentDefinition, ProtocolConfiguration,
ProtocolVersionRecord, ResponsesProtocolConfiguration, VersionSelector,
)
from azure.identity import AzureCliCredential
ENDPOINT = "<your-project-endpoint>"
MODEL_NAME = "<model-deployment-name>"
AGENT_NAME = "contoso-content-pipeline"
SOURCE_DIR = Path(__file__).parent.resolve()
EXCLUDE_PARTS = {".git", ".venv", "__pycache__", ".azure", ".env"}
EXCLUDE_NAMES = {".env", ".dockerignore", "deploy.py"}
def make_zip() -> Path:
zp = Path(tempfile.gettempdir()) / f"{AGENT_NAME}.zip"
zp.unlink(missing_ok=True)
with zipfile.ZipFile(zp, "w", zipfile.ZIP_DEFLATED) as zf:
for p in SOURCE_DIR.rglob("*"):
rel = p.relative_to(SOURCE_DIR)
if not p.is_file() or rel.name in EXCLUDE_NAMES:
continue
if any(part in EXCLUDE_PARTS for part in rel.parts):
continue
zf.write(p, rel.as_posix())
return zp
def wait_active(c, ver) -> None:
for _ in range(90):
time.sleep(10)
status = c.agents.get_version(agent_name=AGENT_NAME, agent_version=ver)["status"]
if status == "active":
return
if status in ("failed", "Failed"):
raise RuntimeError("provisioning failed")
raise TimeoutError("version never went active")
def main() -> None:
zp = make_zip()
with zp.open("rb") as code, AzureCliCredential() as cred, \
AIProjectClient(endpoint=ENDPOINT, credential=cred) as c:
created = c.agents.create_version_from_code(
agent_name=AGENT_NAME,
description="Contoso content pipeline",
definition=HostedAgentDefinition(
cpu="1", memory="2Gi",
code_configuration=CodeConfiguration(
runtime="python_3_13", entry_point=["python", "main.py"],
dependency_resolution=CodeDependencyResolution.REMOTE_BUILD),
environment_variables={
"FOUNDRY_PROJECT_ENDPOINT": ENDPOINT,
"FOUNDRY_MODEL_NAME": MODEL_NAME},
protocol_versions=[ProtocolVersionRecord(protocol="responses", version="2.0.0")],
),
code=code,
)
wait_active(c, created.version)
c.agents.update_details(
agent_name=AGENT_NAME,
agent_endpoint=AgentEndpointConfig(
version_selector=VersionSelector(version_selection_rules=[
FixedRatioVersionSelectionRule(agent_version=created.version, traffic_percentage=100)]),
protocol_configuration=ProtocolConfiguration(responses=ResponsesProtocolConfiguration()),
),
)
with c.get_openai_client(agent_name=AGENT_NAME) as oai:
r = oai.responses.create(input="Slogan for an affordable electric bike")
print("smoke test:", r.status, r.error)
if __name__ == "__main__":
sys.exit(main())| Setting | Value | Why |
|---|---|---|
runtime | python_3_13 | Agent Framework installs cleanly. Avoid python_3_14, where some wheels are missing. |
entry_point | ["python", "main.py"] | main.py starts ResponsesHostServer. |
dependency_resolution | REMOTE_BUILD | Foundry installs requirements.txt in the cloud. |
protocol_versions | responses 2.0.0 | Required by the responses 2.x runtime that process-loss recovery uses. |
cpu / memory | 1 / 2Gi | Allowed sizes are 0.5/1Gi, 1/2Gi and 2/4Gi. |
A healthy smoke test has status == "completed" and error of None. To roll back, point FixedRatioVersionSelectionRule at an earlier version. Never delete the version that is currently routed. Microsoft also documents an azd ai agent flow; the reference deployments behind this guide use the SDK path above because it is easier to run non-interactively.
Call the deployed agent from a client
This is a preview API. It is also how you read the raw stream AMC will see.
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import VersionRefIndicator
from azure.identity import DefaultAzureCredential
ENDPOINT = "<your-project-endpoint>"
AGENT_NAME = "contoso-content-pipeline"
with (DefaultAzureCredential() as cred,
AIProjectClient(endpoint=ENDPOINT, credential=cred, allow_preview=True) as project):
ver = project.agents.get(agent_name=AGENT_NAME).versions["latest"].version
session = project.agents.create_session(
agent_name=AGENT_NAME, version_indicator=VersionRefIndicator(agent_version=ver))
oai = project.get_openai_client(agent_name=AGENT_NAME)
stream = oai.responses.create(
input="Draft a launch slogan.",
stream=True,
extra_body={"agent_session_id": session.agent_session_id},
metadata={"x-ms-debug-mode-enabled": "1"},
)
for event in stream:
print(event.type)
project.agents.delete_session(agent_name=AGENT_NAME, session_id=session.agent_session_id)x-ms-debug-mode-enabled gives richer events. AMC sends the same metadata when it runs the agent.
Related
Last updated 2026-10-21