Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Deploy, evaluate, and manage AI agents end-to-end on Microsoft Azure AI Foundry
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
foundry-agent/create/create-hosted.md
1# Create Hosted Agent Application23Create new hosted agent applications for Microsoft Foundry, or convert existing agent projects to be Foundry-compatible using the hosting adapter.45## Quick Reference67| Property | Value |8|----------|-------|9| **Samples Repo** | `microsoft-foundry/foundry-samples` |10| **Python Samples** | `samples/python/hosted-agents/` |11| **C# Samples** | `samples/csharp/hosted-agents/` |12| **Hosted Agents Docs** | https://learn.microsoft.com/azure/ai-foundry/agents/concepts/hosted-agents |13| **Default Selection** | `Python` + `responses` + `Microsoft Agent Framework` |14| **Best For** | Creating new or converting existing agent projects for Foundry |1516## When to Use This Skill1718- Create a new hosted agent application from scratch (greenfield)19- Start from an official sample and customize it20- Convert an existing agent project to be Foundry-compatible (brownfield)21- Help user choose a language, protocol, framework, or sample for their agent2223## Workflow2425> Relative reference paths in this file are resolved from the directory containing `create.md`. For example, `./references/agentframework.md` means the file next to this document under `create/references/`, not a path relative to the runtime working directory.2627### Step 1: Determine Scenario2829Check the user's workspace for existing agent project indicators:3031- **No agent-related code found** → **Greenfield**. Proceed to Greenfield Workflow (Step 2).32- **Existing agent code present** → **Brownfield**. Proceed to Brownfield Workflow.3334### Step 2: Gather Requirements (Greenfield)3536If the user hasn't already specified, use `ask_user` to collect in this order:3738**Language:** Python (default) or C#.3940**Protocol:**4142| Protocol | Best For |43|----------|----------|44| `responses` (default) | Conversational agents using the OpenAI-compatible `/responses` contract |45| `invocations` | Arbitrary payloads, custom SSE behavior, protocol bridges, webhook-style callers, or client-managed sessions |46| `invocations_ws` | Real-time duplex workloads — voice agents, live streams, signaling for out-of-band media transports. The verify and adapter sections below assume HTTP — for WS specifics (URL with `agent_session_id`, browser-proxy requirement, framing), follow the dedicated [invocations-ws skill](../invocations-ws/invocations-ws.md). |4748> 💡 **Tip:** A single hosted agent can expose **multiple protocols simultaneously**. Declare each in `agent.yaml` under `protocols:` and register the matching handlers on the same `InvocationAgentServerHost` (e.g., `invocations` + `invocations_ws` to pair a control/batch HTTP path with a WebSocket path).4950**Framework:**5152The paths below refer to the framework-level directories in the Foundry sample repo. Choose the protocol-specific subpath in Step 3.5354| Framework | Python Path | C# Path |55|-----------|-------------|---------|56| Microsoft Agent Framework (default) | `agent-framework` | `agent-framework` |57| LangGraph | `bring-your-own` | ❌ Python only |58| Custom | `bring-your-own` | `bring-your-own` |5960> ⚠️ **Warning:** LangGraph is Python-only. For C# + LangGraph, suggest Microsoft Agent Framework or Custom instead.6162> 💡 **Tip:** In the sample repo, **Custom** corresponds to the **Bring Your Own** lanes.6364> 💡 **Tip:** LangGraph samples are under **Bring Your Own**, not under a separate top-level `langgraph` directory.6566If user has no specific preference, suggest Python + `responses` + Microsoft Agent Framework as defaults.6768In non-interactive or YOLO mode, default to Python + `responses` + Microsoft Agent Framework unless the user's request clearly requires another supported combination.6970### Step 3: Browse and Select Sample7172List available samples using the GitHub API. First resolve the `sample_browse_path` (the browse root) from the selected language, protocol, and framework:7374| Selection | Sample Browse Path |75|-----------|--------------------|76| Python + Microsoft Agent Framework + `responses` | `samples/python/hosted-agents/agent-framework/responses/` |77| Python + Microsoft Agent Framework + `invocations` | `samples/python/hosted-agents/agent-framework/invocations/` |78| Python + LangGraph | `samples/python/hosted-agents/bring-your-own/{protocol}/langgraph-chat/` |79| Python + Custom | `samples/python/hosted-agents/bring-your-own/{protocol}/` |80| Python + Custom + `invocations_ws` | `samples/python/hosted-agents/bring-your-own/invocations_ws/` |81| C# + Microsoft Agent Framework + `responses` | `samples/csharp/hosted-agents/agent-framework/` |82| C# + Microsoft Agent Framework + `invocations` | `samples/csharp/hosted-agents/agent-framework/invocations-echo-agent/` |83| C# + Custom | `samples/csharp/hosted-agents/bring-your-own/{protocol}/` |8485Use the chosen lane to browse the repo under `sample_browse_path`:8687```88GET https://api.github.com/repos/microsoft-foundry/foundry-samples/contents/{sample_browse_path}89```9091If the user has specified what they want the agent to do, choose the most relevant or most simple sample under that lane and record its exact `selected_sample_path`. Only if the user has not given any preferences, present the sample directories under `sample_browse_path` to the user and help them choose based on their requirements (e.g., RAG, tools, multi-agent workflows, HITL).9293If the requested combination does not have a real sample, say so clearly and suggest the nearest supported lane.9495> ⚠️ **Tools:** Hosted agents access tools through a **Foundry Toolbox MCP endpoint** — they do NOT wire tools directly. If the user wants an agent with tools (web search, AI search, code interpreter, MCP servers, etc.), select the `toolbox` samples (see [references/use-toolbox-in-hosted-agent.md#code-integration-patterns](references/use-toolbox-in-hosted-agent.md#code-integration-patterns)). These samples include Foundry Toolbox integration in the sample code out of the box, but the user still needs an actual toolbox resource — you'll resolve its endpoint in Step 6 (Verify Startup).9697### Step 4: Download Sample Files9899Download only the selected sample directory — do NOT clone the entire repo. Preserve the directory structure by creating subdirectories as needed.100101Use the exact `selected_sample_path` selected in Step 3.102103**Using `gh` CLI (preferred if available):**104```bash105gh api repos/microsoft-foundry/foundry-samples/contents/{selected_sample_path} \106--jq '.[] | select(.type=="file") | .download_url' | while read url; do107filepath="${url##*/{selected_sample_path}/}"108mkdir -p "$(dirname "$filepath")"109curl -sL "$url" -o "$filepath"110done111```112113**Using curl (fallback):**114```bash115curl -s "https://api.github.com/repos/microsoft-foundry/foundry-samples/contents/{selected_sample_path}" | \116jq -r '.[] | select(.type=="file") | .path + "\t" + .download_url' | while IFS=$'\t' read path url; do117relpath="${path#{selected_sample_path}/}"118mkdir -p "$(dirname "$relpath")"119curl -sL "$url" -o "$relpath"120done121```122123For nested directories, recursively fetch the GitHub contents API for entries where `type == "dir"` and repeat the download for each.124125### Step 5: Customize and Implement1261271. Read the sample's `README.md` and `agent.yaml` or `agent.manifest.yaml` to understand its structure1282. Read the sample code to understand patterns, protocol handling, and dependencies used1293. If using Agent Framework, follow the best practices in [references/agentframework.md](references/agentframework.md)1304. Implement the user's specific requirements on top of the sample1315. Update configuration (`.env`, dependency files, `agent.yaml`, `agent.manifest.yaml`) as needed, and keep the selected protocol consistent across code and config1326. Ensure the project is in a runnable state133134### Step 6: Verify Startup1351361. Install dependencies (use virtual environment for Python)1372. Ask user to provide values for `.env` variables if placeholders were used using `ask_user` tool.138- **If the agent uses tools / toolboxes**: resolve the toolbox endpoint per [references/use-toolbox-in-hosted-agent.md#resolve-toolbox-endpoint](references/use-toolbox-in-hosted-agent.md#resolve-toolbox-endpoint).1393. Run the main entrypoint1404. Fix startup errors and retry if needed1415. Send a protocol-appropriate test request to the correct endpoint:142- `responses` → `POST http://localhost:8088/responses`143- `invocations` → `POST http://localhost:8088/invocations`144- `invocations_ws` → open a WebSocket to `ws://localhost:8088/invocations_ws` (not HTTP POST). The wire format is developer-defined per the sample; see the [invocations-ws skill](../invocations-ws/invocations-ws.md) for the framing model and discovery guidance.1456. Fix any errors from the test request and retry until it succeeds1467. Once startup and test request succeed, stop the server to prevent resource usage147148**Guardrails:**149- ✅ Perform real run to catch startup errors150- ✅ Cleanup after verification (stop server)151- ✅ Ignore auth/connection/timeout errors (expected without Azure config)152- ❌ Don't wait for user input or create test scripts153154## Brownfield Workflow: Convert Existing Agent to Hosted Agent155156Use this workflow when the user has an existing agent project that needs to be made compatible with Foundry hosted agent deployment. The key requirement is wrapping the existing agent with the appropriate hosting adapter.157158### Step B1: Analyze Existing Project159160Scan the project to determine:1611621. **Language** — Python (look for `requirements.txt`, `pyproject.toml`, `*.py`) or C# (look for `*.csproj`, `*.cs`)1632. **Framework** — Identify which agent framework is in use:164165| Indicator | Framework |166|-----------|-----------|167| Imports from `agent_framework` or `Microsoft.Agents.AI` | Microsoft Agent Framework |168| Imports from `langgraph`, `langchain` | LangGraph |169| No recognized framework imports, or other frameworks (e.g., Semantic Kernel, AutoGen, custom code) | Custom |1701713. **Target protocol** — If the user has not specified one, infer whether the project should target `responses`, `invocations`, or `invocations_ws` based on the existing caller contract (HTTP request/response → `responses` or `invocations`; long-lived duplex stream / real-time media → `invocations_ws`)1724. **Entry point** — Identify the main script/entrypoint that creates and runs the agent1735. **Agent object** — Identify the agent instance that needs to be wrapped (e.g., a `BaseAgent` subclass, a compiled `StateGraph`, or an existing server/app)174175### Step B2: Add Hosting Adapter Dependency176177Add the correct adapter package based on framework, language, and protocol. Get the latest version from the package registry — do not hardcode versions.178179**Python adapter packages:**180181| Framework | Package(s) |182|-----------|------------|183| Microsoft Agent Framework | `responses`: `agent-framework-foundry-hosting`; `invocations`: `agent-framework-foundry-hosting` |184| LangGraph | `responses`: `azure-ai-agentserver-responses` + `azure-ai-agentserver-core`; `invocations`: `azure-ai-agentserver-invocations` + `azure-ai-agentserver-core` |185| Custom | `responses`: `azure-ai-agentserver-responses`; `invocations`: `azure-ai-agentserver-invocations` |186187**.NET adapter packages:**188189| Framework | Package(s) |190|-----------|------------|191| Microsoft Agent Framework | `responses`: `Microsoft.Agents.AI.Foundry.Hosting`; `invocations`: `Microsoft.Agents.AI.Foundry.Hosting` + `Azure.AI.AgentServer.Invocations` |192| Custom | `responses`: `Azure.AI.AgentServer.Responses`; `invocations`: `Azure.AI.AgentServer.Invocations` |193194Add the package to the project's dependency file (`requirements.txt`, `pyproject.toml`, or `.csproj`). For Python, also add `python-dotenv` if not present.195196### Step B3: Wrap Agent with Hosting Adapter197198Modify the project's main entrypoint to wrap the existing agent with the adapter. The approach differs by framework and protocol:199200**Microsoft Agent Framework + `responses` (Python):**201- Import `ResponsesHostServer` from the adapter package202- Pass the agent instance (from `agent_framework` package) to the adapter203- Call `.run()` on the adapter as the default entrypoint204205**Microsoft Agent Framework + `invocations` (Python):**206- Use `InvocationAgentServerHost()`207- Implement an `@app.invoke_handler`208- Manage session state if the agent needs multi-turn memory209210**Microsoft Agent Framework + `responses` (C#):**211- Register Foundry responses hosting and map the `responses` protocol212213**Microsoft Agent Framework + `invocations` (C#):**214- Register invocations services and an invocation handler215- Map the `invocations` protocol216217**LangGraph:**218- Python only219- Follow the `bring-your-own/{protocol}/langgraph-chat` sample for the selected protocol lane220221**Custom:**222- Follow the corresponding `bring-your-own/{protocol}` sample for the selected language223- Prefer the protocol SDK sample for the selected lane instead of inventing a custom contract when a sample already exists224225**`invocations_ws`:**226- Use the `azure-ai-agentserver-invocations` SDK and register a WebSocket handler with `@app.ws_handler` on the same `InvocationAgentServerHost`227- Follow the [invocations-ws skill](../invocations-ws/invocations-ws.md) for the wire-level contract and `agent_session_id` semantics228- Reference samples live under `samples/python/hosted-agents/bring-your-own/invocations_ws/`229230> ⚠️ **Warning:** The adapter MUST be the default entrypoint (no flags required to start). This is required for both local debugging and containerized deployment.231232### Step B4: Configure Environment2332341. Create or update a `.env` file with required environment variables (project endpoint, model deployment name, etc.)235- **If the agent uses tools / toolboxes**: resolve the toolbox endpoint per [references/use-toolbox-in-hosted-agent.md#resolve-toolbox-endpoint](references/use-toolbox-in-hosted-agent.md#resolve-toolbox-endpoint).2362. For Python: ensure the code uses `load_dotenv(override=False)` so Foundry-injected environment variables are available at runtime.2373. If the project uses Azure credentials: ensure Python uses `azure.identity.DefaultAzureCredential` for **local development**. In production, use `ManagedIdentityCredential`. See [auth-best-practices.md](../../references/auth-best-practices.md)238239### Step B5: Create agent.yaml240241Create an `agent.yaml` file in the project root. This file defines the agent's metadata and deployment configuration for Foundry. Required fields:242243- `name` — Unique identifier (alphanumeric + hyphens, max 63 chars)244- `description` — What the agent does245- `template.kind` — Must be `hosted`246- `template.protocols` — Must include the selected protocol and matching version from the chosen sample247- `template.environment_variables` — List all environment variables the agent needs at runtime248249Refer to the chosen sample's `agent.yaml` or `agent.manifest.yaml` in the [foundry-samples repo](https://github.com/microsoft-foundry/foundry-samples/tree/main/samples/python/hosted-agents) for the exact schema.250251### Step B6: Create Dockerfile252253Create a `Dockerfile` if one doesn't exist. Requirements:254255- Base image appropriate for the language (e.g., `python:3.12-slim` for Python, `mcr.microsoft.com/dotnet/sdk` for C#)256- Copy source code into the container257- Install dependencies258- Expose port **8088** (the adapter's default port)259- Set the main entrypoint as the CMD260261> ⚠️ **Warning:** When building, MUST use `--platform linux/amd64`. Hosted agents run on Linux AMD64 infrastructure. Images built for other architectures (e.g., ARM64 on Apple Silicon) will fail.262263Refer to the chosen sample's `Dockerfile` in the [foundry-samples repo](https://github.com/microsoft-foundry/foundry-samples/tree/main/samples/python/hosted-agents) for the exact pattern.264265### Step B7: Test Locally2662671. Install dependencies (use virtual environment for Python)2682. Run the main entrypoint — the adapter should start an HTTP server on `localhost:8088`2693. Send a protocol-appropriate test request:270- `responses` → `POST /responses`271- `invocations` → `POST /invocations`272- `invocations_ws` → open a WebSocket to `ws://localhost:8088/invocations_ws` (see the [invocations-ws skill](../invocations-ws/invocations-ws.md) for framing)2734. Verify the response follows the expected protocol shape for the selected lane2745. Fix any errors and retry until the test request succeeds2756. Stop the server276277> 💡 **Tip:** If auth/connection errors occur for Azure services, that's expected without real Azure credentials configured. The key validation is that the HTTP server starts and accepts requests.278279## Common Guidelines280281IMPORTANT: YOU MUST FOLLOW THESE.282283Apply these to both greenfield and brownfield projects:2842851. **Sample-first** — Start from a real sample in the current `foundry-samples` repo. Do not invent unsupported combinations, paths, or protocol behavior.2862872. **Protocol consistency** — Keep the selected protocol consistent across sample choice, code, config, and verification steps.2882893. **Logging** — Implement proper logging using the language's standard logging framework (Python `logging` module, .NET `ILogger`). Hosted agents stream container stdout/stderr logs to Foundry, so all log output is visible via the troubleshoot workflow. Use structured log levels (INFO, WARNING, ERROR) and include context like request IDs and agent names.2902914. **Framework-specific best practices** — When using Microsoft Agent Framework, read the [Agent Framework best practices](references/agentframework.md) for hosting adapter setup, credential patterns, and debugging guidance.2922935. **Deploy handoff** — After the agent has been created and local verification succeeds, explicitly tell the user that they can deploy the agent if they want, and ask them to say `deploy agent to foundry` to continue with the deploy sub-skill.2942956. **Tool integration** — Hosted agents access tools through [Foundry Toolbox](references/use-toolbox-in-hosted-agent.md), NOT by wiring tools directly. If the user needs tools (web search, AI search, code execution, file search, MCP servers, etc.), follow the toolbox integration guide. The toolbox provides a single MCP-compatible endpoint that handles credential injection and tool discovery.2962977. **Reserved environment variables** — The Foundry platform injects environment variables into every hosted agent container at startup. You MUST NOT generate, suggest, or configure any of these in `.env` files, `agent.yaml` `environment_variables`, or application code:298299**Blocked prefixes** (any variable starting with these is reserved):300- `FOUNDRY_*` — platform-injected identity, session, project, and toolset variables301- `AGENT_*` — reserved for platform use302303**Exact reserved names** (platform-managed, overwritten at runtime):304- `PORT` — HTTP listen port (default `8088`)305- `HOME` — session filesystem path (`/home/session`)306- `SSE_KEEPALIVE_INTERVAL` — SSE keep-alive config307- `APPLICATIONINSIGHTS_CONNECTION_STRING` — observability308- `OTEL_EXPORTER_OTLP_ENDPOINT` — OTLP collector endpoint309310**Key `FOUNDRY_*` variables available at runtime** (read-only, do not set):311- `FOUNDRY_PROJECT_ENDPOINT` — project endpoint URL for calling Azure services312- `FOUNDRY_AGENT_NAME` — the deployed agent's name313- `FOUNDRY_AGENT_VERSION` — the deployed agent's version314- `FOUNDRY_TOOLBOX_ENDPOINT` — MCP-compatible toolbox endpoint (if toolbox is configured)315316If user code needs to read these values at runtime (e.g., `FOUNDRY_PROJECT_ENDPOINT` to call Azure services), read them from the environment — do not set or override them.317318## Coding Tips319320Use these when generating or modifying project code:3213221. **Create a `.gitignore` file** — After generating code, create a `.gitignore` file if one does not already exist. If one already exists, update it as needed.323- Choose the ignore entries based on the language, framework, and files generated.324- Do not leave the project with no ignored files.325- For Python projects, `.venv/` MUST be ignored at a minimum.326327## Non-Interactive / YOLO Mode328329When running in non-interactive mode (e.g., YOLO mode), skip selection prompts and use these defaults unless the user has already specified otherwise:330331- **Language** — `Python`332- **Protocol** — `responses`333- **Framework** — `Microsoft Agent Framework`334335If the user's request clearly requires another supported lane, use that lane instead of forcing the defaults.336337## Error Handling338339| Error | Cause | Resolution |340|-------|-------|------------|341| GitHub API rate limit | Too many requests | Authenticate with `gh auth login` |342| `gh` not available | CLI not installed | Use curl REST API fallback |343| Sample not found | Path changed in repo or selected lane has no matching sample | List the selected parent directory again and choose a current sample |344| Requested combination not supported | Example: C# + LangGraph | Explain the gap and switch to the nearest supported lane |345| Protocol mismatch | Code, `agent.yaml`, and test request are not aligned | Make all three match the selected protocol |346| Dependency install fails | Version conflicts | Use versions from the selected sample's own dependency file |347