Skip to content

feat: gate Foundry agent previews independently - #10640

Open
Hui Miao (huimiu) wants to merge 20 commits into
mainfrom
hui/foundry-feature-flags-hosted-agent
Open

Hui Miao (huimiu) wants to merge 20 commits into
mainfrom
hui/foundry-feature-flags-hosted-agent

Conversation

@huimiu

@huimiu Hui Miao (huimiu) commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Fixes #10659

Summary

Make managed harness, voice, and long-running invocation separate opt-ins in the Foundry agents extension, and hide each one from help while it's off. This replaces the broad Hosted Agent gate. Regular hosted and plain prompt agents work without any opt-in.

Stacked on #10636 and uses its IsEnabled check and feature registry. The SDK stays pinned to cli/azd v1.37.0 with no local module replace. No core feature registry, RPC, or SDK version change. Telemetry still uses the SDK's v1beta types, and events and attributes are unchanged.

Breaking change

The three previews are now off by default. Projects that used voice, managed harness, or long-running invocation must opt in to each one with azd config set alpha.<ID> on or its env var. alpha.all doesn't turn them on. CI runs that use these previews need the env var set. The CHANGELOG lists each key and variable.

Changes

Feature ID Scope Environment variable
agents.managed_harness Prompt agents using microsoft_copilot_preview or legacy github_copilot_preview AZD_FOUNDRY_EXT_ENABLE_AGENTS_MANAGED_HARNESS
agents.voice Voice / prompt-voice agents and hosted voice bridges advertising invocations_ws AZD_FOUNDRY_EXT_ENABLE_AGENTS_VOICE
agents.long_running Starting background Responses invocations with --long-running / --no-wait AZD_FOUNDRY_EXT_ENABLE_AGENTS_LONG_RUNNING
  • All gates are off by default. Turn one on with azd config set alpha.<ID> on, azd env set with its env var, or the process env var. Opt-ins are additive and a false value never cancels one from another source. alpha.all and unrelated config keys are ignored for agents previews. Core's global opt-in is unchanged. The selected command environment is passed through as is.
  • Command layer: preview commands and flags carry annotations (previewCommand, previewFlag with optional values, discoverCommand, gateAgentServices). The root PersistentPreRunE reads them once after the SDK pre-run and calls Require for the selected environment. Existing pre-run chaining still works and -e is honored. Per-command checks and env binding are gone.
  • Service layer: invoke, run, and optimize deploy are marked gateAgentServices, so resolveAgentService checks the classified definition before returning, including the deployed-name fallback. Fallbacks never swallow gate errors.
  • Lifecycle: the service target runs one prepareGatedOperation step for resource lookup, package, publish, and deploy, keyed off the existing project.RequireAgentFeatures classification.
  • Direct checks stay where an annotation can't see the input: init and agent add definitions from manifests or $ref files, staged templates before adoption, the existing project before init writes, the remote definition optimize deploy fetches, and the predeploy and preprovision hooks (they run outside a command). The spec lists each one and why.
  • Help: while a feature is off, help hides its commands, flags, and sections: invoke --long-running, invoke --no-wait, the invocations group, init --voice, and the prompt-voice value of init --kind. The root has no azd client when the tree is built, so a help hook asks the host for feature state at render time for the selected environment. If that fails it falls back to the process env var. Command summaries and flag usages that stay visible name agents generically and leave out the hidden previews. Hidden commands and flags are still reachable and still refused while off. Extension metadata and shell completion come from the static tree and still list preview flags. Hiding only affects discovery.
  • init and agent add reject disabled explicit inputs and inline or $ref definitions before any avoidable auth or project writes. Staged templates are checked before adoption, and voice is left out of the init picker when off. Long-running flags on a prompt invocation are now refused instead of ignored.
  • Local argument errors are reported before the preview gate. Bad flag combinations on invoke and init, such as --no-wait without --long-running or --harness without --kind prompt, now return their own error even while the preview is off. Commands register a local check that runs only when the gate would refuse.
  • An explicit empty --environment is rejected for preview checks instead of falling back to the default environment. Help still renders with process values in that case.
  • Add a CHANGELOG entry under Breaking Changes and fix the README voice line.
  • No state migration, and no new checks on generic evaluations or routines requests.
  • Opt-in instructions live only in errors, README, and the spec. Help no longer repeats them. Doc changes stay inside cli/azd/extensions/azure.ai.agents. The opt-in guide has azd config set and azd env set commands for all three gates.

Validation

