doc: design spec for azd ai agent init reuse of existing agent.yaml#8325
Open
hund030 wants to merge 4 commits into
Open
doc: design spec for azd ai agent init reuse of existing agent.yaml#8325hund030 wants to merge 4 commits into
hund030 wants to merge 4 commits into
Conversation
During implementation we discovered the manifest case is already handled upstream by detectLocalManifest in init.go, and our reuse helper only owns the bare-definition case. Update the spec to reflect that — narrow the scope, remove the dead reuseLocalManifest sub-section, and update file references to current main.
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a design spec documenting the planned change to azd ai agent init (Azure AI Agents extension) to detect and reuse an existing bare agent.yaml definition in the target directory, avoiding overwrite prompts/fail-fast behavior and only writing the azure.yaml service entry.
Changes:
- Introduces a new design document describing dispatch ordering, reuse flow, and error handling for existing bare
agent.yaml. - Documents key design decisions (where detection happens, non-goals like Foundry project resolution, and why manifest reuse is left to existing logic).
- Provides a decision tree and test plan guidance for the intended behavior.
|
|
||
| This change adds **definition reuse**: when the user has a bare `agent.yaml` (a YAML file without a top-level `template:` wrapper) in the target directory and runs `azd ai agent init`, the command treats that file as the source of truth, skips the from-code prompts, and writes only the `azure.yaml` service entry, matching the issue's wording: *"if it's a definition, then we have less to ask and just setup azure.yaml."* | ||
|
|
||
| Manifest reuse (the other half of the issue) is already handled by upstream `detectLocalManifest` in `init.go`, which intercepts valid local manifests (regardless of filename) and routes them through `runInitFromManifest`. This spec does **not** touch that path; it only fills the bare-definition gap. |
Comment on lines
+56
to
+59
| 1. `detectLocalManifest(srcDir)`: existing helper, runs first. If it returns a valid manifest path, `flags.manifestPointer` is set (with an optional confirmation prompt in interactive mode) and the manifest pipeline runs as today. | ||
| 2. **If `flags.manifestPointer` is still empty**, the new step runs: `findExistingAgentYaml(srcDir)` does a shallow `os.Stat` against the four candidate filenames. Any hit at this point is guaranteed to either be a bare definition (rejected by `detectLocalManifest` for lacking `template:`) or a malformed manifest (rejected for failing manifest validation). | ||
| 3. On a hit, a confirmation prompt ("An existing agent definition was found at ... Use it?") is shown; in `--no-prompt` mode the answer auto-defaults to yes. | ||
| 4. On confirmation, `runReuseDefinition(ctx, flags, azdClient, httpClient, srcDir, existingPath)` is called and the command returns. The init-mode prompt and the from-code scaffolding sequence are both skipped. |
Comment on lines
+40
to
+44
| | Upstream manifest detection | `cmd/init.go` (`detectLocalManifest`) | **Unchanged**. | | ||
| | Manifest pipeline | `cmd/init.go` (`runInitFromManifest`) | **Unchanged**. | | ||
| | Definition reuse helpers | `cmd/init_from_code_reuse.go` (new file) | `findExistingAgentYaml`, `runReuseDefinition`, `loadAgentDefinitionFile`. | | ||
| | `azure.yaml` writer | `cmd/init_from_code.go` (`addToProject`) | **Reused as-is** by `runReuseDefinition`. | | ||
| | Project / environment bootstrap | `cmd/init.go` (`ensureProject`, `getExistingEnvironment`, `createNewEnvironment`) | **Reused as-is**: the reuse path runs the same setup `runInitFromManifest` does. | |
Comment on lines
+120
to
+126
| ## 7. Test Plan | ||
|
|
||
| - **Pre-existing unit tests** in `cli/azd/extensions/azure.ai.agents/internal/cmd/*_test.go` continue to pass. The no-yaml regression is covered by today's `init_from_code_test.go`. | ||
| - **Manual e2e** against the locally-built `azd` + extension. Three scenarios: | ||
| - **Definition reuse**: write a bare `agent.yaml`, run `azd ai agent init --no-prompt`; assert no init-mode prompt, `Detected existing agent definition: ...` printed, `azure.yaml` contains the agent's `name:`, on-disk `agent.yaml` byte-identical to input. | ||
| - **Manifest reuse**: write `agent.manifest.yaml`, run with `AZURE_SUBSCRIPTION_ID` and `AZURE_AI_PROJECT_ID` set; assert the existing upstream manifest path runs unchanged and `azure.yaml` ends up with the manifest's `template.name`. | ||
| - **Invalid yaml**: write broken YAML; assert non-zero exit, error references `agent.yaml`, `azure.yaml` not mutated. |
|
|
||
| 1. `loadAgentDefinitionFile(path)`: reads the file, rejects anything with a top-level `template:` (manifest-shaped but invalid, produces a targeted error), unmarshals to `agent_yaml.ContainerAgent` so `CodeConfiguration` is preserved, and validates the name via `agent_yaml.ValidateAgentName`. | ||
| 2. Prints `Detected existing agent definition: <relative-path> (name: <def.Name>).` | ||
| 3. Bootstraps project + env using the same helpers `runInitFromManifest` uses: `ensureProject`, then `getExistingEnvironment` / `createNewEnvironment` (the env is named `<def.Name>-dev` when none was supplied via `-e`). |
📋 Prioritization NoteThanks for the contribution! The linked issue isn't in the current milestone yet. |
- Tighten manifest-detection wording: detectLocalManifest scans four fixed filenames, not arbitrary ones. - Correct file-location references in the touch-points table (detectLocalManifest lives in init_from_templates_helpers.go; createNewEnvironment lives in init_foundry_resources_helpers.go). - Document the declined-manifest edge case: when detectLocalManifest finds a valid manifest that the user declines, the reuse scan must be skipped so the declined file is not mis-classified as an invalid definition. - Note that the derived env name goes through sanitizeAgentName to match the existing from-code path. - Test plan: remove the inaccurate claim that init_from_code_test.go covers the no-yaml regression; clarify the existing unit tests cover unrelated helpers and that the new paths are exercised by manual e2e instead.
hund030
added a commit
that referenced
this pull request
May 25, 2026
Copilot review of #8325 caught an edge case in the lifted dispatch: when detectLocalManifest finds a valid manifest in srcDir but the user declines the 'Use it?' prompt, flags.manifestPointer stays empty and the new definition reuse scan would re-discover the same on-disk file. The bare definition loader rejects files with a top-level 'template:' key, so the declined manifest would be reported as an invalid definition with CodeInvalidAgentManifest, blocking init and contradicting the user's choice to start fresh. Track the decline explicitly with a manifestDetectedButDeclined flag and gate the definition reuse scan on it being false. Non-interactive mode is unaffected because --no-prompt auto-accepts the manifest.
Collaborator
Author
|
Thanks for the careful review. Summary of how each comment was addressed:
|
hund030
added a commit
that referenced
this pull request
May 25, 2026
Copilot review of #8325 caught an edge case in the lifted dispatch: when detectLocalManifest finds a valid manifest in srcDir but the user declines the 'Use it?' prompt, flags.manifestPointer stays empty and the new definition reuse scan would re-discover the same on-disk file. The bare definition loader rejects files with a top-level 'template:' key, so the declined manifest would be reported as an invalid definition with CodeInvalidAgentManifest, blocking init and contradicting the user's choice to start fresh. Track the decline explicitly with a manifestDetectedButDeclined flag and gate the definition reuse scan on it being false. Non-interactive mode is unaffected because --no-prompt auto-accepts the manifest.
Updates the spec to match what was actually shipped in PR #8326: - §3 / §9 #8: overwrite guard inside InitFromCodeAction.Run is now documented as retained (covering all four candidate filenames), not removed. §4.6 added to describe the decline-reuse fallback path. - §3 / §4.2 / §6 / §9 #7: validation switched from ValidateAgentName to ValidateAgentDefinition so missing/invalid kind, name format, and kind-specific structural checks are caught. - §3: language detection inside addToProject is limited to bare-definition filenames; lookup table updated to reflect that. - §4.2: runReuseDefinition now includes the absolute-src normalization step and a displayPath-aware `Reusing existing <file>` message. - §4.3 / §6: error suggestion text uses displayPath, not hardcoded `agent.yaml`. - §5: new row for the declined-reuse fallback; --src row notes abs->rel. - §7: documents the actual unit tests that now ship in init_from_code_reuse_test.go. - §10: decision tree expanded to cover the manifest-decline branch, the init-mode prompt with the overwrite guard, and the abs-src step.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the design spec for #7268: when
azd ai agent initruns in a directory that already contains a bareagent.yamldefinition, reuse it instead of prompting to overwrite (interactive) or failing fast (--no-prompt, behavior added in #8266).The manifest half of the issue is documented as already handled by upstream
detectLocalManifest; this work fills only the bare-definition gap.Highlights for review
RunEnext todetectLocalManifest, not insideInitFromCodeAction.Run(avoids forcing users through the init-mode prompt before reuse fires).InitFromCodeAction.Runis retained as a safety net for the decline-reuse fallback path (user declines the reuse prompt and then picks "Use the code in the current directory").loadAgentDefinitionFileruns fullValidateAgentDefinition(kind + name + structural checks), not just name validation.Related
azd ai agent initto detect and reuse an existing agent.yaml #7268