-
Notifications
You must be signed in to change notification settings - Fork 288
Rebrand agent UX to GitHub Copilot and improve prompt quality #7194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -283,7 +283,7 @@ func (i *initAction) Run(ctx context.Context) (*actions.ActionResult, error) { | |||||
|
|
||||||
| if i.featuresManager.IsEnabled(agentcopilot.FeatureCopilot) { | ||||||
| followUp += fmt.Sprintf("\n\n%s Run %s to deploy project to the cloud.", | ||||||
| color.HiMagentaString("Next steps:"), | ||||||
| output.WithHintFormat("(→) NEXT STEPS:"), | ||||||
| output.WithHighLightFormat("azd up")) | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -409,7 +409,11 @@ func (i *initAction) initAppWithAgent(ctx context.Context, azdCtx *azdcontext.Az | |||||
| if dirty { | ||||||
| defaultNo := false | ||||||
| confirm := uxlib.NewConfirm(&uxlib.ConfirmOptions{ | ||||||
| Message: "Your working directory has uncommitted changes. Continue initializing?", | ||||||
| Message: "Your working directory has uncommitted changes. Continue initializing?", | ||||||
| HelpMessage: fmt.Sprintf( | ||||||
| "%s may create or modify files in your working directory. "+ | ||||||
| "Consider committing or stashing your changes first to avoid losing work.", | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe drop the "losing work" blurb because there are so many other reasons you might want to do this (easily seeing all the changes in a diff, trying again with a higher reasoning effort, ...)?
Suggested change
|
||||||
| agentcopilot.DisplayTitle), | ||||||
| DefaultValue: &defaultNo, | ||||||
| }) | ||||||
| result, promptErr := confirm.Ask(ctx) | ||||||
|
|
@@ -422,12 +426,14 @@ func (i *initAction) initAppWithAgent(ctx context.Context, azdCtx *azdcontext.Az | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| // Show alpha warning | ||||||
| // Show preview notice | ||||||
| i.console.MessageUxItem(ctx, &ux.MessageTitle{ | ||||||
| Title: fmt.Sprintf("Agentic mode init is in preview. The agent will scan your repository and "+ | ||||||
| "attempt to make an azd-ready template to init.\nYou can always change permissions later "+ | ||||||
| "by running %s. Mistakes may occur in agent mode.\n\n"+ | ||||||
| "To learn more, go to %s", | ||||||
| Title: fmt.Sprintf( | ||||||
| "%s will scan your repository and help generate an azd compatible project to get you started. "+ | ||||||
| "This experience is currently in preview.\n\n"+ | ||||||
| "You can always change permissions later by running %s.\n\n"+ | ||||||
| "To learn more, go to %s", | ||||||
| agentcopilot.DisplayTitle, | ||||||
| output.WithHighLightFormat("azd copilot consent"), | ||||||
| output.WithLinkFormat("https://aka.ms/azd-feature-stages")), | ||||||
| }) | ||||||
|
|
@@ -486,7 +492,9 @@ func (i *initAction) initAppWithAgent(ctx context.Context, azdCtx *azdcontext.Az | |||||
| timeDisplay := agent.FormatSessionTime(session.StartedAt) | ||||||
| defaultYes := true | ||||||
| confirm := uxlib.NewConfirm(&uxlib.ConfirmOptions{ | ||||||
| Message: fmt.Sprintf("Resume previous session from %s?", timeDisplay), | ||||||
| Message: fmt.Sprintf("Resume previous session from %s?", timeDisplay), | ||||||
| HelpMessage: "Resuming continues where you left off. " + | ||||||
| "Choosing no starts a fresh session.", | ||||||
|
Comment on lines
+496
to
+497
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Future idea - Might be worth very briefly summarizing what's in that session? A session from 30 seconds ago is obvious, but if I got interrupted last Friday I might not remember what that includes. |
||||||
| DefaultValue: &defaultYes, | ||||||
| }) | ||||||
| if result, err := confirm.Ask(ctx); err == nil && result != nil && *result { | ||||||
|
|
@@ -561,7 +569,7 @@ func promptInitType( | |||||
| options := []string{ | ||||||
| "Scan current directory", // This now covers minimal project creation too | ||||||
| "Select a template", | ||||||
| fmt.Sprintf("Use agent mode %s", color.YellowString("(Alpha)")), | ||||||
| fmt.Sprintf("Set up with %s %s", agentcopilot.DisplayTitle, color.YellowString("(Preview)")), | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit - Might be worth getting slightly more descriptive than
Suggested change
|
||||||
| } | ||||||
|
|
||||||
| selection, err := console.Select(ctx, input.ConsoleOptions{ | ||||||
|
|
@@ -594,8 +602,8 @@ func promptInitType( | |||||
| return initUnknown, fmt.Errorf("failed to save config: %w", err) | ||||||
| } | ||||||
|
|
||||||
| console.Message(ctx, "\nThe azd agent feature has been enabled to support this new experience."+ | ||||||
| " To turn off in the future run `azd config unset alpha.llm`.") | ||||||
| console.Message(ctx, fmt.Sprintf("\n%s has been enabled to support this new experience."+ | ||||||
| " To turn off in the future run `azd config unset alpha.llm`.", agentcopilot.DisplayTitle)) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit - worth adding something like |
||||||
|
|
||||||
| err = azdConfig.Set(agentcopilot.ConfigKeyModelType, "copilot") | ||||||
| if err != nil { | ||||||
|
|
@@ -607,8 +615,10 @@ func promptInitType( | |||||
| return initUnknown, fmt.Errorf("failed to save config: %w", err) | ||||||
| } | ||||||
|
|
||||||
| console.Message(ctx, fmt.Sprintf("\nGitHub Copilot has been enabled to support this new experience."+ | ||||||
| " To turn off in the future run `azd config unset %s`.", agentcopilot.ConfigKeyModelType)) | ||||||
| console.Message(ctx, fmt.Sprintf( | ||||||
| "\n%s has been enabled to support this new experience."+ | ||||||
| " To turn off in the future run `azd config unset %s`.", | ||||||
| agentcopilot.DisplayTitle, agentcopilot.ConfigKeyModelType)) | ||||||
| } | ||||||
|
|
||||||
| return initWithAgent, nil | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -156,13 +156,13 @@ func (c *CopilotCLI) ensureInstalled(ctx context.Context) error { | |
| return fmt.Errorf("creating copilot CLI directory: %w", err) | ||
| } | ||
|
|
||
| c.console.ShowSpinner(ctx, "Downloading Copilot CLI", input.Step) | ||
| c.console.ShowSpinner(ctx, "Downloading GitHub Copilot CLI", input.Step) | ||
| err := downloadCopilotCLI(ctx, c.transporter, cliVersion, cliPath) | ||
| if err != nil { | ||
| c.console.StopSpinner(ctx, "Downloading Copilot CLI", input.StepFailed) | ||
| c.console.StopSpinner(ctx, "Downloading GitHub Copilot CLI", input.StepFailed) | ||
| return fmt.Errorf("downloading copilot CLI: %w", err) | ||
| } | ||
| c.console.StopSpinner(ctx, "Downloading Copilot CLI", input.StepDone) | ||
| c.console.StopSpinner(ctx, "Downloading GitHub Copilot CLI", input.StepDone) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One minor thing that bugs me is telling people we're downloading this when they already probably have it installed. Feels confusing if you don't know about the layering of the Copilot SDK. Is it worth changing this to something more like |
||
| c.console.Message(ctx, "") | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -70,8 +70,8 @@ func (m *CopilotClientManager) Start(ctx context.Context) error { | |||||
| if err := m.client.Start(ctx); err != nil { | ||||||
| log.Printf("[copilot-client] Start failed: %v", err) | ||||||
| return fmt.Errorf( | ||||||
| "failed to start Copilot agent runtime: %w", | ||||||
| err, | ||||||
| "failed to start %s agent runtime: %w", | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want still want
Suggested change
|
||||||
| DisplayTitle, err, | ||||||
| ) | ||||||
| } | ||||||
| log.Printf("[copilot-client] Started successfully (state=%s)", m.client.State()) | ||||||
|
|
@@ -95,7 +95,7 @@ func (m *CopilotClientManager) Client() *copilot.Client { | |||||
| func (m *CopilotClientManager) GetAuthStatus(ctx context.Context) (*copilot.GetAuthStatusResponse, error) { | ||||||
| status, err := m.client.GetAuthStatus(ctx) | ||||||
| if err != nil { | ||||||
| return nil, fmt.Errorf("failed to check Copilot auth status: %w", err) | ||||||
| return nil, fmt.Errorf("failed to check %s auth status: %w", DisplayTitle, err) | ||||||
| } | ||||||
| return status, nil | ||||||
| } | ||||||
|
|
@@ -104,7 +104,7 @@ func (m *CopilotClientManager) GetAuthStatus(ctx context.Context) (*copilot.GetA | |||||
| func (m *CopilotClientManager) ListModels(ctx context.Context) ([]copilot.ModelInfo, error) { | ||||||
| models, err := m.client.ListModels(ctx) | ||||||
| if err != nil { | ||||||
| return nil, fmt.Errorf("failed to list Copilot models: %w", err) | ||||||
| return nil, fmt.Errorf("failed to list %s models: %w", DisplayTitle, err) | ||||||
| } | ||||||
| return models, nil | ||||||
| } | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -767,7 +767,10 @@ func (a *CopilotAgent) createUserInputHandler(ctx context.Context) copilot.UserI | |||||
|
|
||||||
| selected := choices[*idx].Value | ||||||
| if selected == freeformValue { | ||||||
| prompt := uxlib.NewPrompt(&uxlib.PromptOptions{Message: question}) | ||||||
| prompt := uxlib.NewPrompt(&uxlib.PromptOptions{ | ||||||
| Message: question, | ||||||
| IgnoreHintKeys: true, | ||||||
| }) | ||||||
| answer, err := prompt.Ask(ctx) | ||||||
| fmt.Println() | ||||||
| if err != nil { | ||||||
|
|
@@ -779,7 +782,12 @@ func (a *CopilotAgent) createUserInputHandler(ctx context.Context) copilot.UserI | |||||
| return copilot.UserInputResponse{Answer: selected}, nil | ||||||
| } | ||||||
|
|
||||||
| prompt := uxlib.NewPrompt(&uxlib.PromptOptions{Message: question}) | ||||||
| // TODO: IgnoreHintKeys should not be needed — Prompt should auto-suppress | ||||||
| // hint key handling when no HelpMessage is provided. | ||||||
| prompt := uxlib.NewPrompt(&uxlib.PromptOptions{ | ||||||
| Message: question, | ||||||
| IgnoreHintKeys: true, | ||||||
| }) | ||||||
| answer, err := prompt.Ask(ctx) | ||||||
| fmt.Println() | ||||||
| if err != nil { | ||||||
|
|
@@ -850,11 +858,14 @@ func (a *CopilotAgent) ensureAuthenticated(ctx context.Context) error { | |||||
|
|
||||||
| // Not authenticated — prompt to sign in | ||||||
| a.console.Message(ctx, "") | ||||||
| a.console.Message(ctx, output.WithWarningFormat("Not authenticated with GitHub Copilot")) | ||||||
| a.console.Message(ctx, output.WithWarningFormat("Not authenticated with %s", agentcopilot.DisplayTitle)) | ||||||
| a.console.Message(ctx, "") | ||||||
|
|
||||||
| confirm := uxlib.NewConfirm(&uxlib.ConfirmOptions{ | ||||||
| Message: "Sign in to GitHub Copilot? (opens browser)", | ||||||
| Message: fmt.Sprintf("Sign in to %s? (opens browser)", agentcopilot.DisplayTitle), | ||||||
| HelpMessage: fmt.Sprintf( | ||||||
| "%s requires GitHub authentication to access AI models and agent capabilities.", | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit - maybe drop
Suggested change
|
||||||
| agentcopilot.DisplayTitle), | ||||||
| DefaultValue: uxlib.Ptr(true), | ||||||
| }) | ||||||
|
|
||||||
|
|
@@ -864,18 +875,18 @@ func (a *CopilotAgent) ensureAuthenticated(ctx context.Context) error { | |||||
| } | ||||||
|
|
||||||
| if shouldLogin == nil || !*shouldLogin { | ||||||
| return fmt.Errorf("GitHub Copilot authentication is required to continue") | ||||||
| return fmt.Errorf("%s authentication is required to continue", agentcopilot.DisplayTitle) | ||||||
| } | ||||||
|
|
||||||
| a.console.Message(ctx, "") | ||||||
| if err := a.cli.Login(ctx); err != nil { | ||||||
| return fmt.Errorf("GitHub Copilot sign-in failed: %w", err) | ||||||
| return fmt.Errorf("%s sign-in failed: %w", agentcopilot.DisplayTitle, err) | ||||||
| } | ||||||
|
|
||||||
| // Verify auth succeeded | ||||||
| authStatus, err = a.clientManager.GetAuthStatus(ctx) | ||||||
| if err != nil || !authStatus.IsAuthenticated { | ||||||
| return fmt.Errorf("GitHub Copilot authentication was not completed") | ||||||
| return fmt.Errorf("%s authentication was not completed", agentcopilot.DisplayTitle) | ||||||
| } | ||||||
|
|
||||||
| a.console.Message(ctx, "") | ||||||
|
|
@@ -889,7 +900,7 @@ func (a *CopilotAgent) ensurePlugins(ctx context.Context) { | |||||
| if _, err := exec.LookPath("copilot"); err != nil { | ||||||
| log.Printf("[copilot] 'copilot' CLI not found in PATH — skipping plugin management") | ||||||
| a.console.Message(ctx, output.WithWarningFormat( | ||||||
| "The Copilot CLI is not installed. Some features may be limited.\n"+ | ||||||
| "The GitHub Copilot CLI is not installed. Some features may be limited.\n"+ | ||||||
| "Install it with: npm install -g @github/copilot")) | ||||||
| return | ||||||
| } | ||||||
|
|
@@ -933,12 +944,13 @@ func (a *CopilotAgent) promptPluginInstall(ctx context.Context, plugin pluginSpe | |||||
|
|
||||||
| a.console.Message(ctx, "") | ||||||
| confirm := uxlib.NewConfirm(&uxlib.ConfirmOptions{ | ||||||
| Message: fmt.Sprintf("The %s plugin is not installed. Would you like to install it?", plugin.Name), | ||||||
| HelpMessage: fmt.Sprintf( | ||||||
| "The %s plugin provides Azure-specific skills for infrastructure generation, "+ | ||||||
| "project validation, and deployment guidance. Without it, the agent will have "+ | ||||||
| "limited Azure capabilities. The plugin is installed globally at ~/.copilot/installed-plugins/.", | ||||||
| plugin.Name), | ||||||
| Message: fmt.Sprintf( | ||||||
| "%s works better with the %s plugin. Would you like to install it?", | ||||||
| agentcopilot.DisplayTitle, plugin.Name), | ||||||
| HelpMessage: "The Azure plugin provides:\n" + | ||||||
| "• Azure MCP server that contains additional tools for Azure\n" + | ||||||
| "• Skills that streamline and provide better results for creating, " + | ||||||
| "validating, and deploying applications to Azure", | ||||||
wbreza marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| DefaultValue: &defaultYes, | ||||||
| }) | ||||||
|
|
||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Future nit - think it's worth collecting patterns like
(→)inoutputto help us evolve our whole UX easier as we kick the tires with things like TUIs?