Go 1.26.4 against the pinned published SDK:

  • go build ./..., go vet ./..., and go test ./... pass. gofmt is clean. golangci-lint with the repo config reports 0 issues. cSpell passes on touched files.
  • Command tests go through the root command so the central pre-run applies. They cover which flags and values need which feature, inherited annotations, service gate placement, gate independence, the old hosted opt-in having no effect, environment selection for enforcement and help, per-feature help hiding with the process fallback, hidden commands staying reachable, staged manifests, local invocation, the deployed-name fallback, untouched project state on rejection, normal flows, and read access.
  • Tests for local errors winning over the gate with previews off, the check running once and only when needed, and the empty environment handling.
  • Help snapshots with every feature on and with every feature off. A walk over every command with every feature off fails on any help text that names voice, harness, or long running.
  • Tier 0: 0.31-preview-help-visibility replaces 0.31-preview-init-help. 0.02 and 0.18 turn on the previews they show.

E2E

azd and the extension were built from the #10657 head (b52dddb2f). That head contains this PR (4e2bac721) and only adds config list-alpha. The extension binary was swapped into the local install. Help rows were rerun at the #10657 head 21d001a69, which contains this PR at 73c907743, with a fresh isolated azd config. Real Azure runs used a temporary Foundry project in eastus2 with gpt-4.1-mini and gpt-realtime-mini. Off means a fresh user config with no opt-in. Refused means the command stopped with preview feature "<id>" is disabled and the enable hint. All agents were deleted afterwards. The resource group was deleted and the account purged.

The last fifteen rows ran after the review fixes. They used the #10657 head (7cf859518), which contains this PR at 833eb9e29, and were compared with the previous #10657 head (2da7a7a69), where every one of them returned the preview error. Each used an isolated azd config. Real Azure rows used a new temporary project in eastus2 with gpt-4.1-mini.

Scenario Expected Result
Root help, all off invocations hidden, command summaries name no preview hidden, none named
invoke --help, all off --long-running, --no-wait, and the voice and long-running sections hidden hidden
init --help, all off --voice, prompt-voice, the voice section, and voice or --harness notes in --acr-connection, --instructions, and --model hidden hidden
add, delete, show, and endpoint show help, all off no voice, harness, or long running mention none
Help with only voice on, by process env var or alpha.agents.voice on --voice, prompt-voice, the voice sections, and the voice notes in add, delete, endpoint show, --acr-connection, and --model shown shown
Help with only long running on --long-running, --no-wait, its section, and invocations shown shown
Help with only managed harness on --harness stays hidden, nothing else changes as expected
init --kind prompt-voice, off refused, nothing written refused, directory empty
init --voice, off refused refused
agent add with a prompt-voice definition, off refused, azure.yaml unchanged refused, unchanged
Voice agent deploy, off refused refused
invoke on a voice agent, off refused refused
init --kind prompt-voice, with and without --voice, voice on project created created
agent add with a prompt-voice definition, voice on added added
Voice agent deploy with alpha.agents.voice on or azd env set in the selected env deployed deployed
Voice WebSocket session on the deployed agent spoken reply reply with transcript "Hello."
invoke on a voice agent, voice on gate passed, then voice guidance voice guidance error
endpoint update on a hosted voice agent, off refused, nothing written refused, project unchanged
endpoint update on a hosted voice agent, voice on gate passed, then reaches the service reached the agent endpoint
endpoint update on an ordinary hosted agent, all off not gated reached the agent endpoint
init --kind prompt --harness microsoft_copilot_preview, off refused, nothing written refused, directory empty
init -t with a harness service in the manifest, off refused, nothing written refused, directory empty
agent add with a harness definition, off refused, azure.yaml unchanged refused, unchanged
Harness deploy, off refused refused
Harness invoke, off refused refused
Harness init, init -t, and agent add, harness on work work
Harness deploy, harness on reaches the service blocked by service (403, harness not enabled for the subscription)
Harness invoke, harness on reaches the service 404, agent was never created
optimize apply on a harness agent, off refused, nothing written refused, project unchanged
optimize apply on a harness agent, harness on gate passed stopped at the missing optimization job
invoke --long-running or --long-running --no-wait on a hosted Responses agent, off refused refused
invoke --no-wait alone, off refused refused
invoke --long-running on a prompt agent, off refused refused
invoke --long-running on a hosted Responses agent, long-running on reply after a background run reply
invoke --long-running --no-wait, long-running on Response ID and follow hint ID and hint
invoke --long-running on a prompt agent, long-running on clear refusal refused as not supported for prompt agents
Long-running opt-in only in env two, run with -e two or AZD_ENVIRONMENT=two passes passes
Same, default env refused refused
Process AZD_FOUNDRY_EXT_ENABLE_AGENTS_LONG_RUNNING=true passes passes
alpha.agents.long_running true, alpha.all on, or process yes refused refused
Voice agent add and deploy with only the other two features on refused refused
Harness init, agent add, and deploy with only the other two features on refused refused
invoke --long-running with only the other two features on refused refused
Plain prompt init, deploy, invoke, ai agent show, show, endpoint show, and delete works with no opt-in works
Hosted code deploy agent init -t, deploy, invoke, ai agent show, and delete works with no opt-in works
Voice agent ai agent show, show, endpoint show, and delete, off works works
invocations show and invocations follow for a background response, off works works
down on a voice project, off works and leaves the existing project in place works
invoke --no-wait, previews off --no-wait requires --long-running as expected
invoke --long-running --local, previews off refused as supported only for remote Responses agents as expected
invoke --long-running --timeout 5, previews off timeout conflict error as expected
invoke --protocol bogus --long-running, previews off unsupported protocol error as expected
init --voice x --kind hosted, previews off voice flag error as expected
init --kind prompt-voice --deploy-mode code, previews off incompatible inputs error as expected
init --kind hosted --harness microsoft_copilot_preview, previews off --harness is only valid with --kind prompt as expected
Valid invoke --long-running, previews off refused refused
invoke --long-running -e "" and --environment "", opt-in only in the default env rejected as an empty environment rejected
invoke --no-wait -e "" local error first local error
invoke --help -e "" help renders renders
alpha.all on on a deployed prompt agent, real Azure invoke --long-running refused refused
alpha.agents.long_running on on a deployed prompt agent, real Azure gate passed, then refused for prompt agents as expected
Same with -e "", real Azure rejected as an empty environment rejected
Plain invoke and invoke -e "" on a prompt agent, no opt-in, real Azure reply reply "pong"
Historical E2E: previous head d1efa2765

