Commit d003b46
feat(azure.ai.agents): add doctor check
Adds the 7th local doctor check, surfacing the same MissingManualVars
signal that the post-init `Next:` block renders — but at any point in
the flow (post-deploy, mid-debug, before reporting a bug). Closes the
"manual config values missing" branch from issue Azure#7975
lines 117-127 on the doctor side.
## Why
The doctor's job is to short-circuit user frustration: "I get the same
guidance from `azd ai agent doctor` regardless of where I am in the
flow." Today the manual-vars signal only surfaces at the tail of `azd
ai agent init`, so a user who hits the issue mid-cycle (e.g. they
cloned a friend's project, ran `azd env select`, and went straight to
`azd ai agent run`) sees no clear pointer to the missing config.
## What
- `internal/cmd/doctor/checks_manual_env.go` — new check produces ID
`local.manual-env-vars`, name "manual env vars set". On Pass, message
is "no manual env vars are missing"; on Fail, lists every missing var
in the message and stages a paste-ready `azd env set <FIRST> <value>`
suggestion (sorted alphabetically — the renderer paints Suggestion as
a single line, multi-line breaks indentation). When 2+ vars are
missing the suggestion adds a "Repeat for each of the other
variables listed above." clause; when exactly 1 is missing the bare
command is the suggestion (no misleading "and others" wording).
- `internal/cmd/doctor/checks_local.go` — adds the check as the 7th
entry in `NewLocalChecks` (after `local.agent-yaml-valid`); introduces
a lowercase `assembleState` field on the exported `Dependencies`
struct as a test seam (production code leaves it nil; tests inject
directly).
- Skip cascade: skips when AzdClient is nil OR when
`local.agent-yaml-valid` failed/skipped OR when
`local.environment-selected` failed/skipped. The first guard
transitively covers azure-yaml → agent-service-detected →
agent-yaml-valid; the second is required because env-selection is a
sibling chain (not upstream of agent-yaml-valid) and
`nextstep.AssembleState` silently early-exits its detectMissingVars
block when no env is selected (state.go: `if project != nil &&
envName != ""`). Without the env guard the check would falsely Pass
in a state where no env values were ever examined.
## Architecture: why reuse `nextstep.AssembleState`
The "manual vs infra" classification logic lives in nextstep — the same
place that drives every other `Next:` recommendation. Adding a separate
classifier inside the doctor would split the source of truth, and
future improvements (e.g. C1's Bicep-output discovery replacing the
`AZURE_` prefix shortcut) would have to be ported twice. Forwarding to
`AssembleState` keeps the doctor as a presentation layer.
## Tests
12 new sub-tests in `checks_manual_env_test.go`:
- No client → Skip
- Prior `local.agent-yaml-valid` failed → Skip
- Prior `local.agent-yaml-valid` skipped → Skip (cascade propagation)
- Prior `local.environment-selected` failed → Skip (regression for
Opus xhigh review HIGH finding; asserts assembler is NOT called via
t.Fatalf in the fake)
- Prior `local.environment-selected` skipped → Skip (symmetric)
- 0 missing → Pass with "no manual env vars are missing"
- 1 missing → Fail with bare `azd env set <NAME> <value>` suggestion
(asserts no "Repeat" / "likewise" wording — regression for Sonnet
4.6 review MEDIUM finding)
- 4 missing → Fail with sorted list; suggestion has "Repeat for each
of the other variables" clause
- nil State from assembler → Fail with assembly error message
- nil State + nil errs → Fail with fallback "unknown error" message
- Non-fatal errs but State populated → Pass (state.MissingManualVars
is the authoritative signal; ancillary errors like missing
AI_AGENT_PENDING_PROVISION key don't dirty the result)
- Existing `TestNewLocalChecks_OrderAndIDs` extended from 6 to 7 checks;
new `TestNewLocalChecks_IncludesManualEnvVarsLast` pins the
agent-yaml-valid → manual-env-vars ordering invariant so a future
reorder can't silently break the skip-cascade.
## Out of scope
- Bicep-output classifier (B1 fix / C1) — `assembleState` today routes
non-`AZURE_*` Bicep outputs (e.g. `TOOLBOX_*`) into MissingManualVars
rather than MissingInfraVars. This check will surface that bug
verbatim until C1 lands; that's the correct phasing because (a)
every Phase 5 consumer benefits from the same fix at once, and (b)
showing the current behavior in the doctor makes the bug debuggable
in the meantime.
Refs: Azure#7975 lines 117-127, 308-312 (issue spec)
Refs: Azure#8057 (PR being implemented)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>local.manual-env-vars (P5.1 C9)1 parent d8d5aba commit d003b46
4 files changed
Lines changed: 482 additions & 3 deletions
File tree
- cli/azd/extensions/azure.ai.agents/internal/cmd/doctor
Lines changed: 16 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
| 13 | + | |
12 | 14 | | |
13 | 15 | | |
14 | 16 | | |
| |||
39 | 41 | | |
40 | 42 | | |
41 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
42 | 52 | | |
43 | 53 | | |
44 | 54 | | |
45 | | - | |
| 55 | + | |
46 | 56 | | |
47 | | - | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
48 | 61 | | |
49 | 62 | | |
50 | 63 | | |
| |||
53 | 66 | | |
54 | 67 | | |
55 | 68 | | |
| 69 | + | |
56 | 70 | | |
57 | 71 | | |
58 | 72 | | |
| |||
Lines changed: 2 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
443 | 443 | | |
444 | 444 | | |
445 | 445 | | |
446 | | - | |
| 446 | + | |
447 | 447 | | |
448 | 448 | | |
449 | 449 | | |
| |||
456 | 456 | | |
457 | 457 | | |
458 | 458 | | |
| 459 | + | |
459 | 460 | | |
460 | 461 | | |
461 | 462 | | |
| |||
Lines changed: 144 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
0 commit comments