fix: run interactive Azure context setup in unified azure.yaml adoption path#8933
Conversation
…on path When 'azd ai agent init -m <azure.yaml>' points at a unified Foundry azure.yaml, the adoption path now runs subscription selection and Foundry project configuration (existing vs new) after scaffolding, matching the agent-manifest flow. Extracts the shared subscription + Foundry project selection logic from configureModelChoice's !hasModelResources branch into a standalone configureFoundryProject helper. Both the adoption path and the agent-manifest path now call this helper, eliminating duplication. Fixes #8922 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…project After selecting a Foundry project, the adoption path now checks each model deployment declared in the azure.yaml against existing deployments in the project. For each deployment, the user can: - Use an existing matching deployment (removes it from azure.yaml) - Deploy as specified (keeps it for provisioning) - Choose a different model (full catalog + deployment prompt) - Skip (removes from azure.yaml) The first selected deployment's name is persisted as AZURE_AI_MODEL_DEPLOYMENT_NAME (same env var as the manifest path). In --no-prompt mode, existing matches are auto-used and unmatched models are auto-deployed. Closes #8922 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests cover: - foundryDeployments: single/multiple deployments, missing sections, non-project hosts, empty/malformed content, partial fields - stringField: correct type, wrong type, missing, empty - intField: int, float64, wrong type, missing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace map[string]any manual extraction with typed structs (azureYamlServices, azureYamlService) that unmarshal directly into project.Deployment. This gives strong typing at parse time and removes the stringField/intField helpers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Makes the YAML field mapping an explicit contract rather than relying on yaml.v3's lowercase-field-name fallback behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ion path When --model-deployment is provided, auto-select the named deployment from the Foundry project without interactive prompts (error if not found). When --model is provided, pre-select it as the default in the catalog prompt when the user chooses a different model. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
📋 Prioritization NoteThanks for the contribution! The linked issue isn't in the current milestone yet. |
There was a problem hiding this comment.
Pull request overview
This PR fixes issue #8922, where azd ai agent init -m <azure.yaml> pointed at a unified Foundry azure.yaml scaffolded the project but returned early without running any interactive Azure setup (subscription selection, Foundry project selection, model verification), leaving an environment that could not provision. It wires the interactive setup into the unified adoption path (runInitFromAzureYaml) so it matches the agent-manifest flow.
Changes:
- Extracts the shared subscription + Foundry project selection logic out of
configureModelChoice's!hasModelResourcesbranch into a new reusableconfigureFoundryProjecthelper (returningCredential+FoundryProject), and delegates to it frominit.go. - Adds a model-deployment verification phase to the adoption path: parses deployments from
azure.yaml, compares them against the selected project's existing deployments, and lets the user use-existing / deploy / choose-different / skip (auto-resolved under--no-prompt), rewritingazure.yamland persistingAZURE_AI_MODEL_DEPLOYMENT_NAME. - Adds explicit
yamlstruct tags toproject.Deployment/DeploymentModel/DeploymentSkuand a table-driven test for the newfoundryDeploymentsparser.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
cli/azd/extensions/azure.ai.agents/internal/project/config.go |
Adds yaml tags to Deployment types (additive; matches yaml.v3 default lowercasing). |
cli/azd/extensions/azure.ai.agents/internal/cmd/init.go |
Refactors the !hasModelResources branch to delegate to configureFoundryProject. |
cli/azd/extensions/azure.ai.agents/internal/cmd/init_foundry_project_setup.go |
New file; the extracted configureFoundryProject helper (project-id / deferred / no-prompt / interactive modes). |
cli/azd/extensions/azure.ai.agents/internal/cmd/init_adopt.go |
Wires subscription/Foundry setup and deployment verification into runInitFromAzureYaml; adds parsing, prompting, and azure.yaml rewrite logic. |
cli/azd/extensions/azure.ai.agents/internal/cmd/init_adopt_test.go |
Tests for foundryDeployments; adds two skipped placeholder stubs for removed helpers. |
Key findings:
- Critical: the "rewrite
azure.yaml" guard compares only list lengths (init_adopt.go:747). The "Choose a different model" flow replaces a deployment without changing the count, so a single-model manifest where the user swaps the model never gets rewritten — provisioning keeps the original model whileAZURE_AI_MODEL_DEPLOYMENT_NAMEpoints at the new one. - Nit: two always-skipped placeholder tests for removed helpers add no coverage and should be deleted.
jongio
left a comment
There was a problem hiding this comment.
The extraction of configureFoundryProject is a clean refactor that removes real duplication. The deployment verification flow for the adoption path is well-structured and the typed YAML parsing is a good choice over map[string]any. Two issues to address before merging.
- The azure.yaml rewrite guard has a logic gap when the user swaps a model (count stays the same but content changes).
- Non-deterministic service assignment for replacement deployments that don't match any original entry.
- Fix azure.yaml rewrite guard: use a 'modified' flag instead of length-only comparison, so model swaps via 'Choose a different model' correctly trigger a rewrite. - Fix non-deterministic service assignment: return keptEntries with ServiceName preserved from the original entry, eliminating the map-iteration fallback. - Fix deferred project path: return deploymentsToKeep as referencedDeployments when AZURE_AI_PROJECT_ID is empty, so AZURE_AI_MODEL_DEPLOYMENT_NAME is still written. - Delete always-skipped TestStringField and TestIntField stubs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Show model details and prompt for confirmation even when creating a new project (no early return on empty AZURE_AI_PROJECT_ID). - Skip redundant 'Deploy as specified' option when an exact match exists. - Skip intermediate catalog/existing prompt when no deployments exist. - Use context-appropriate messaging (no 'not found in project' when there is no project yet). - Remove deployment from azure.yaml when user picks an existing one via 'Choose a different model' (no provisioning needed). - Update 'matching deployments' message for clarity. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jongio
left a comment
There was a problem hiding this comment.
Both issues from my prior review are addressed:
- The length-only rewrite guard is replaced by a modified flag set at each decision point. Cleaner than the content comparison I suggested.
- Non-deterministic service assignment is eliminated by returning []foundryDeploymentEntry with ServiceName preserved from the original entry.
The --model-deployment and --model flag wiring, isExisting distinction in promptAlternativeDeployment, and the exact-match check for hiding redundant "Deploy as specified" are all solid additions.
Motivation
When
azd ai agent init -m <azure.yaml>points at a unified Foundry azure.yaml, the command scaffolds the project but returns early without running subscription selection, Foundry project setup, or model deployment verification. Users are left with an environment that cannot provision without manual configuration.Approach
This PR adds interactive environment setup to the unified azure.yaml adoption path (
runInitFromAzureYaml):Subscription and Foundry project setup:
Extracts the shared subscription + Foundry project selection logic from
configureModelChoice's!hasModelResourcesbranch into a standaloneconfigureFoundryProjecthelper. Both the agent-manifest path and the unified azure.yaml adoption path now call this helper, eliminating duplication and ensuring the adoption path runs the same interactive flow.Model deployment verification:
After project selection, parses model deployments from the azure.yaml and verifies each one against the selected Foundry project's existing deployments. For each declared deployment, the user can:
When creating a new project (no existing deployments to compare against), the user is still shown the model details and asked to confirm, change, or skip.
The first selected deployment is persisted as
AZURE_AI_MODEL_DEPLOYMENT_NAME(same env var as the manifest path).Flag support:
--model-deployment <name>: auto-selects the named existing deployment without prompting (errors if not found)--model <name>: pre-selects the model in the catalog prompt when choosing a different model--project <id>: already supported viaconfigureFoundryProject--no-prompt: auto-uses existing matches and auto-deploys unmatched modelsKey design decisions
configureFoundryProjectreturns afoundryProjectSetupResultwithCredentialandFoundryProjectInfo, allowing callers to chain dependent operations (like listing deployments).yamltags onproject.Deploymentrather thanmap[string]any, so field mapping is a compile-time contract.verifyAzureYamlDeploymentsreturns kept entries with their originating service name preserved, plus amodifiedflag -- eliminates the previous length-only rewrite guard and non-deterministic service assignment.referencedDeployments(not kept in azure.yaml) since it doesn't need provisioning.SetServiceConfigValuewith pathdeployments-- same mechanism used bysetServiceUsesfor theuses:field.Files changed
init_foundry_project_setup.go(new) -- extractedconfigureFoundryProjecthelperinit.go-- refactored!hasModelResourcesbranch to delegate to the helperinit_adopt.go-- wired setup + verification intorunInitFromAzureYaml; deployment parsing, verification, UX improvementsinit_adopt_test.go-- unit tests forfoundryDeploymentsparserproject/config.go-- addedyamlstruct tags toDeploymenttypesFixes: #8922