Commit 94d47f2
[azure.ai.agents] nextstep: surface every fix-up category after init/doctor, broaden placeholder regex
Two correctness fixes from the 3/3-consensus review of commit 4.6
(`2194327e8`). GPT-5.5 surfaced both initially; cross-pollination to
Opus 4.7 (xhigh) and Sonnet 4.6 confirmed both findings 3/3 — Sonnet
flipped its initial APPROVE after re-reading the renderer.
G1 (renderer): when ResolveAfterInit emits multiple fix-up categories
in a single state (e.g. the toolbox sample: 1 unresolved {{NAME}}
placeholder + 1 missing manual env var + the trailing `azd deploy`
reminder), PrintNext silently truncated the env-set line. PrintNext
caps total rendered lines at maxRendered=2 with one slot reserved for
the Trailing entry — so the budget for primaries is 1, and any
secondary category gets dropped on the floor. Pre-4.6 the toolbox
state was [env-set, deploy/trailing] → both rendered. Post-4.6 the
state became [placeholder, env-set, deploy/trailing] → only
[placeholder, deploy] rendered. Net effect: the user saw the
placeholder hint and the deploy reminder, but had no idea they also
needed to `azd env set TOOLBOX_WEB_SEARCH_TOOLS_MCP_ENDPOINT <value>`.
The 2-line cap exists for mid-flow resolvers (Run/Invoke/Show, all of
which produce ≤2 suggestions naturally — the cap prevents drowning
out subsequent command output). It does NOT apply to ResolveAfterInit
or doctor, both of which fire at the very END of their command with
no further output to drown. Fix: parameterize renderBlock with a
limit argument (0 = uncapped) and add a sibling `PrintAllNext`
that calls renderBlock(suggestions, 0). Switch init.go and
doctor_format.go to PrintAllNext. PrintNext semantics (and all its
existing tests) preserved byte-for-byte for the mid-flow callers
(invoke.go, run.go, show.go). Worst-case bound for the uncapped
renderer is 7 lines (3 placeholders + 3 manual vars + 1 trailing),
already capped at the resolver level by maxFixupLines=3 per category
in resolver.go.
G2 (regex): the placeholder-detection regex in state.go was
`\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}` — accepted only Go-style
identifier names. But parameters.go:237-244 substitutes the raw YAML
parameter name into the template via `fmt.Sprintf("{{%s}}", paramName)`
WITHOUT any shape validation, and yaml.go:425-431 assigns the raw
YAML key to Property.Name with no validation either. So a manifest
can legally use names like `toolbox-endpoint`, `my.component.id`, or
even quoted YAML keys containing whitespace — and 4.6's
placeholder-detection silently missed all of them. Broadened to
`\{\{\s*([^\s{}][^{}]*?)\s*\}\}` (first char must be non-whitespace
non-brace; remaining is lazy any-non-brace). Allows hyphens, dots,
and internal whitespace in paramName. Empty braces `{{}}` and
whitespace-only braces `{{ }}` correctly do NOT match (because the
first capture-group char must be non-whitespace non-brace). Picked
Sonnet's regex over Opus's `[^\s{}]+?` because Sonnet's is slightly
more permissive — covers the rare-but-valid quoted-YAML-key-with-
whitespace case. Trade-off: tiny false-positive risk (the surfaced
suggestion is benign — just an "edit agent.yaml" line — and false
negatives are the bug we're fixing, so we err toward detection).
The toolbox-sample regression is locked at two layers:
- format_test.go: a hand-crafted Suggestions slice matching the
exact toolbox state ("G1 regression repro" sub-case).
- resolver_test.go: a new end-to-end test that builds the State,
runs it through ResolveAfterInit, renders with PrintAllNext, and
asserts all three lines (placeholder, env-set, deploy) appear.
- state_test.go: extended the placeholder-extraction table with
hyphenated, dotted, empty-braces, and whitespace-only-braces cases.
- format_test.go: new TestPrintAllNext / TestPrintAllNext_Propagates
WriteError / TestPrintAllNext_EmptyInputSkipsWrite covering
empty input, single-suggestion, the G1 toolbox shape, worst-case
7-line uncapped render, and the trailing-last invariant under
uncapped mode.
Files: 7 changed.
- format.go: renderBlock(suggestions) → renderBlock(suggestions,
limit). New PrintAllNext(w, suggestions). PrintNext doc-comment
points at PrintAllNext for multi-category flows.
- state.go: placeholderPattern broadened. Doc comment cites the
YAML key examples (toolbox-endpoint, my.param, "my key") and
links to parameters.go's substitution code.
- init.go:1608, doctor_format.go:116: PrintNext → PrintAllNext.
doctor_format.go's surrounding doc-comment updated to mention
PrintAllNext rationale.
- format_test.go, state_test.go, resolver_test.go: tests as above.
Pre-flight: gofmt clean, vet clean, build clean, full extension
test suite green (cmd 17.2s, nextstep 5.8s, doctor 5.8s, agent_api
9.1s, agent_yaml 2.1s, etc.), golangci-lint 0 issues on
./internal/cmd/nextstep/... + ./internal/cmd/..., cspell 0 issues
on the 4 production files. The existing TestPrintNext suite
(including "more than two suggestions are truncated by priority"
and "trailing suggestion survives truncation when primaries fill
the block") still passes — PrintNext is unchanged.
Refs PR Azure#8057 (azd ai agent context-aware next-step guidance).
Consensus tally: G1 = GPT-5.5 (MEDIUM) + Sonnet (High, flipped) +
Opus (Medium, acknowledged miss) = 3/3. G2 = GPT-5.5 (Low) +
Sonnet (Low) + Opus (Low) = 3/3.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent 961cf10 commit 94d47f2
7 files changed
Lines changed: 236 additions & 12 deletions
File tree
- cli/azd/extensions/azure.ai.agents/internal/cmd
- nextstep
Lines changed: 6 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
86 | 86 | | |
87 | 87 | | |
88 | 88 | | |
89 | | - | |
| 89 | + | |
90 | 90 | | |
91 | | - | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
92 | 95 | | |
93 | 96 | | |
94 | 97 | | |
| |||
113 | 116 | | |
114 | 117 | | |
115 | 118 | | |
116 | | - | |
| 119 | + | |
117 | 120 | | |
118 | 121 | | |
119 | 122 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2017 | 2017 | | |
2018 | 2018 | | |
2019 | 2019 | | |
2020 | | - | |
| 2020 | + | |
2021 | 2021 | | |
2022 | 2022 | | |
2023 | 2023 | | |
| |||
Lines changed: 32 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
34 | 38 | | |
35 | | - | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
36 | 62 | | |
37 | 63 | | |
38 | 64 | | |
| |||
65 | 91 | | |
66 | 92 | | |
67 | 93 | | |
68 | | - | |
69 | | - | |
70 | | - | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
71 | 99 | | |
72 | 100 | | |
73 | 101 | | |
| |||
Lines changed: 110 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
144 | 144 | | |
145 | 145 | | |
146 | 146 | | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
147 | 257 | | |
148 | 258 | | |
149 | 259 | | |
| |||
Lines changed: 29 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
107 | 107 | | |
108 | 108 | | |
109 | 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 | + | |
110 | 139 | | |
111 | 140 | | |
112 | 141 | | |
| |||
Lines changed: 12 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
69 | 77 | | |
70 | 78 | | |
71 | 79 | | |
| |||
Lines changed: 46 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
571 | 571 | | |
572 | 572 | | |
573 | 573 | | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
574 | 620 | | |
575 | 621 | | |
576 | 622 | | |
| |||
0 commit comments