Skip to content

Commit 526fe96

Browse files
authored
azure.ai.agents - adopt SDK root command and remove reserved flag conflicts (#7947)
* azure.ai.agents - adopt SDK root command and remove reserved flag conflicts Switch the azure.ai.agents extension to azdext.NewExtensionRootCommand so it stops registering flags that conflict with azd's reserved global flag set (--debug, --no-prompt, --environment, --output/-o). * Fix conflicts * Further refactoring
1 parent a5dd579 commit 526fe96

23 files changed

Lines changed: 302 additions & 353 deletions

cli/azd/extensions/azure.ai.agents/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ require (
1212
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerregistry/armcontainerregistry v1.3.0-beta.3
1313
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0
1414
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.3.0
15-
github.com/azure/azure-dev/cli/azd v1.23.14
15+
github.com/azure/azure-dev/cli/azd v1.24.3
1616
github.com/braydonk/yaml v0.9.0
1717
github.com/drone/envsubst v1.0.3
1818
github.com/fatih/color v1.18.0

cli/azd/extensions/azure.ai.agents/go.sum

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthoriza
1919
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v3 v3.0.0-beta.2/go.mod h1:jVRrRDLCOuif95HDYC23ADTMlvahB7tMdl519m9Iyjc=
2020
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cognitiveservices/armcognitiveservices/v2 v2.0.0 h1:pxphC/uRZKNHNPbZ0duDDgKkefju2F03OkG5xF6byHQ=
2121
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cognitiveservices/armcognitiveservices/v2 v2.0.0/go.mod h1:twcwRey+l1znKBL5TEzYiZMtiVkWfM7Pq8a9vY04xYc=
22-
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerregistry/armcontainerregistry v1.2.0 h1:DWlwvVV5r/Wy1561nZ3wrpI1/vDIBRY/Wd1HWaRBZWA=
23-
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerregistry/armcontainerregistry v1.2.0/go.mod h1:E7ltexgRDmeJ0fJWv0D/HLwY2xbDdN+uv+X2uZtOx3w=
2422
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerregistry/armcontainerregistry v1.3.0-beta.3 h1:4qfc7os3wRQcl+ImfeH9z0abWJzuV9IGcN1B9olmPTU=
2523
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerregistry/armcontainerregistry v1.3.0-beta.3/go.mod h1:NlNAngH4e++mzPTN0+1EEvyUmwFmR91u/MQUVV230Z4=
2624
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
@@ -61,8 +59,8 @@ github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWp
6159
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
6260
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
6361
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
64-
github.com/azure/azure-dev/cli/azd v1.23.14 h1:yfmEPu3T+FqFuHhHHX9gEc+yflAu0k1aDOkN00HlFzo=
65-
github.com/azure/azure-dev/cli/azd v1.23.14/go.mod h1:mS/n9XZcwRrTaDcFxWFfgcsmB6AuuTNarB2IDCS5QzI=
62+
github.com/azure/azure-dev/cli/azd v1.24.3 h1:r2kEr2YYLu4ImKo6nR/WjhHg/1SliN1uwmAVqnM8t3o=
63+
github.com/azure/azure-dev/cli/azd v1.24.3/go.mod h1:YANepMw36aWA8/mQyXau6JCAG84oK0ZgfvLF8rN5asU=
6664
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
6765
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
6866
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package cmd
5+
6+
import "github.com/azure/azure-dev/cli/azd/pkg/azdext"
7+
8+
// ensureExtensionContext returns a non-nil [azdext.ExtensionContext] so command
9+
// constructors can be safely invoked from tests with a nil receiver. The SDK's
10+
// [azdext.NewExtensionRootCommand] populates the real context (and its env-var
11+
// fallback) before any leaf RunE runs, so tests that don't exercise RunE can
12+
// safely pass nil here.
13+
func ensureExtensionContext(extCtx *azdext.ExtensionContext) *azdext.ExtensionContext {
14+
if extCtx == nil {
15+
return &azdext.ExtensionContext{}
16+
}
17+
return extCtx
18+
}

cli/azd/extensions/azure.ai.agents/internal/cmd/files.go

Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ type filesFlags struct {
2424
session string // optional: explicit session ID override
2525
}
2626

27-
func newFilesCommand() *cobra.Command {
27+
func newFilesCommand(extCtx *azdext.ExtensionContext) *cobra.Command {
28+
extCtx = ensureExtensionContext(extCtx)
29+
2830
cmd := &cobra.Command{
2931
Use: "files",
3032
Short: "Manage files in a hosted agent session.",
@@ -37,26 +39,14 @@ Agent details (name, endpoint) are automatically resolved from the
3739
azd environment. Use --agent-name to select a specific agent when the project
3840
has multiple azure.ai.agent services. The session ID is automatically resolved
3941
from the last invoke session, or can be overridden with --session-id.`,
40-
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
41-
// Chain with root's PersistentPreRunE (root sets NoPrompt).
42-
// Note: cmd.Parent() would return the "files" command itself when
43-
// a subcommand runs, causing infinite recursion.
44-
if root := cmd.Root(); root != nil && root.PersistentPreRunE != nil {
45-
if err := root.PersistentPreRunE(cmd, args); err != nil {
46-
return err
47-
}
48-
}
49-
50-
return nil
51-
},
5242
}
5343

54-
cmd.AddCommand(newFilesUploadCommand())
55-
cmd.AddCommand(newFilesDownloadCommand())
56-
cmd.AddCommand(newFilesListCommand())
57-
cmd.AddCommand(newFilesRemoveCommand())
58-
cmd.AddCommand(newFilesMkdirCommand())
59-
cmd.AddCommand(newFilesStatCommand())
44+
cmd.AddCommand(newFilesUploadCommand(extCtx))
45+
cmd.AddCommand(newFilesDownloadCommand(extCtx))
46+
cmd.AddCommand(newFilesListCommand(extCtx))
47+
cmd.AddCommand(newFilesRemoveCommand(extCtx))
48+
cmd.AddCommand(newFilesMkdirCommand(extCtx))
49+
cmd.AddCommand(newFilesStatCommand(extCtx))
6050

6151
return cmd
6252
}
@@ -74,14 +64,14 @@ type filesContext struct {
7464
}
7565

7666
// resolveFilesContext resolves agent details and session from the azd environment.
77-
func resolveFilesContext(ctx context.Context, flags *filesFlags) (*filesContext, error) {
67+
func resolveFilesContext(ctx context.Context, flags *filesFlags, noPrompt bool) (*filesContext, error) {
7868
azdClient, err := azdext.NewAzdClient()
7969
if err != nil {
8070
return nil, fmt.Errorf("failed to create azd client: %w", err)
8171
}
8272
defer azdClient.Close()
8373

84-
info, err := resolveAgentServiceFromProject(ctx, azdClient, flags.agentName, rootFlags.NoPrompt)
74+
info, err := resolveAgentServiceFromProject(ctx, azdClient, flags.agentName, noPrompt)
8575
if err != nil {
8676
return nil, err
8777
}
@@ -137,8 +127,9 @@ type FilesUploadAction struct {
137127
sessionID string
138128
}
139129

140-
func newFilesUploadCommand() *cobra.Command {
130+
func newFilesUploadCommand(extCtx *azdext.ExtensionContext) *cobra.Command {
141131
flags := &filesUploadFlags{}
132+
extCtx = ensureExtensionContext(extCtx)
142133

143134
cmd := &cobra.Command{
144135
Use: "upload [file]",
@@ -161,8 +152,6 @@ Agent details are automatically resolved from the azd environment.`,
161152
Args: cobra.MaximumNArgs(1),
162153
RunE: func(cmd *cobra.Command, args []string) error {
163154
ctx := azdext.WithAccessToken(cmd.Context())
164-
logCleanup := setupDebugLogging(cmd.Flags())
165-
defer logCleanup()
166155

167156
if len(args) > 0 && flags.file == "" {
168157
flags.file = args[0]
@@ -174,7 +163,7 @@ Agent details are automatically resolved from the azd environment.`,
174163
)
175164
}
176165

177-
fc, err := resolveFilesContext(ctx, &flags.filesFlags)
166+
fc, err := resolveFilesContext(ctx, &flags.filesFlags, extCtx.NoPrompt)
178167
if err != nil {
179168
return err
180169
}
@@ -246,8 +235,9 @@ type FilesDownloadAction struct {
246235
sessionID string
247236
}
248237

249-
func newFilesDownloadCommand() *cobra.Command {
238+
func newFilesDownloadCommand(extCtx *azdext.ExtensionContext) *cobra.Command {
250239
flags := &filesDownloadFlags{}
240+
extCtx = ensureExtensionContext(extCtx)
251241

252242
cmd := &cobra.Command{
253243
Use: "download [file]",
@@ -270,8 +260,6 @@ Agent details are automatically resolved from the azd environment.`,
270260
Args: cobra.MaximumNArgs(1),
271261
RunE: func(cmd *cobra.Command, args []string) error {
272262
ctx := azdext.WithAccessToken(cmd.Context())
273-
logCleanup := setupDebugLogging(cmd.Flags())
274-
defer logCleanup()
275263

276264
if len(args) > 0 && flags.file == "" {
277265
flags.file = args[0]
@@ -283,7 +271,7 @@ Agent details are automatically resolved from the azd environment.`,
283271
)
284272
}
285273

286-
fc, err := resolveFilesContext(ctx, &flags.filesFlags)
274+
fc, err := resolveFilesContext(ctx, &flags.filesFlags, extCtx.NoPrompt)
287275
if err != nil {
288276
return err
289277
}
@@ -359,8 +347,9 @@ type FilesListAction struct {
359347
remotePath string
360348
}
361349

362-
func newFilesListCommand() *cobra.Command {
350+
func newFilesListCommand(extCtx *azdext.ExtensionContext) *cobra.Command {
363351
flags := &filesListFlags{}
352+
extCtx = ensureExtensionContext(extCtx)
364353

365354
cmd := &cobra.Command{
366355
Use: "list [remote-path]",
@@ -385,11 +374,11 @@ Agent details are automatically resolved from the azd environment.`,
385374
azd ai agent files list --session-id <session-id>`,
386375
Args: cobra.MaximumNArgs(1),
387376
RunE: func(cmd *cobra.Command, args []string) error {
377+
flags.output = extCtx.OutputFormat
378+
388379
ctx := azdext.WithAccessToken(cmd.Context())
389-
logCleanup := setupDebugLogging(cmd.Flags())
390-
defer logCleanup()
391380

392-
fc, err := resolveFilesContext(ctx, &flags.filesFlags)
381+
fc, err := resolveFilesContext(ctx, &flags.filesFlags, extCtx.NoPrompt)
393382
if err != nil {
394383
return err
395384
}
@@ -411,7 +400,11 @@ Agent details are automatically resolved from the azd environment.`,
411400
}
412401

413402
addFilesFlags(cmd, &flags.filesFlags)
414-
cmd.Flags().StringVar(&flags.output, "output", "json", "Output format (json or table)")
403+
azdext.RegisterFlagOptions(cmd, azdext.FlagOptions{
404+
Name: "output",
405+
AllowedValues: []string{"json", "table"},
406+
Default: "json",
407+
})
415408

416409
return cmd
417410
}
@@ -486,9 +479,10 @@ type FilesRemoveAction struct {
486479
remotePath string
487480
}
488481

489-
func newFilesRemoveCommand() *cobra.Command {
482+
func newFilesRemoveCommand(extCtx *azdext.ExtensionContext) *cobra.Command {
490483
flags := &filesRemoveFlags{}
491484
var filePath string
485+
extCtx = ensureExtensionContext(extCtx)
492486

493487
cmd := &cobra.Command{
494488
Use: "delete [file]",
@@ -511,8 +505,6 @@ Agent details are automatically resolved from the azd environment.`,
511505
Args: cobra.MaximumNArgs(1),
512506
RunE: func(cmd *cobra.Command, args []string) error {
513507
ctx := azdext.WithAccessToken(cmd.Context())
514-
logCleanup := setupDebugLogging(cmd.Flags())
515-
defer logCleanup()
516508

517509
if len(args) > 0 && filePath == "" {
518510
filePath = args[0]
@@ -524,7 +516,7 @@ Agent details are automatically resolved from the azd environment.`,
524516
)
525517
}
526518

527-
fc, err := resolveFilesContext(ctx, &flags.filesFlags)
519+
fc, err := resolveFilesContext(ctx, &flags.filesFlags, extCtx.NoPrompt)
528520
if err != nil {
529521
return err
530522
}
@@ -579,9 +571,10 @@ type FilesMkdirAction struct {
579571
remotePath string
580572
}
581573

582-
func newFilesMkdirCommand() *cobra.Command {
574+
func newFilesMkdirCommand(extCtx *azdext.ExtensionContext) *cobra.Command {
583575
flags := &filesFlags{}
584576
var dirPath string
577+
extCtx = ensureExtensionContext(extCtx)
585578

586579
cmd := &cobra.Command{
587580
Use: "mkdir [dir]",
@@ -600,8 +593,6 @@ Agent details are automatically resolved from the azd environment.`,
600593
Args: cobra.MaximumNArgs(1),
601594
RunE: func(cmd *cobra.Command, args []string) error {
602595
ctx := azdext.WithAccessToken(cmd.Context())
603-
logCleanup := setupDebugLogging(cmd.Flags())
604-
defer logCleanup()
605596

606597
if len(args) > 0 && dirPath == "" {
607598
dirPath = args[0]
@@ -613,7 +604,7 @@ Agent details are automatically resolved from the azd environment.`,
613604
)
614605
}
615606

616-
fc, err := resolveFilesContext(ctx, flags)
607+
fc, err := resolveFilesContext(ctx, flags, extCtx.NoPrompt)
617608
if err != nil {
618609
return err
619610
}
@@ -671,8 +662,9 @@ type FilesStatAction struct {
671662
remotePath string
672663
}
673664

674-
func newFilesStatCommand() *cobra.Command {
665+
func newFilesStatCommand(extCtx *azdext.ExtensionContext) *cobra.Command {
675666
flags := &filesStatFlags{}
667+
extCtx = ensureExtensionContext(extCtx)
676668

677669
cmd := &cobra.Command{
678670
Use: "stat <remote-path>",
@@ -692,11 +684,11 @@ Agent details are automatically resolved from the azd environment.`,
692684
azd ai agent files stat /data/output.csv --session-id <session-id>`,
693685
Args: cobra.ExactArgs(1),
694686
RunE: func(cmd *cobra.Command, args []string) error {
687+
flags.output = extCtx.OutputFormat
688+
695689
ctx := azdext.WithAccessToken(cmd.Context())
696-
logCleanup := setupDebugLogging(cmd.Flags())
697-
defer logCleanup()
698690

699-
fc, err := resolveFilesContext(ctx, &flags.filesFlags)
691+
fc, err := resolveFilesContext(ctx, &flags.filesFlags, extCtx.NoPrompt)
700692
if err != nil {
701693
return err
702694
}
@@ -713,7 +705,11 @@ Agent details are automatically resolved from the azd environment.`,
713705
}
714706

715707
addFilesFlags(cmd, &flags.filesFlags)
716-
cmd.Flags().StringVarP(&flags.output, "output", "o", "json", "Output format (json or table)")
708+
azdext.RegisterFlagOptions(cmd, azdext.FlagOptions{
709+
Name: "output",
710+
AllowedValues: []string{"json", "table"},
711+
Default: "json",
712+
})
717713

718714
return cmd
719715
}

0 commit comments

Comments
 (0)