feat: delegate Foundry project ownership to projects - #9511
feat: delegate Foundry project ownership to projects#9511Hui Miao (huimiu) wants to merge 10 commits into
Conversation
125f300 to
c65a148
Compare
b644a9e to
acd1efb
Compare
acd1efb to
387f5a7
Compare
This comment was marked as off-topic.
This comment was marked as off-topic.
There was a problem hiding this comment.
Pull request overview
Moves Foundry project lifecycle capabilities into azure.ai.projects.
Changes:
- Adds project initialization, adoption, environment reconciliation, and infrastructure ejection.
- Adds managed model deployment selection and persistence.
- Introduces a versioned delegation contract and regression tests.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
internal/exterrors/errors.go |
Adds compatibility errors. |
internal/cmd/root.go |
Registers new commands. |
internal/cmd/project_service_reconciler.go |
Reconciles project services. |
internal/cmd/project_ownership_test.go |
Tests ownership workflows. |
internal/cmd/project_init.go |
Implements project initialization. |
internal/cmd/project_environment.go |
Reconciles environment state. |
internal/cmd/project_deployment.go |
Resolves and persists deployments. |
internal/cmd/project_deployment_add.go |
Implements deployment addition. |
internal/cmd/delegated_contract.go |
Defines delegation contracts. |
go.mod |
Promotes RPC dependency to direct. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
📋 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
Copilot reviewed 24 out of 24 changed files in this pull request and generated 1 comment.
Suppressed comments (3)
cli/azd/extensions/azure.ai.projects/internal/cmd/project_init.go:756
- azd-code-reviewer: When the active environment already has
AZURE_SUBSCRIPTION_IDbut lacksAZURE_LOCATION,needSubscriptionis false, sotarget.SubscriptionIdis never populated. This location prompt is consequently created with an empty subscription (and tenant) instead of the existing environment context, preventing the location selector from querying the intended subscription. Fall back to the environment values when building the scope.
azureContext := &azdext.AzureContext{
Scope: &azdext.AzureScope{
SubscriptionId: target.SubscriptionId,
TenantId: target.UserTenantId,
},
cli/azd/extensions/azure.ai.projects/internal/cmd/project_init.go:267
- azd-code-reviewer: Infrastructure planning and collision validation first happen here, after environment reconciliation and the service/deployment mutations above have already persisted. A symlink, provider, marker, or file-collision error therefore returns a failed
project initwhile leavingazure.yamland the active environment partially updated; the staged filesystem rollback cannot restore those values. Preflight the ejection plan before persistent mutations, or snapshot and roll back the project/environment state on failure.
if infra := infraFromRequest(request, a.flags); infra != "" {
if err := ejectProjectInfra(projectRoot, serviceName, infra); err != nil {
return err
cli/azd/extensions/azure.ai.projects/internal/cmd/project_init.go:1046
- azd-code-reviewer: This always inspects
<projectRoot>/infra, even thoughvalidateFoundryProvideralso calls it for projects whoseinfra.pathis custom. For example,infra.path: iacwith valid files underiac/is treated as empty (or judged by an unrelatedinfra/) and rejected as an infrastructure conflict. Resolve the configured path relative toproject.GetPath()and inspect that directory instead.
target := filepath.Join(projectRoot, "infra")
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 30 changed files in this pull request and generated no new comments.
Suppressed comments (3)
cli/azd/extensions/azure.ai.projects/internal/cmd/delegated_contract.go:178
- [azd-code-reviewer] Replacement requests validate only deployment names, so a v2 request with empty model format/name/version, an empty SKU, or a non-positive capacity is accepted and persisted into
azure.yaml; provisioning then fails later on the malformed declaration. Validate the full required deployment tuple before mutating project state, matching the checks inProjectDeploymentAddAction.
for _, deployment := range r.Deployments {
cli/azd/extensions/azure.ai.projects/internal/cmd/project_infra_layers.go:862
- [azd-code-reviewer] The rollback contract cannot report cleanup failures: both returned closures discard
Remove,RemoveAll, andMkdirAllerrors. If the laterazure.yamlupdate fails and cleanup is blocked, eject reports only the original error while leaving generated infrastructure installed, breaking the documented all-or-nothing behavior. Return an error from the rollback callback and combine it with the caller's failure.
func installProjectInfraStage(
stageDir string,
plan *projectInfraEjectPlan,
) (func(), error) {
cli/azd/extensions/azure.ai.projects/internal/cmd/project_deployment.go:90
- [azd-code-reviewer] Negative capacities are treated as unspecified:
--capacity=-1never reachesoptions.Capacity, so the command silently selects and persists a default positive capacity. Reject negative values from both the CLI selection and delegated model before resolving candidates.
if model.Capacity > 0 {
selection.Capacity = model.Capacity
}
Azure Dev CLI Install InstructionsInstall scriptsMacOS/Linux
bash: pwsh: WindowsPowerShell install MSI install Standalone Binary
MSI
Documentationlearn.microsoft.com documentationtitle: Azure Developer CLI reference
|
|
This combined PR has been split into four focused draft PRs:
Closing this combined PR to avoid duplicate review surfaces. |
Closes: #9534
What this changes
Foundry project setup is currently shared between
azure.ai.agentsandazure.ai.projects. This change gives the project lifecycle a single owner:azure.ai.projectsnow handles project identity, endpoints, connections, managed model deployments, environment reconciliation, and project infrastructure.azure.ai.agentscontinues to handle Agent definitions, Agent-specific deployments, and workflows.Existing Agent commands still work. When they need to change project-owned state, Agents sends a versioned v2, input-only JSON request to Projects. The request prefers a resource ID over an endpoint, uses a private temporary file, cleans that file up, and reads the saved project state after the call.
Why
Two extensions writing the same project state makes initialization and adoption hard to reason about. Endpoints, deployments, environment values, or infrastructure can drift, or the same change can be applied twice. Giving Projects one owner keeps those changes together and lets Agents focus on Agent behavior.
This is the ownership split needed for the larger goal of separating project management from Agent management. We kept the existing extension boundary so current Agent workflows can use the new owner without adding a core transport dependency.
Implementation
AZURE_LOCATIONthat represents the resource group or infrastructure location.azure.ai.agentsproject services migrate only the project-ownedendpoint,deployments, andnetworkfields. Agent fields, hooks, uses, and environment settings are not copied.infra/foundrywhen a separate layer is needed. The code checks paths, symlinks, providers, modules, and file collisions before installing staged output, and rolls back on failure.