These ran against the old broad Hosted Agent gate, before the three-gate split. They don't validate the current policy.

Scenario Expected at d1efa2765 Result
Flag off refuse refuse (disabled)
alpha.agents.hosted on past gate past gate
alpha.agents.hosted true (not on) refuse refuse (disabled)
Process env true past gate past gate
-e envtwo, flag only in envtwo .env past gate past gate
azd package, flag off refuse refuse (disabled)
Hosted deploy, real Azure, flag off refuse refuse (disabled)
Hosted deploy, real Azure, process env true deployed deployed

At that head only the Hosted Agent path was gated. Voice, managed harness, and long-running invocation still worked with every flag off, which is why it was replaced.

Enforcement limits

Explicit HTTP --agent-endpoint targets aren't classified. The URL doesn't say the agent's kind or harness, and this PR adds no authenticated lookup of the remote definition, so the managed harness gate can't cover that route. The long-running gate still applies before invoke. Text invoke doesn't accept voice WebSocket endpoints.

Template catalogs have no capability metadata. Entries stay visible, and the staged definition is checked before adoption instead of guessing from the template name.

azure.ai.routines and azure.ai.evaluations send requests to existing agents and aren't gated. They can't import this internal package.

Read, show, endpoint show, invocation show/follow/cancel, delete, and down stay available with flags off.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
25 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@github-actions github-actions Bot added ext-agents azure.ai.agents extension ext-foundry microsoft.foundry meta package or Foundry/AI extensions overall. Not individual extension issues. labels Oct 20, 2026
@huimiu
Hui Miao (huimiu) added this pull request to stack #10646 October 21, 2026 02:27
@huimiu
Hui Miao (huimiu) force-pushed the hui/foundry-feature-flags-hosted-agent branch from 2643837 to 5b8acda Compare October 21, 2026 03:12
@huimiu
Hui Miao (huimiu) removed this pull request from stack #10646 October 21, 2026 03:12
@huimiu
Hui Miao (huimiu) changed the base branch from hui/foundry-feature-flags-core to hui/foundry-shared-feature-access October 21, 2026 03:12
@huimiu
Hui Miao (huimiu) added this pull request to stack #10647 October 21, 2026 03:12
@huimiu Hui Miao (huimiu) changed the title feat: gate Hosted Agent path with IsFeatureEnabled feat: gate Hosted Agent path with extension feature flags Oct 21, 2026
@huimiu Hui Miao (huimiu) changed the title feat: gate Hosted Agent path with extension feature flags feat: gate Foundry agent previews independently Oct 21, 2026
@huimiu
Hui Miao (huimiu) removed this pull request from stack #10647 October 21, 2026 12:36
@huimiu
Hui Miao (huimiu) added this pull request to stack #10658 October 21, 2026 12:36
@huimiu
Hui Miao (huimiu) marked this pull request as ready for review October 21, 2026 14:16
Copilot AI lite review requested due to automatic review settings October 21, 2026 14:16

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.

🔵 Needs a closer look

One or more issues must be addressed before approval.

No open issues 🎉

What changed in this PR

Adds independent opt-ins for managed harness, voice, and long-running Foundry agent features, including centralized enforcement and help visibility controls.

