Skip to content

Commit 3ecb295

Browse files
zimegsrtaalej
andauthored
fix: 'create agent' command to show template, bolt framework, and agent framework options (#479)
* fix: separate inputs for framework and adapter options * fix: order starter agent before example agents * fix: select an agent framework no adapter * feat: select a bolt framwork for agent apps * feat: secondary descriptions of agentic templates * feat: breadcrumbs for the agent selection --------- Co-authored-by: Ale Mercado <104795114+srtaalej@users.noreply.github.com>
1 parent 8d047bb commit 3ecb295

File tree

2 files changed

+198
-50
lines changed

2 files changed

+198
-50
lines changed

cmd/project/create_template.go

Lines changed: 127 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ func getSelectionOptions(categoryID string) []promptObject {
4444
},
4545
},
4646
"slack-cli#ai-apps": {
47-
{
48-
Title: fmt.Sprintf("Support Agent %s", style.Secondary("Resolve IT support cases")),
49-
Repository: "slack-cli#ai-apps/support-agent",
50-
},
5147
{
5248
Title: fmt.Sprintf("Starter Agent %s", style.Secondary("Start from scratch")),
5349
Repository: "slack-cli#ai-apps/starter-agent",
5450
},
51+
{
52+
Title: fmt.Sprintf("Support Agent %s", style.Secondary("Resolve IT support cases")),
53+
Repository: "slack-cli#ai-apps/support-agent",
54+
},
5555
},
5656
"slack-cli#automation-apps": {
5757
{
@@ -71,38 +71,96 @@ func getSelectionOptions(categoryID string) []promptObject {
7171
return templatePromptObjects[categoryID]
7272
}
7373

74-
// getFrameworkOptions returns the framework choices for a given template.
74+
// getFrameworkOptions returns the framework choices for a given AI app template.
7575
func getFrameworkOptions(template string) []promptObject {
7676
frameworkPromptObjects := map[string][]promptObject{
7777
"slack-cli#ai-apps/support-agent": {
7878
{
79-
Title: fmt.Sprintf("Claude Agent SDK %s", style.Secondary("Bolt for Python")),
79+
Title: fmt.Sprintf("Bolt for JavaScript %s", style.Secondary("Support Agent")),
80+
Repository: "slack-cli#ai-apps/support-agent/bolt-js",
81+
},
82+
{
83+
Title: fmt.Sprintf("Bolt for Python %s", style.Secondary("Support Agent")),
84+
Repository: "slack-cli#ai-apps/support-agent/bolt-python",
85+
},
86+
},
87+
"slack-cli#ai-apps/starter-agent": {
88+
{
89+
Title: fmt.Sprintf("Bolt for JavaScript %s", style.Secondary("Starter Agent")),
90+
Repository: "slack-cli#ai-apps/starter-agent/bolt-js",
91+
},
92+
{
93+
Title: fmt.Sprintf("Bolt for Python %s", style.Secondary("Starter Agent")),
94+
Repository: "slack-cli#ai-apps/starter-agent/bolt-python",
95+
},
96+
},
97+
}
98+
return frameworkPromptObjects[template]
99+
}
100+
101+
// getAdapterOptions returns the AI agent framework choices for a given template and framework.
102+
func getAdapterOptions(framework string) []promptObject {
103+
adapterPromptObjects := map[string][]promptObject{
104+
"slack-cli#ai-apps/support-agent/bolt-js": {
105+
{
106+
Title: fmt.Sprintf("Claude Agent SDK %s", style.Secondary("Bolt for JavaScript - Support Agent")),
107+
Repository: "slack-samples/bolt-js-support-agent",
108+
Subdir: "claude-agent-sdk",
109+
},
110+
{
111+
Title: fmt.Sprintf("OpenAI Agents SDK %s", style.Secondary("Bolt for JavaScript - Support Agent")),
112+
Repository: "slack-samples/bolt-js-support-agent",
113+
Subdir: "openai-agents-sdk",
114+
},
115+
},
116+
"slack-cli#ai-apps/support-agent/bolt-python": {
117+
{
118+
Title: fmt.Sprintf("Claude Agent SDK %s", style.Secondary("Bolt for Python - Support Agent")),
80119
Repository: "slack-samples/bolt-python-support-agent",
81120
Subdir: "claude-agent-sdk",
82121
},
83122
{
84-
Title: fmt.Sprintf("OpenAI Agents SDK %s", style.Secondary("Bolt for Python")),
123+
Title: fmt.Sprintf("OpenAI Agents SDK %s", style.Secondary("Bolt for Python - Support Agent")),
85124
Repository: "slack-samples/bolt-python-support-agent",
86125
Subdir: "openai-agents-sdk",
87126
},
88127
{
89-
Title: fmt.Sprintf("Pydantic AI %s", style.Secondary("Bolt for Python")),
128+
Title: fmt.Sprintf("Pydantic AI %s", style.Secondary("Bolt for Python - Support Agent")),
90129
Repository: "slack-samples/bolt-python-support-agent",
91130
Subdir: "pydantic-ai",
92131
},
93132
},
94-
"slack-cli#ai-apps/starter-agent": {
133+
"slack-cli#ai-apps/starter-agent/bolt-js": {
95134
{
96-
Title: fmt.Sprintf("Bolt for JavaScript %s", style.Secondary("Node.js")),
135+
Title: fmt.Sprintf("Claude Agent SDK %s", style.Secondary("Bolt for JavaScript - Starter Agent")),
97136
Repository: "slack-samples/bolt-js-starter-agent",
137+
Subdir: "claude-agent-sdk",
98138
},
99139
{
100-
Title: fmt.Sprintf("Bolt for Python %s", style.Secondary("Python")),
140+
Title: fmt.Sprintf("OpenAI Agents SDK %s", style.Secondary("Bolt for JavaScript - Starter Agent")),
141+
Repository: "slack-samples/bolt-js-starter-agent",
142+
Subdir: "openai-agents-sdk",
143+
},
144+
},
145+
"slack-cli#ai-apps/starter-agent/bolt-python": {
146+
{
147+
Title: fmt.Sprintf("Claude Agent SDK %s", style.Secondary("Bolt for Python - Starter Agent")),
148+
Repository: "slack-samples/bolt-python-starter-agent",
149+
Subdir: "claude-agent-sdk",
150+
},
151+
{
152+
Title: fmt.Sprintf("OpenAI Agents SDK %s", style.Secondary("Bolt for Python - Starter Agent")),
153+
Repository: "slack-samples/bolt-python-starter-agent",
154+
Subdir: "openai-agents-sdk",
155+
},
156+
{
157+
Title: fmt.Sprintf("Pydantic AI %s", style.Secondary("Bolt for Python - Starter Agent")),
101158
Repository: "slack-samples/bolt-python-starter-agent",
159+
Subdir: "pydantic-ai",
102160
},
103161
},
104162
}
105-
return frameworkPromptObjects[template]
163+
return adapterPromptObjects[framework]
106164
}
107165

108166
// getSelectionOptionsForCategory returns the top-level category options for
@@ -223,31 +281,63 @@ func promptTemplateSelection(cmd *cobra.Command, clients *shared.ClientFactory,
223281
}
224282
template := options[selection.Index].Repository
225283

226-
// Prompt for the example framework
227-
examples := getFrameworkOptions(template)
228-
choices := make([]string, len(examples))
229-
for i, opt := range examples {
230-
choices[i] = opt.Title
284+
// Prompt for the framework
285+
frameworks := getFrameworkOptions(template)
286+
frameworkChoices := make([]string, len(frameworks))
287+
for i, opt := range frameworks {
288+
frameworkChoices[i] = opt.Title
231289
}
232-
choice, err := clients.IO.SelectPrompt(ctx, "Select a framework:", choices, iostreams.SelectPromptConfig{
290+
frameworkSelection, err := clients.IO.SelectPrompt(ctx, "Select a Bolt framework:", frameworkChoices, iostreams.SelectPromptConfig{
233291
Description: func(value string, index int) string {
234-
return examples[index].Description
292+
return frameworks[index].Description
235293
},
236294
Required: true,
237295
Template: getSelectionTemplate(clients),
238296
})
239297
if err != nil {
240298
return create.Template{}, err
241-
} else if choice.Flag {
299+
} else if frameworkSelection.Flag {
242300
return create.Template{}, slackerror.New(slackerror.ErrPrompt)
243301
}
244-
example := examples[choice.Index]
245-
resolved, err := create.ResolveTemplateURL(example.Repository)
302+
framework := frameworks[frameworkSelection.Index]
303+
304+
// Check if there are adapter options for this framework
305+
adapters := getAdapterOptions(framework.Repository)
306+
if len(adapters) > 0 {
307+
adapterChoices := make([]string, len(adapters))
308+
for i, opt := range adapters {
309+
adapterChoices[i] = opt.Title
310+
}
311+
adapterSelection, err := clients.IO.SelectPrompt(ctx, "Select an agent framework:", adapterChoices, iostreams.SelectPromptConfig{
312+
Description: func(value string, index int) string {
313+
return adapters[index].Description
314+
},
315+
Required: true,
316+
Template: getSelectionTemplate(clients),
317+
})
318+
if err != nil {
319+
return create.Template{}, err
320+
} else if adapterSelection.Flag {
321+
return create.Template{}, slackerror.New(slackerror.ErrPrompt)
322+
}
323+
adapter := adapters[adapterSelection.Index]
324+
resolved, err := create.ResolveTemplateURL(adapter.Repository)
325+
if err != nil {
326+
return create.Template{}, err
327+
}
328+
if adapter.Subdir != "" {
329+
resolved.SetSubdir(adapter.Subdir)
330+
}
331+
return resolved, nil
332+
}
333+
334+
// No adapter options - resolve the framework directly
335+
resolved, err := create.ResolveTemplateURL(framework.Repository)
246336
if err != nil {
247337
return create.Template{}, err
248338
}
249-
if example.Subdir != "" {
250-
resolved.SetSubdir(example.Subdir)
339+
if framework.Subdir != "" {
340+
resolved.SetSubdir(framework.Subdir)
251341
}
252342
return resolved, nil
253343
}
@@ -300,27 +390,33 @@ func listTemplates(ctx context.Context, clients *shared.ClientFactory, categoryS
300390
var categories []categoryInfo
301391
if categoryShortcut == "agent" {
302392
categories = []categoryInfo{
303-
{id: "slack-cli#ai-apps/support-agent", name: "Support agent"},
304393
{id: "slack-cli#ai-apps/starter-agent", name: "Starter agent"},
394+
{id: "slack-cli#ai-apps/support-agent", name: "Support agent"},
305395
}
306396
} else {
307397
categories = []categoryInfo{
308398
{id: "slack-cli#getting-started", name: "Getting started"},
309-
{id: "slack-cli#ai-apps/support-agent", name: "Support agent"},
310399
{id: "slack-cli#ai-apps/starter-agent", name: "Starter agent"},
400+
{id: "slack-cli#ai-apps/support-agent", name: "Support agent"},
311401
{id: "slack-cli#automation-apps", name: "Automation apps"},
312402
}
313403
}
314404

315405
for _, category := range categories {
316406
var secondary []string
317407
if frameworks := getFrameworkOptions(category.id); len(frameworks) > 0 {
318-
for _, tmpl := range frameworks {
319-
repo := tmpl.Repository
320-
if tmpl.Subdir != "" {
321-
repo = fmt.Sprintf("%s --subdir %s", repo, tmpl.Subdir)
408+
for _, fw := range frameworks {
409+
if adapters := getAdapterOptions(fw.Repository); len(adapters) > 0 {
410+
for _, adapter := range adapters {
411+
repo := adapter.Repository
412+
if adapter.Subdir != "" {
413+
repo = fmt.Sprintf("%s --subdir %s", repo, adapter.Subdir)
414+
}
415+
secondary = append(secondary, repo)
416+
}
417+
} else {
418+
secondary = append(secondary, fw.Repository)
322419
}
323-
secondary = append(secondary, repo)
324420
}
325421
} else {
326422
for _, tmpl := range getSelectionOptions(category.id) {

0 commit comments

Comments
 (0)