azd ai agent init: unified azure.yaml path defers model config without saying so, and claims --no-prompt when it wasn't passed
- Dominant language
- Go
- Stars
- 569
- Forks
- 364
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 136
Description
### Summary
`azd ai agent init -m ` can silently produce a project missing
`AZURE_AI_MODEL_DEPLOYMENT_NAME`, which fails later at agent runtime with a `KeyError`.
Two distinct defects:
1. **The deferral is reported as `--no-prompt` even when that flag was never passed.**
2. **The unified `azure.yaml` path suppresses the "model configuration was deferred" warning** that
the legacy `agent.manifest.yaml` path prints, because of a hardcoded `false`.
### Defect 1 — misleading message, and it isn't limited to `--no-prompt`
Running **without** `--no-prompt`, on a pty (`pty.fork`, so stdin/stdout/stderr are all char
devices), no `CI` variable set:
```
Missing Azure environment values: AZURE_SUBSCRIPTION_ID, AZURE_LOCATION. Continuing because --no-prompt was specified.
```
No flag was specified. The user is told they asked for this, which sends them looking for a flag
they never passed rather than at their Azure context.
The real gate is `InteractiveInfo.CanPrompt()` (`pkg/azdext/tui.go`):
```go
func (i InteractiveInfo) CanPrompt() bool {
return i.StdinTTY && i.StdoutTTY && !i.NoPrompt && !i.CI && !i.Agent
}
```
`i.Agent` is set from `agentEnvVars`:
```go
var agentEnvVars = []string{
"CLAUDE_CODE", "CLAUDE_CODE_ENTRYPOINT", "GITHUB_COPILOT_CLI", "GH_COPILOT",
"GEMINI_CLI", "GEMINI_CLI_NO_RELAUNCH", "OPENCODE", "AZURE_DEV_AGENT_TYPE",
}
```
So **CI pipelines and AI-coding-agent sessions are forced down this path with no flag**, and given
how many users now drive `azd` through a coding agent, that is a meaningful blast radius. The
message should name the detected reason (non-TTY / CI / agent / explicit flag) instead of asserting
`--no-prompt`.
### Defect 2 — the deferred-model warning is suppressed on the azure.yaml path
Both paths call the same helper; only one reports model deferral:
```go
// init_foundry_project_setup.go:96 — unified azure.yaml (adopt) path
configureDeferredInitAzureContext(ctx, azdClient, envName, azureContext, false)
// ^^^^^ always false
```
```go
// init.go:2474 — legacy agent.manifest.yaml path
hasModelResources := manifestHasModelResources(agentManifest)
configureDeferredInitAzureContext(ctx, ..., hasModelResources)
```
That flag gates this block in `configureDeferredInitAzureContext`:
```go
if hasModelResources {
"Model resource configuration was deferred because model lookup requires the missing Azure values."
"Set the missing values, then re-run init to resolve model deployments automatically."
}
```
`manifestHasModelResources` reads `AgentManifest.Resources`, only populated for the legacy
`template:` manifest — so a unified `azure.yaml` reports `false` regardless, even when its
`services..deployments:` block was in fact deferred.
### Repro
```sh
mkdir probe && cd probe
azd ai agent init \
-m "https://github.com/microsoft-foundry/foundry-samples/blob/main/samples/python/hosted-agents/agent-framework/responses/01-basic/azure.yaml" \
--agent-name probe-agent
```
`.azure//.env` has no `AZURE_AI_MODEL_DEPLOYMENT_NAME`, while the generated `azure.yaml` still
contains `value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}` — it resolves to empty, so `main.py`'s
`os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"]` raises `KeyError` at run time.
The identical command in a directory whose azd env already has `AZURE_SUBSCRIPTION_ID` and
`AZURE_LOCATION` sets it correctly to `gpt-5.4-mini`. That is the only differing variable.
Verified on `azd` 1.31.2, `azure.ai.agents` 1.0.0-beta.11, across three harnesses: `--no-prompt`;
piped stdin without the flag; and `pty.fork` without the flag. All three defer identically.
### Scope I could not verify
I have no genuine interactive terminal in my environment, so I could **not** confirm the behaviour
for a human at a real TTY. Reading `CanPrompt()`, that case should prompt for subscription/location
and set the variable correctly. Treat the interactive path as unverified here rather than as known
good or known broken.
### Why the printed remediation doesn't recover
Setting `AZURE_SUBSCRIPTION_ID` / `AZURE_LOCATION` afterwards doesn't re-run deployment
verification, and `deploymentEnvUpdate` (`listen.go`) writes only `AI_PROJECT_DEPLOYMENTS` — never
`AZURE_AI_MODEL_DEPLOYMENT_NAME`. The project stays broken until `init` is re-run or the variable is
set by hand, and the message suggests neither.
### Suggested fixes
1. Report the actual reason for skipping prompts rather than blaming `--no-prompt`.
2. Base the deferral warning on what the adopted `azure.yaml` declares:
```go
hasDeployments := len(foundryDeployments(content)) > 0
configureDeferredInitAzureContext(ctx, azdClient, envName, azureContext, hasDeployments)
```
3. Optionally, when verification is skipped but `azure.yaml` declares exactly one deployment, fall
back to `persistFirstDeploymentName` with the declared name — no Azure call required, and it is
the same value verification would pick.
### Is it a regression?
Not of the adoption path — the gap has existed since it shipped. But it is a regression in effect
for anyone following the samples, because the ecosystem moved onto the path that lost the
diagnostic:
| date | change |
|---|---|
| 2026-06-24 (#8656) | Deferral warning added, including the `hasModelResources` branch |
| 2026-07-01 (#8885) | Unified `azure.yaml` adoption path added to `azd ai agent init -m` |
| 2026-07-02 (#8933) | Adoption path gains context setup, verification and `persistFirstDeploymentName`; deferral call site written with a literal `false` |
| 2026-07-07 | `foundry-samples` migrates hosted-agent samples to unified `azure.yaml` |
Earlier revisions of this issue claimed the model env-var binding was missing entirely after the
unified `azure.yaml` migration, and later that impact was limited to explicit `--no-prompt`. Both
were wrong: `persistFirstDeploymentName` handles the binding correctly when Azure context is
present, and the deferral triggers without any flag. Rescoped to the actual defects.
Contributor guide
Research direction
Start with InteractiveInfo.CanPrompt in pkg/azdext/tui.go, then compare the call sites in init_foundry_project_setup.go and init.go for configureDeferredInitAzureContext; listen.go documents the related environment update behavior. Run the provided azd ai agent init reproduction and inspect the adopted azure.yaml deployment data. Done means skipped-prompt messages identify the actual reason, and unified azure.yaml adoption reports model deferral when deployments were deferred.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, go
- Domain
- ai, cli, cloud
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100