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/deploy/references/direct-code-deployment.md
1# Direct Code Deployment Reference23Use this reference only when the user explicitly requested direct code deployment.45This reference covers only direct-code deployment from [deploy.md](../deploy.md) Step 3. After deployment completes, proceed directly back to [deploy.md Step 7: Test the Agent](../deploy.md#step-7-test-the-agent).67Direct-code deployment uses local project files plus the Foundry REST API for upload and version operations. Azure MCP discovery and context lookup are optional context, not a prerequisite when project endpoint, model deployment, and agent name are already resolved. For the code upload itself, follow the REST endpoints below instead of the Docker/ACR `agent_update` path.89## Task 1: Preflight1011Resolve the project endpoint from project context, `.env`, `azd env get-values`, or the user. The endpoint must look like:1213```text14https://<account>.services.ai.azure.com/api/projects/<project>15```1617Every direct-code REST call must use:1819```http20Foundry-Features: CodeAgents=V1Preview,HostedAgents=V1Preview21```2223This includes create/update/create-version, version polling, version listing, code download, and delete calls.2425Get the token for this resource. Do not use the Cognitive Services token resource for direct-code REST calls:2627```text28https://ai.azure.com29```3031Direct-code REST caller prerequisite: the signed-in user or service principal must have `Azure AI User` or a higher role on the Foundry project.3233Global direct-code limits:3435- Agent name: at most 63 characters, alphanumeric and hyphens only.36- Multipart upload zip: at most 250 MB.37- CPU/memory: use conservative defaults such as `0.5` CPU and `1Gi` when the project does not specify resources.3839## Task 2: Detect Runtime and Entry Point4041Scan only the selected agent root.4243| Project Type | Detection | Runtime | Entry point |44|--------------|-----------|---------|-------------|45| Python | `main.py` plus `requirements.txt` | `python_3_13` or `python_3_14` | `["python", "main.py"]` |46| C#/.NET | exactly one `*.csproj` or user-selected project file | `dotnet_8`, `dotnet_9`, or `dotnet_10` | `["dotnet", "<AssemblyName>.dll"]` |4748For Python, prefer a supported runtime explicitly declared in `agent.yaml`/`agent.manifest.yaml` or provided by the user. If none is declared, use `python_3_13`. Do not use `python_3_11` or `python_3_12` for this preview path; if a manifest declares either one, warn and choose `python_3_13` unless the user selects another supported runtime.4950For .NET, derive the runtime from the project `TargetFramework`:5152| TargetFramework | Runtime |53|-----------------|---------|54| `net8.0` | `dotnet_8` |55| `net9.0` | `dotnet_9` |56| `net10.0` | `dotnet_10` |5758If the target framework is missing or does not map to a supported runtime, ask instead of guessing.5960For .NET, derive `<AssemblyName>` from `<AssemblyName>` in the `.csproj` when present; otherwise use the `.csproj` file stem. Never use `["dotnet", "run", ...]` for direct code deployment. The runtime environment has the .NET runtime, not the SDK, and `dotnet run` fails with `No .NET SDKs were found`.6162## Task 3: Collect Direct-Code Configuration6364Ask only for values not already resolved:6566- `projectEndpoint`67- `agentName` - prefer `agent.yaml` or `agent.manifest.yaml` name, then folder name68- model deployment environment variable, usually `AZURE_AI_MODEL_DEPLOYMENT_NAME`69- CPU and memory - prefer `agent.yaml` resources, otherwise use conservative defaults (`0.5` CPU, `1Gi` memory)70- protocol/version - prefer `agent.yaml` protocols, otherwise `responses` `1.0.0`7172Do not put `FOUNDRY_PROJECT_ENDPOINT` in `environment_variables`; the platform injects it for hosted agents. Include only custom variables that the agent code reads at runtime, such as `AZURE_AI_MODEL_DEPLOYMENT_NAME`.7374### Dependency Packaging Mode7576Use remote dependency packaging by default (`dependency_resolution: "remote_build"` in `metadata.json`). In this mode, upload source files plus dependency manifests such as `requirements.txt` or `.csproj`; Foundry installs dependencies during the remote build.7778Use bundled local dependencies only when the user explicitly asks for it. In bundled mode, package Linux-compatible dependencies that match the selected runtime.7980For remote packaging, keep the user's dependency files unchanged. Do not slim, pin, or remove packages just to make deployment smoother. If the service fails while installing dependencies, report the exact error and ask before changing dependencies.8182## Task 4: Create `metadata.json`8384Create the parent directory and write `.foundry/direct-code/metadata.json`. Do not write `metadata.json` before the parent directory exists.8586Use the user's platform or language tooling. For example, Python works consistently across common shells:8788```python89from pathlib import Path9091metadata = Path(".foundry/direct-code/metadata.json")92metadata.parent.mkdir(parents=True, exist_ok=True)93# Build the JSON object, then write it to metadata.94```9596Example Python metadata:9798```json99{100"description": "Direct code deployment hosted agent",101"definition": {102"kind": "hosted",103"protocol_versions": [104{105"protocol": "responses",106"version": "1.0.0"107}108],109"cpu": "0.5",110"memory": "1Gi",111"environment_variables": {112"AZURE_AI_MODEL_DEPLOYMENT_NAME": "<model-deployment>"113},114"code_configuration": {115"runtime": "python_3_13",116"entry_point": ["python", "main.py"],117"dependency_resolution": "remote_build"118}119}120}121```122123Example C#/.NET metadata:124125```json126{127"description": "Direct code deployment C# hosted agent",128"definition": {129"kind": "hosted",130"protocol_versions": [131{132"protocol": "responses",133"version": "1.0.0"134}135],136"cpu": "0.5",137"memory": "1Gi",138"environment_variables": {139"AZURE_AI_MODEL_DEPLOYMENT_NAME": "<model-deployment>"140},141"code_configuration": {142"runtime": "dotnet_10",143"entry_point": ["dotnet", "<AssemblyName>.dll"],144"dependency_resolution": "remote_build"145}146}147}148```149150## Task 5: Create a Flat Code Zip151152The zip must be flat at the root. Do not include a top-level wrapper folder such as `my-agent/`. The entry point path in `metadata.json` must resolve from the zip root.153154Before upload, inspect the archive entries and verify the required files are at the zip root. A wrapper folder, raw wheel files, Windows binaries, or a published output nested under `publish/` will usually fail at version build or session startup.155156Exclude local/development artifacts:157158```text159.env160.foundry/161.git/162.vscode/163.venv/164__pycache__/165bin/166obj/167Dockerfile168.dockerignore169docker-compose.yml170Properties/launchSettings.json171```172173### Remote Packaging (Default)174175The examples below use Python's `zipfile` module so they work across common shells and operating systems. Use equivalent platform zip tooling if Python is unavailable.176177Python remote-packaging zip should include `main.py`, `requirements.txt`, and any imported local source modules/packages needed by the entry point. Do not include `packages/`; the service installs dependencies from `requirements.txt`.178179```python180from pathlib import Path181from zipfile import ZipFile, ZIP_DEFLATED182183zip_path = Path(".foundry/direct-code/agent-code.zip")184zip_path.parent.mkdir(parents=True, exist_ok=True)185files = ["main.py", "requirements.txt"]186187with ZipFile(zip_path, "w", ZIP_DEFLATED) as zf:188for name in files:189path = Path(name)190if path.exists():191zf.write(path, name)192```193194C#/.NET remote-packaging zip should include the project file, source files, and appsettings files. Do not include `bin/`, `obj/`, `.env`, Docker assets, or local launch settings. The `.csproj` `TargetFramework` must match the selected `dotnet_*` runtime.195196```python197from pathlib import Path198from zipfile import ZipFile, ZIP_DEFLATED199200zip_path = Path(".foundry/direct-code/agent-code.zip")201zip_path.parent.mkdir(parents=True, exist_ok=True)202files = ["StorytellerAgent.csproj", "Program.cs", "appsettings.json", "appsettings.Development.json"]203204with ZipFile(zip_path, "w", ZIP_DEFLATED) as zf:205for name in files:206path = Path(name)207if path.exists():208zf.write(path, name)209```210211### Bundled Local Dependencies (Only When Requested)212213Bundled Python zip should include `main.py`, `requirements.txt`, and a `packages/` directory containing extracted Linux-compatible modules. Do not include raw `.whl` files, Windows `.pyd`/`.dll` binaries, or packages built without the target Linux platform flags.214215```text216python -m pip install -r requirements.txt --target packages --platform manylinux2014_x86_64 --python-version 3.13 --implementation cp --only-binary=:all:217```218219Match `--python-version` to the selected `python_*` runtime and avoid Windows binaries.220221Bundled .NET zip is the output of `dotnet publish -c Release -r linux-x64 --self-contained false`, rooted directly at the publish output. It should contain `<AssemblyName>.dll`, `<AssemblyName>.runtimeconfig.json`, and the rest of the publish output at the zip root, not inside a `publish/` wrapper folder.222223```text224dotnet publish -c Release -r linux-x64 --self-contained false -o publish225```226227Then create the zip from the publish output:228229```python230from pathlib import Path231from zipfile import ZipFile, ZIP_DEFLATED232233root = Path("publish")234zip_path = Path(".foundry/direct-code/agent-code.zip")235zip_path.parent.mkdir(parents=True, exist_ok=True)236237with ZipFile(zip_path, "w", ZIP_DEFLATED) as zf:238for path in root.rglob("*"):239if path.is_file():240zf.write(path, path.relative_to(root).as_posix())241```242243## Task 6: Upload Code and Create or Update the Agent244245Use the user's current platform and shell syntax. The examples below use literal placeholders and can be translated to any shell or HTTP client. Always keep `?api-version=...` in the final request URL.246247Resolve these values:248249- `<project-endpoint>`250- `<agent-name>`251- `<metadata-json>` - usually `.foundry/direct-code/metadata.json`252- `<code-zip>` - usually `.foundry/direct-code/agent-code.zip`253- `<access-token>` - from `az account get-access-token --resource https://ai.azure.com --query accessToken -o tsv`254- `<code-sha256>` - SHA-256 of the zip file255256Calculate the zip SHA-256 with any platform tool. Python example:257258```python259import hashlib260from pathlib import Path261262with Path(".foundry/direct-code/agent-code.zip").open("rb") as f:263print(hashlib.sha256(f.read()).hexdigest())264```265266Use `<project-endpoint>` as the base URL. Append paths directly to that project endpoint; do not strip `/api/projects/<project>` from it.267268Direct-code deployment uses these REST operations:269270| Purpose | Method and endpoint | When to use |271|---------|---------------------|-------------|272| Check whether the agent exists | `GET <project-endpoint>/agents/<agent-name>?api-version=2025-11-15-preview` | Run first. `404` means create the agent; `200` means deploy a new version by default |273| Create a new agent | `POST <project-endpoint>/agents?api-version=2025-11-15-preview` | Use only when the existence check returned `404` |274| Create a new version for an existing agent | `POST <project-endpoint>/agents/<agent-name>/versions?api-version=2025-11-15-preview` | Default path when the agent already exists |275| Update an existing agent in place | `POST <project-endpoint>/agents/<agent-name>?api-version=2025-11-15-preview` | Use only when the user explicitly asks for an in-place update |276277If any GET/POST returns `Missing required query parameter: api-version`, the request URL was malformed. Fix the URL construction and retry the same REST call before continuing; do not interpret that response as "agent exists", "agent missing", or a version/build problem.278279All write requests use `multipart/form-data` with:280281- `metadata`: the JSON metadata file, content type `application/json`282- `code`: the flat zip file, content type `application/zip`, with `filename=<agent-name>.zip`283- `x-ms-code-zip-sha256`: SHA-256 of the zip file284285Create-agent request shape:286287```http288POST <project-endpoint>/agents?api-version=2025-11-15-preview289Authorization: Bearer <access-token>290Accept: application/json291Foundry-Features: CodeAgents=V1Preview,HostedAgents=V1Preview292x-ms-agent-name: <agent-name>293x-ms-code-zip-sha256: <code-sha256>294Content-Type: multipart/form-data295296metadata=<metadata-json file>; type=application/json297code=<code-zip file>; type=application/zip; filename=<agent-name>.zip298```299300Create-version request shape:301302```http303POST <project-endpoint>/agents/<agent-name>/versions?api-version=2025-11-15-preview304Authorization: Bearer <access-token>305Accept: application/json306Foundry-Features: CodeAgents=V1Preview,HostedAgents=V1Preview307x-ms-code-zip-sha256: <code-sha256>308Content-Type: multipart/form-data309310metadata=<metadata-json file>; type=application/json311code=<code-zip file>; type=application/zip; filename=<agent-name>.zip312```313314Do not send `x-ms-agent-name` on `POST /agents/<agent-name>/versions` or `POST /agents/<agent-name>`. Send it only on `POST /agents` because the agent name is not in that route.315316Update agent and create version are idempotent on zip SHA-256 plus agent definition. If both are unchanged from the latest version, the service can return the existing version instead of creating a duplicate. To force a new version, change the zip contents or definition.317318Other useful REST operations:319320| Purpose | Method and endpoint | Notes |321|---------|---------------------|-------|322| List versions | `GET <project-endpoint>/agents/<agent-name>/versions?api-version=2025-11-15-preview` | Use when the write response does not clearly return a version |323| Download code | `GET <project-endpoint>/agents/<agent-name>/code:download?api-version=2025-11-15-preview` | Add `agent_version=<n>` when downloading a specific version; compare the `x-ms-code-zip-sha256` response header with the local SHA |324| Delete agent | `DELETE <project-endpoint>/agents/<agent-name>?api-version=2025-11-15-preview` | Deletes the agent and all versions; pull logs before deletion if needed |325326## Task 7: Poll Version Status327328Use the version from the create/version response. If the response does not clearly include it, list versions and pick the newest version returned for the agent.329330```http331GET <project-endpoint>/agents/<agent-name>/versions/<version>?api-version=2025-11-15-preview332Authorization: Bearer <access-token>333Foundry-Features: CodeAgents=V1Preview,HostedAgents=V1Preview334```335336Loop until the version status is no longer `creating`.337338- `active` -> proceed directly back to [deploy.md Step 7: Test the Agent](../deploy.md#step-7-test-the-agent).339- `failed` -> read the error from the version object. There is no runtime session yet, so `:logstream` will not help.340