Skip to content

feat(agents): split Foundry init into per-resource azure.yaml services#8675

Merged
huimiu merged 13 commits into
huimiu/foundry-azure-yamlfrom
huimiu/foundry-unified-init
Jun 24, 2026
Merged

feat(agents): split Foundry init into per-resource azure.yaml services#8675
huimiu merged 13 commits into
huimiu/foundry-azure-yamlfrom
huimiu/foundry-unified-init

Conversation

@huimiu

@huimiu huimiu commented Jun 16, 2026

Copy link
Copy Markdown
Member

What this PR does

Changes how azd ai agent init writes Foundry resources into azure.yaml: each resource type becomes its own service entry instead of being bundled into the single agent service.

Per-resource azure.yaml services

Before: all Foundry resources (model deployments, connections, toolboxes) were bundled into the single agent service entry.

After: each resource type gets its own azure.yaml service entry with a dedicated host:

  • azure.ai.project — the Foundry project + model deployments (one per agent)
  • azure.ai.connection — one entry per connection
  • azure.ai.toolbox — one entry per toolbox

The agent service lists these as uses: dependencies so azd provisions them in the right order.

Example azure.yaml after init:

services:
  ai-project:
    host: azure.ai.project
    config:
      deployments: [...]
  my-connection:
    host: azure.ai.connection
    uses: [ai-project]
    config:
      name: my-connection
  my-agent:
    host: azure.ai.agents
    uses: [ai-project, my-connection]

Why split: per-resource services give each Foundry resource a clear ownership boundary in azure.yaml and make the provisioning graph explicit via uses:. For now the agents extension registers all three resource hosts (azure.ai.project, azure.ai.connection, azure.ai.toolbox) as no-op service targets, so only that extension needs to be installed for azd up/deploy to walk the entries; the resources themselves are still provisioned by Bicep / the data-plane API during provision.

Provisioning behavior is unchanged — the agent extension re-sources deployments, connections, and toolboxes from the sibling services when setting provisioning environment variables and creating toolsets. Projects created before the split (resources bundled on the agent service) keep working: the collectors fall back to the agent service config when no sibling services exist, so an existing azure.yaml still provisions without re-running init.

Scope / follow-up

This PR is intentionally limited to the azure.yaml split plus registering the resource hosts from the agents extension. Fully onboarding azure.ai.projects / azure.ai.connections / azure.ai.toolboxes as standalone azd extensions that own their resource's deploy-time lifecycle is a larger effort and will be iterated on separately — each host can move from the shared no-op provider in the agents extension to its own extension when it gains real behavior.

Base branch