Changes:

  • Adds command, service, lifecycle, and definition-level feature gates.
  • Updates help output, README/spec documentation, and interactive scenarios.
  • Adds extensive unit, integration, and snapshot coverage.
File Description
cli/​azd/​extensions/​azure.ai.agents/​tests/​cli-interactive-tester-scenarios/​tier1/​1.10-init-harness-region-restrictions.yaml Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​tests/​cli-interactive-tester-scenarios/​tier0/​0.31-preview-help-visibility.yaml Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​tests/​cli-interactive-tester-scenarios/​tier0/​0.18-invoke-long-running-validation.yaml Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​tests/​cli-interactive-tester-scenarios/​tier0/​0.10-init-picker-navigation.yaml Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​tests/​cli-interactive-tester-scenarios/​tier0/​0.02-help-root.yaml Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​README.md Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​project/​service_target_agent.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​project/​service_target_agent_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​project/​preview_features.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​project/​preview_features_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​project/​deploy_precheck_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​featureflags/​agents.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​featureflags/​agents_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​exterrors/​codes.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​testdata/​TestAgentHelpPreviewsOff-root.snap Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​testdata/​TestAgentHelpPreviewsOff-invoke.snap Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​testdata/​TestAgentHelpPreviewsOff-init.snap Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​run.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​root.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​root_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​preview_features.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​preview_features_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​preview_central_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​optimize.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​optimize_deploy.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​listen.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​invoke.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​invoke_voice_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​invoke_usage_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​invoke_usage_grpc_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​invoke_latency_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​invocations.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​init.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​init_voice_flag_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​init_from_templates_helpers.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​init_from_templates_helpers_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​init_foundry_resources_helpers_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​init_adopt.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​helpers.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​helpers_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​help_test.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​internal/​cmd/​agent_service_add.go Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​go.sum Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​docs/​specs/​preview-feature-flags.md Updated as part of this pull request.
cli/​azd/​extensions/​azure.ai.agents/​cspell.yaml Updated as part of this pull request.

Review effort: Lite

When the preview gate would reject a command, run its local argument checks first so conflicts such as --no-wait without --long-running are reported before feature_not_enabled. Bind an explicit empty --environment so preview checks reject it before reading any source.

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.

🔵 Needs a closer look

A moderate init-path gating gap remains, and preview opt-in behavior needs documentation clarification.

1 open issue

Review effort: Lite

Copilot AI lite review requested due to automatic review settings October 22, 2026 02:20

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.

🟡 Changes recommended

Three unresolved moderate issues remain in initialization gating and help-state resolution.

1 open issue
1 resolved since last review

Review effort: Lite

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/init.go
Copilot AI lite review requested due to automatic review settings October 22, 2026 03:47

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.

🟡 Changes recommended

Critical initialization-path issues remain unresolved, along with a test reliability issue.

2 open issues
1 resolved since last review

Review effort: Lite

Comment thread cli/azd/extensions/azure.ai.agents/internal/cmd/init.go
Copilot AI lite review requested due to automatic review settings October 22, 2026 06:24

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.

🟡 Changes recommended

Unresolved findings remain in harness normalization, init help scope binding, and local-template validation ordering.

3 open issues

Review effort: Lite

Comment thread cli/azd/extensions/azure.ai.agents/internal/project/preview_features.go Outdated
Copilot AI lite review requested due to automatic review settings October 22, 2026 07:15

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.

🔵 Needs a closer look

A moderate issue remains around the duplicate central preview check in init_from_code.go; the README clarification is also outstanding.

No open issues 🎉

3 resolved since last review

Review effort: Lite

@azure-sdk-automation

Copy link
Copy Markdown
Contributor

azure.ai.agents PR build

Note

This is an unsigned development build. Install it only if you trust this PR.

Install the extension:

azd ext install "https://azuresdkartifacts.z5.web.core.windows.net/azd/extensions/pr/10640/azure-ai-agents.zip"
  • Version: 1.0.0-beta.21.pr.10640.6987885
  • Merge commit: d66a6d2

Base automatically changed from hui/foundry-shared-feature-access to main October 23, 2026 01:43
Copilot AI lite review requested due to automatic review settings October 23, 2026 01:51

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.

🟡 Changes recommended

Three unresolved findings remain involving explicit-protocol validation ordering, initialization help scope resolution, and read-only azd show service-target gating.

1 open issue

Review effort: Lite

defaultResolver func() (*azdext.TargetResource, error),
) (*azdext.TargetResource, error) {
if err := p.adoptAndResolveServiceConfig(ctx, serviceConfig); err != nil {
if err := p.prepareGatedOperation(ctx, serviceConfig); err != nil {

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ext-agents azure.ai.agents extension ext-foundry microsoft.foundry meta package or Foundry/AI extensions overall. Not individual extension issues.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add preview feature flags to the agents extension

3 participants