feat(agents): reuse existing agent.yaml on init from existing code#8326
Open
hund030 wants to merge 4 commits into
Open
feat(agents): reuse existing agent.yaml on init from existing code#8326hund030 wants to merge 4 commits into
hund030 wants to merge 4 commits into
Conversation
📋 Prioritization NoteThanks for the contribution! The linked issue isn't in the current milestone yet. |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the azd ai agent init flow in the Azure AI Agents extension to detect an existing bare agent.yaml (definition-only, no template: wrapper) and reuse it instead of overwriting/failing, aligning with #7268.
Changes:
- Add a pre-dispatch detection step in
initto find and optionally reuse an existing bare agent definition YAML. - Remove the earlier
agent.yaml already existsguard from the from-code init path (intended to be handled by the new upstream dispatch). - Add a new reuse implementation that loads an existing definition and wires it into
azure.yamlwithout rewriting the definition file.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
cli/azd/extensions/azure.ai.agents/internal/cmd/init.go |
Adds detection/prompting to reuse an existing bare agent definition before prompting for init mode / scaffolding. |
cli/azd/extensions/azure.ai.agents/internal/cmd/init_from_code.go |
Removes the pre-flight overwrite protection for existing agent.yaml in the from-code path. |
cli/azd/extensions/azure.ai.agents/internal/cmd/init_from_code_reuse.go |
New helpers to locate, parse, and reuse an existing definition file and update azure.yaml. |
Comments suppressed due to low confidence (1)
cli/azd/extensions/azure.ai.agents/internal/cmd/init_from_code.go:87
- The overwrite guard for an existing agent.yaml was removed, but writeDefinitionToSrcDir still unconditionally writes srcDir/agent.yaml. If the user declines the new “reuse existing definition” prompt upstream, the from-code path will now silently overwrite the existing file (data loss). Reintroduce an overwrite confirmation here (or ensure init.go treats “decline reuse” as a cancellation / requires --force before overwriting).
// No manifest pointer provided - process local agent code
// Create a definition based on user prompts
localDefinition, err := a.createDefinitionFromLocalAgent(ctx)
if err != nil {
return fmt.Errorf("failed to create definition from local agent: %w", err)
hund030
added a commit
that referenced
this pull request
May 25, 2026
Five fixes plus targeted unit tests, in response to inline review on #8326. - Use go.yaml.in/yaml/v3 in init_from_code_reuse.go so custom UnmarshalYAML methods on agent_yaml types (e.g. PropertySchema) are honored. The package previously used gopkg.in/yaml.v3 which has an incompatible Node type and silently bypassed custom decoders. - Run agent_yaml.ValidateAgentDefinition on the loaded bytes so missing or invalid kind, structural shape, etc. fail fast with the same error the manifest pipeline produces, instead of slipping through and failing later. - Walk agentYamlCandidates in addToProject's language-detection block instead of hardcoding 'agent.yaml', so dotnet runtimes declared in agent.yml are detected correctly. - Replace hardcoded 'agent.yaml' in user-facing error/info messages with displayPath, so the reuse path correctly references agent.yml or agent.manifest.yaml when those are the detected file. - Mirror InitFromCodeAction.Run's absolute --src normalization: convert an absolute path to a project-relative path before calling addToProject so azure.yaml's RelativePath stays portable. Unit tests added in init_from_code_reuse_test.go cover findExistingAgentYaml (filename precedence, shallow scan, dir-vs-file), loadAgentDefinitionFile (happy path, missing kind, invalid name, manifest-shaped rejection, broken yaml), and the runReuseDefinition failure paths that surface CodeInvalidAgentManifest without needing the project gRPC mock.
Closes #7268. When `azd ai agent init` runs in a directory that already contains a bare `agent.yaml` definition, the from-code action now detects and reuses it instead of either prompting to overwrite (interactive) or failing fast with `CodeInvalidAgentManifest: agent.yaml already exists at ...` (--no-prompt mode, added in #8266). The reuse path: - Validates the file as a bare AgentDefinition (rejects manifest-shaped files that fail upstream detectLocalManifest validation with a targeted error). - Skips the model / instructions / runtime / entry-point prompt sequence in createDefinitionFromLocalAgent. - Ensures an azd environment exists (the prompt sequence normally bootstraps this) and calls the existing addToProject helper. - Never rewrites the on-disk agent.yaml — it is treated as authoritative. Valid local manifest files (top-level `template:`) are unchanged: they continue to be intercepted upstream by detectLocalManifest in init.go and routed through runInitFromManifest before InitFromCodeAction.Run is reached. Design spec: cli/azd/docs/design/azure-ai-agent-init-reuse-agent-yaml.md
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.
Five fixes plus targeted unit tests, in response to inline review on #8326. - Use go.yaml.in/yaml/v3 in init_from_code_reuse.go so custom UnmarshalYAML methods on agent_yaml types (e.g. PropertySchema) are honored. The package previously used gopkg.in/yaml.v3 which has an incompatible Node type and silently bypassed custom decoders. - Run agent_yaml.ValidateAgentDefinition on the loaded bytes so missing or invalid kind, structural shape, etc. fail fast with the same error the manifest pipeline produces, instead of slipping through and failing later. - Walk agentYamlCandidates in addToProject's language-detection block instead of hardcoding 'agent.yaml', so dotnet runtimes declared in agent.yml are detected correctly. - Replace hardcoded 'agent.yaml' in user-facing error/info messages with displayPath, so the reuse path correctly references agent.yml or agent.manifest.yaml when those are the detected file. - Mirror InitFromCodeAction.Run's absolute --src normalization: convert an absolute path to a project-relative path before calling addToProject so azure.yaml's RelativePath stays portable. Unit tests added in init_from_code_reuse_test.go cover findExistingAgentYaml (filename precedence, shallow scan, dir-vs-file), loadAgentDefinitionFile (happy path, missing kind, invalid name, manifest-shaped rejection, broken yaml), and the runReuseDefinition failure paths that surface CodeInvalidAgentManifest without needing the project gRPC mock.
e5e1c69 to
7fd6728
Compare
Five Copilot findings on the new reuse path: - Lang detection in addToProject (init_from_code.go) restricted to agent.yaml / agent.yml so a leftover agent.manifest.* does not short-circuit detection before the actual definition file is read. - agentYamlCandidates reordered to match detectLocalManifest in init_from_templates_helpers.go (manifest.yaml -> yaml -> manifest.yml -> yml). - errors.As replaced with errors.AsType[T] in init_from_code_reuse_test.go per the cli/azd/AGENTS.md Go 1.26 modernization rule. - Overwrite guard restored inside InitFromCodeAction.Run so the from-code scaffold cannot silently overwrite an existing agent.yaml when the user declined the reuse prompt in RunE. Matches the safety invariant from #8266 (--no-prompt fails fast; interactive defaults to no). Also trims verbose doc and inline comments across the touched files.
hund030
added a commit
that referenced
this pull request
May 25, 2026
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.
Closes #7268.
Summary
When
azd ai agent initruns in a directory that already contains a bareagent.yamldefinition (notemplate:wrapper), reuse it instead of either prompting to overwrite (interactive) or failing withCodeInvalidAgentManifest: agent.yaml already exists at ...(--no-prompt, added in #8266). Matches the issue's wording: "if it's a definition, then we have less to ask and just setup azure.yaml."The manifest half of the issue is already handled by upstream
detectLocalManifestand is unchanged.Changes
cmd/init.goRunE: new detection block alongsidedetectLocalManifest. A user with a localagent.yamlskips both the init-mode prompt and the from-code scaffolding. Symmetric confirmation prompt (auto-yes under--no-prompt). TracksmanifestDetectedButDeclinedso a declined manifest is not re-discovered and mis-classified.cmd/init_from_code.go: retained theagent.yaml already existsguard from add 'azd ai agent sample list' to browse templates and improve non-interactive init #8266 (usingfindExistingAgentYamlso it covers all four candidate filenames). The guard now only fires on the decline-reuse fallback path (user declines theRunEprompt and then picks "Use the code in the current directory"); it prevents silent overwrite. Lang detection inaddToProjectis limited to bare-definition filenames so a leftover manifest cannot short-circuit detection.cmd/init_from_code_reuse.go(new):findExistingAgentYaml,runReuseDefinition,loadAgentDefinitionFile. Runs fullagent_yaml.ValidateAgentDefinition(catches missing/invalid kind, name format, kind-specific structural checks), bootstraps project + env, normalizes absolute--srcto project-relative, calls existingaddToProject. Error/info messages use the actual detected filename so users withagent.ymlseeagent.yml, not a hardcodedagent.yaml. The on-disk file is never rewritten.AZURE_AI_PROJECT_IDor use the manifest pipeline.Unit tests in
cmd/init_from_code_reuse_test.gocoverfindExistingAgentYaml(filename precedence, shallow scan),loadAgentDefinitionFile(happy path + reject manifest-shaped, missing kind, invalid name, broken yaml), and therunReuseDefinitionfailure branches that short-circuit before any azd gRPC calls.Verification
Manual e2e on Windows against the locally-built CLI:
agent.yaml+--no-promptagent.yaml already exists at ...exit 1agent.yamlinteractive, accept reuse promptagent.yamlinteractive, decline reuse prompt -> pick "from code" modeagent.manifest.yamlagent.yamlCodeInvalidAgentManifestreferencing the actual filenameagent.yamlRelated
azd ai agent initto detect and reuse an existing agent.yaml #7268