This PR targets huimiu/foundry-azure-yaml, which carries only the already-merged Foundry azure.yaml schema work (#8603, #8627, #8689, #8643).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR completes the extension-side work to have azd ai agent init emit a unified host: microsoft.foundry service entry in azure.yaml, aligning init output with the new Foundry service target shape (single hosted agent) and removing the legacy agent.yaml/manifest outputs.

Changes:

  • Add a new microsoft.foundry service target provider that binds inline Foundry config from ServiceConfig.AdditionalProperties and deploys a single hosted agent (image or code-zip runtime).
  • Refactor init flows (init + init-from-code) to write the unified Foundry service entry (deployments at service level + agent inline), and keep emitting .agentignore for packaging.
  • Introduce Foundry config parsing/validation utilities and unit tests (config validation, endpoint parsing, and init-to-project wiring).

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
cli/azd/extensions/azure.ai.agents/internal/project/service_target_foundry.go Implements host: microsoft.foundry deploy lifecycle for a single hosted agent and reuses shared agent deploy helpers.
cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go Extracts shared auth setup and ZIP packaging helper for reuse by the Foundry target.
cli/azd/extensions/azure.ai.agents/internal/project/foundry_project_resolve.go Adds endpoint → ARM project ID resolution and endpoint parsing helpers.
cli/azd/extensions/azure.ai.agents/internal/project/foundry_project_resolve_test.go Unit tests for Foundry endpoint parsing.
cli/azd/extensions/azure.ai.agents/internal/project/foundry_config.go Defines/validates the unified Foundry config shapes (service + agent) and maps to deploy request types.
cli/azd/extensions/azure.ai.agents/internal/project/foundry_config_test.go Unit tests for Foundry config validation and binding from AdditionalProperties.
cli/azd/extensions/azure.ai.agents/internal/cmd/listen.go Registers the new microsoft.foundry service target.
cli/azd/extensions/azure.ai.agents/internal/cmd/init.go Updates init to stop writing agent.yaml and to emit unified Foundry service config + .agentignore.
cli/azd/extensions/azure.ai.agents/internal/cmd/init_from_code.go Updates init-from-code to emit unified Foundry service config and derive runtime/entrypoint from on-disk definition.
cli/azd/extensions/azure.ai.agents/internal/cmd/init_foundry.go Adds helper to build unified Foundry service config + helper mappers + .agentignore writer.
cli/azd/extensions/azure.ai.agents/internal/cmd/init_foundry_test.go Unit tests for the unified Foundry service config builder helpers.
cli/azd/extensions/azure.ai.agents/internal/cmd/init_foundry_addtoproject_test.go End-to-end-ish tests asserting init writes the unified Foundry service shape via gRPC AddService.
cli/azd/extensions/azure.ai.agents/extension.yaml Registers the microsoft.foundry provider in the extension manifest.

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/init_foundry.go Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/init_foundry.go Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/project/service_target_foundry.go Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/project/foundry_project_resolve.go Outdated
@huimiu huimiu force-pushed the huimiu/foundry-unified-init branch from bc38428 to 15ef2ed Compare June 16, 2026 09:18
@huimiu huimiu changed the base branch from huimiu/foundry-azure-yaml to huimiu/foundry-service-target June 16, 2026 09:18
@glharper

Copy link
Copy Markdown
Member

Review: unified microsoft.foundry config from init

Switches azd ai agent init (manifest + from-code paths) to write a single unified host: microsoft.foundry service entry with the agent inline under agents: and model deployments: at project level, carried on ServiceConfig.AdditionalProperties instead of config:. Drops the separate agent.yaml write, extracts a shared buildFoundryServiceConfig helper, and adds solid tests. Build, go vet, gofmt, and the new tests pass locally; line lengths are within the lll limit.

The design is clean and the test coverage is genuinely good — TestBuildFoundryServiceConfig_ValidatesAsHostedAgent round-trips the writer''s output through the reader''s FoundryProjectConfig.Validate(), and splitRuntime is verified as the correct inverse of the service target''s runtimeString.

Issues

1. (High) nextstep no longer recognizes the service init just wrote.
init.go calls nextstep.AssembleStateResolveAfterInit at the end of addToProject (init.go:2679-2680), but nextstep/state.go:438 filters services by svc.Host != agentHost where agentHost = "azure.ai.agent" (state.go:30). Since init now writes microsoft.foundry, the just-initialized service is skipped, so init''s own "next steps" output silently loses protocol-aware azd ai agent run guidance, azd env set <KEY> hints, and edit agent.yaml placeholder hints. doctor/checks_project.go:24 matches the same stale literal. These filters should also accept microsoft.foundry.

2. (Medium, by design) Container/docker agents become undeployable.
For a hosted agent with no codeConfiguration and no image (the default remote-build container path), buildFoundryServiceConfig falls into the default branch and sets agent.Docker — but validateHostedAgent (foundry_config.go:276) hard-rejects deployModeDocker. So init writes an azure.yaml that fails only later at deploy/provision. It''s acknowledged in comments, but consider emitting a warning at init time so users aren''t surprised at deploy.

3. (Low) Stale comment. init.go:2666-2674 still says the resolver "inspects … each azure.ai.agent service''s agent.yaml" — the host is now microsoft.foundry and init no longer writes agent.yaml.

4. (Low) foundryAgentInput.instructions is never populated. A prompt-kind agent (set when agentDef.Kind != AgentKindHosted) would be written with empty instructions. Latent only because prompt agents are rejected by the target today.

Minor: the container branch hardcodes Docker.Path: "Dockerfile" regardless of the actual Dockerfile name (no impact while docker mode is non-deployable).

Item #1 is the one I''d want addressed (or explicitly deferred with a tracking note) before merge, since it regresses init''s own UX immediately.

@therealjohn

Copy link
Copy Markdown
Contributor

This fixes #7962

@therealjohn therealjohn left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After more review, some changes:

  • each resource needs to be it's own service entry
  • each extension would own the schema for that service entry, similar to how the agents ext owns the schema for host: azure.ai.agents
  • each extension would need a hook on doing dataplane operations, similar to how the agents ext has a post-deploy hook to create an agent

Right now, AZD does not support different extensions contributing to the same service host - so separating them makes that possible, but it also means we can more easily manipulate each resource as a service.

Example: https://github.com/therealjohn/foundry-azd-config-preview/blob/separate-services/REFERENCE.md#project-basics

@huimiu huimiu force-pushed the huimiu/foundry-unified-init branch from 31b9b43 to 5cb2336 Compare June 22, 2026 05:25
@huimiu huimiu changed the base branch from main to huimiu/foundry-azure-yaml June 22, 2026 06:47
@github-actions github-actions Bot added the area/extensions Extensions (general) label Jun 22, 2026
@huimiu huimiu force-pushed the huimiu/foundry-azure-yaml branch from 491afd5 to b9d8cb6 Compare June 22, 2026 07:35
@huimiu huimiu force-pushed the huimiu/foundry-unified-init branch from d192494 to 08fad8d Compare June 22, 2026 07:35
@huimiu huimiu requested a review from Copilot June 22, 2026 12:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 32 changed files in this pull request and generated 5 comments.

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/listen.go Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/project/foundry_project_resolve.go Outdated
Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/resource_services.go Outdated
Comment thread cli/azd/extensions/azure.ai.connections/internal/cmd/listen.go Outdated
// single azure.ai.project service. A stable name keeps repeated inits
// idempotent (AddService overwrites by name) so there is one project
// service per project, matching the unified Foundry config design.
aiProjectServiceName = "ai-project"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having this fixed, should it be the name of the user's Foundry project?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking was to keep ai-project as a fixed internal key (rather than a display name), so re-running init would consistently reuse the same service instead of creating duplicates. A real project name could also potentially clash with other keys. Does that reasoning make sense to you?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't conflict with other keys since it's specific to the azure.ai.project scope, right? It just feels weird to me that everything else we have the name matches, but this one doesn't. Re-running init shouldn't create duplicates as long as users are using the same Foundry project. If they want to use a different Foundry project we would need to handle that, but personally it feels better to handle that than to have this discrepancy in the services. @therealjohn maybe you have an opinion here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@huimiu can we remain consistent with our other approach where the service name matches the user defined name when its a new project, or the one they select if its existing?

That being said - I dont think we have a feature where we allow a user to define a project name - its determined in the Bicep today and it's not customizable.

So if we dont have the upstream feature to support that lets file and track that with this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, let me update in next PR

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/resource_services.go Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/extensions Extensions (general) ext-agents azure.ai.agents extension ext-connections azure.ai.connections extension ext-foundry azure.ai.{agents,connections,inspector,projects,routines,skills,toolboxes}, microsoft.foundry ext-projects azure.ai.projects extension ext-toolboxes azure.ai.toolboxes extension

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ext-agents]: azd ai agent init writes unified microsoft.foundry config in azure.yaml

5 participants