feat(agents): add .NET code deploy support (dotnet_8/9/10 runtimes)#8161
Draft
v1212 wants to merge 24 commits into
Draft
feat(agents): add .NET code deploy support (dotnet_8/9/10 runtimes)#8161v1212 wants to merge 24 commits into
v1212 wants to merge 24 commits into
Conversation
added 21 commits
May 11, 2026 16:17
Implements code-based deployment as a complementary mode to container deploy. Agents with code_configuration in agent.yaml are deployed via multipart ZIP upload instead of Docker/ACR, eliminating permission complexity.
Add deploy mode prompt (code vs container) to the init flow. When code deploy is selected, prompts for runtime, entry_point, and dependency_resolution, then generates agent.yaml with code_configuration and azure.yaml with language: python (no Docker).
…aults - Fix gosec G304 warnings with nolint annotations for safe file reads - Fix gosec G104 by properly handling tmpFile.Close() errors - Fix gofmt formatting in excludeDirs map - Update runtime choices to python_3_12/3_11/3_13 per spec - Change --no-prompt deploy mode default to container (backward compat) - Change --no-prompt runtime default to python_3_12 - Align prompt labels with spec wording - Add container.resources + startupCommand to azure.yaml for code deploy
- Add .azure and .env/.env.* to ZIP exclusion list to prevent uploading secrets - Skip symlinks in WalkDir to avoid including files outside agent directory - Stream ZIP directly to temp file with io.MultiWriter for SHA-256, reducing memory usage - Clean up temp file on all error paths using deferred cleanup - Only fall back to create agent on 404; propagate auth/5xx/network errors - Use context-aware select/time.After in polling loop for responsive cancellation - Add dedicated CodeMissingCodeZipArtifact error code - Fix entry point auto-detection to use srcDir instead of cwd - Replace hardcoded multipart boundary with mime/multipart.Writer - Add unit tests for zipDeployRequest multipart format and headers
…deploy and set metadata Content-Type - Add PatchAgent call after code deploy create/update to apply agent_endpoint and agent_card fields (matching container deploy behavior) - Use CreatePart with explicit Content-Type: application/json for the metadata multipart part instead of CreateFormField - Update unit test to verify metadata part Content-Type header
- Add //nolint:gosec to os.ReadFile in init_from_code.go - Handle req.Body.Close() return value in test transport - Suppress Close/Remove errors in deferred cleanup with _ = - Add 'mypy' to cspell.yaml words list
Add deploy mode prompt (code vs container) to the template init flow, allowing users to choose code deploy when initializing from a template. Skip ACR configuration when code deploy is selected. Auto-derive startup command from entry_point for code deploy instead of prompting.
…switch - Default to Container (Docker) for backward compatibility - Use clearer labels: 'Container (Docker)' / 'Code deploy (ZIP upload)' - Remove code_configuration from agent.yaml when switching to container mode
When skipACR is true (code deploy mode), skip the configureAcrConnection call entirely to prevent prompting users for ACR configuration.
When running 'azd ai agent init' from a subdirectory with an existing agent.manifest.yaml, the addToProject function received targetDir='.' which wrote 'project: .' into azure.yaml. Since azure.yaml resolves paths relative to the project root, this caused the service to point to the wrong directory. Fix: resolve the actual relative path from project root to cwd when targetDir is '.', so azure.yaml gets the correct project path (e.g. 'src/hello-world-python-invocations' instead of '.').
- T1: Hide code deploy for non-Python projects (isPythonProject check) - T2: Add TODO for region validation in code deploy - T3: Reorder runtime list to 3.11, 3.12, 3.13 - T4: Update entry point prompt wording - T6: Add descriptions to bundled/remote_build choices - J1: Consolidate promptCodeConfig into single shared function - J3: Use errors.AsType[*azcore.ResponseError] per Go 1.26 - J4: Extract shared deriveStartupCommand helper - V1: Rename to 'Container Image (Docker)' / 'Source Code (ZIP upload)' - V2: Unify HostedAgentDefinition with custom JSON marshal/unmarshal - V4: Fix error message to reference 'azd package' - V5: Extract prepareDeploy/finalizeDeploy shared helpers - C1+C3: Verify ZIP exclusions (.azure, .env) and temp file cleanup
… default Add region validation for code deploy at both init-time (filter project list) and deploy-time (fail early with clear error). Supported regions: westus2, canadacentral, northcentralus. Unify dependency_resolution fallback default to 'remote_build' to match --no-prompt behavior.
…ATION Move CodeDeployRegions to project.config.go as a shared exported var, referenced by both init filtering and deploy validation. Add explicit check for empty AZURE_LOCATION with actionable error message.
…rompt - Include service error code/message and x-request-id in remote build failure errors - Rename 'container resource allocation' prompt to 'Select resources (CPU and Memory)'
…PI request mapping)
added 3 commits
May 13, 2026 16:58
Reject code packages exceeding 250 MB with a clear error message suggesting to reduce package size or use remote_build.
…me options - Fix template init path that hardcoded language=python for all code deploy; now correctly sets language=csharp when agent uses a dotnet runtime - Filter runtime options in promptCodeConfig based on detected project type (Python projects see only Python runtimes, .NET only .NET, mixed sees all) - Add isDotnetProject helper (checks for .csproj/.fsproj files) - Enable code deploy option for .NET projects in both init paths - Capture dotnet publish stdout/stderr in error message for better diagnostics - Add TODO comment to CodeDeployRegions for future dynamic discovery
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds .NET runtime support (
dotnet_8,dotnet_9,dotnet_10) to the code deploy (ZIP upload) path introduced in #8146. This enables deploying .NET agent source code directly via ZIP upload without requiring Docker/ACR, alongside the existing Python support.Init Flow Changes
Deploy Mode Prompt
The code deploy option now appears for both Python and .NET projects (detected via
.csproj/.fsprojfiles). For projects that are neither Python nor .NET, the code deploy option remains hidden.Existing Code -> Code Deploy (.NET)
Runtime Filtering
promptCodeConfig()now filters runtime choices based on detected project type:.csproj/.fsproj, no.py/requirements.txt): Shows only .NET 9, .NET 8, .NET 10.py/requirements.txt, no.csproj): Shows only Python 3.11, 3.12, 3.13Language Detection in
azure.yamlBoth init paths (template and from-code) correctly set
language: csharpwhen a dotnet runtime is selected, fixing a bug where code deploy always hardcodedlanguage: python.Deploy Path Changes
Bundled Mode (
dependency_resolution: bundled)For .NET agents in bundled mode,
packageDotnetBundled():dotnet publish -c Release -r linux-x64 --self-contained false -o <temp-dir>Remote Build Mode (
dependency_resolution: remote_build)For .NET agents in remote build mode:
.cs,.csprojfiles etc.) excluding build artifactsdotnet publishon the remote environmentEntry Point Prefix
.NET agents use
dotnet <entry_point>as the startup command (e.g.,["dotnet", "HelloWorld.dll"]), while Python usespython <entry_point>.250 MB ZIP Size Limit
Enforced for all code deploy packages (both Python and .NET) with a clear error message.
Files Modified
init_from_code.goisDotnetProject()helper,detectDefaultEntryPoint()for.dll/.csproj, filter runtime choices by project type, updateshowCodeDeployto include .NET, fixnoPromptdefault for dotnetinit_from_code_test.godetectDefaultEntryPoint()with dotnet scenariosinit.golanguage: pythonhardcoding bug -- now checks runtime prefix forcsharp; updateshowCodeDeployto useisDotnetProject()map.godotnet_8/9/10runtimes to API format with"dotnet"command prefixmap_test.goservice_target_agent.gopackageDotnetBundled()withdotnet publish+ output capture in errors; displaydotnetprefix in deploy output; addbytesimport; enforce 250 MB ZIP limitconfig.goCodeDeployRegionsfor future dynamic discoveryHow to Build
Manual Test Steps
Prerequisites
westus2,canadacentral,northcentralus)gpt-4o,gpt-5.1) in your Foundry projectazdCLI installed, logged in (azd auth login)cd cli/azd/extensions/azure.ai.agents && azd x buildTest 1: .NET Code Deploy with Remote Build
Test 2: .NET Code Deploy with Bundled Mode
Test Results
All configurations verified end-to-end on
canadacentral(Foundry projectwujia-aifproject260512):dotnet publishruns locallyInvoke Output Example (Remote Build, dotnet_9)
Unit Tests
Specific test coverage for this PR:
TestDetectDefaultEntryPoint-- verifies.dlldetection fromdotnet publishoutput and.csprojAssemblyName fallbackTestCodeConfigurationDotnetRoundTrip-- verifiesdotnet_9runtime maps to API format with["dotnet", "HelloWorld.dll"]entry pointTestCodeConfigurationDotnetRemoteBuild-- verifiesdependency_resolution: remote_buildmapping for dotnetNotes
--no-promptdefaults: For .NET projects, defaults todotnet_9runtime. For Python projects, defaults topython_3_12(unchanged)..csproj<AssemblyName>property first, falls back to project directory name +.dll.exec.Command("dotnet", "publish", csprojPath, ...)--csprojPathis derived from user's local project directory, not external input.westus2,canadacentral,northcentralus.Dependencies
main, this PR's diff will shrink to only the .NET-specific additions (~5 commits)Related
code_configurationschema updated with .NET runtimes (dotnet_8/9/10),.dllentry point examples, and .NET build workflow descriptions