Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 46 additions & 14 deletions cmd/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,38 @@ var agentDeleteCmd = &cobra.Command{
},
}

func getAgentInfoFlow(logger logger.Logger, remoteAgents []agent.Agent, name string, description string) (string, string) {
if name == "" {
var prompt, help string
if len(remoteAgents) > 0 {
prompt = "What should we name the agent?"
help = "The name of the agent must be unique within the project"
} else {
prompt = "What should we name the initial agent?"
help = "The name can be changed at any time and helps identify the agent"
}
name = tui.InputWithValidation(logger, prompt, help, 255, func(name string) error {
for _, agent := range remoteAgents {
if strings.EqualFold(agent.Name, name) {
return fmt.Errorf("agent %s already exists with this name", name)
}
}
return nil
})
}

if description == "" {
description = tui.Input(logger, "How should we describe what the "+name+" agent does?", "The description of the agent is optional but helpful for understanding the role of the agent")
}

return name, description
}

var agentCreateCmd = &cobra.Command{
Use: "create",
Use: "create [name] [description]",
Short: "Create a new agent",
Aliases: []string{"new"},
Args: cobra.MaximumNArgs(2),
Run: func(cmd *cobra.Command, args []string) {
logger := env.NewLogger(cmd)
theproject := ensureProject(cmd)
Expand All @@ -101,16 +129,18 @@ var agentCreateCmd = &cobra.Command{

initScreenWithLogo()

name := tui.InputWithValidation(logger, "What should we name the agent?", "The name of the agent must be unique within the project", 255, func(name string) error {
for _, agent := range remoteAgents {
if strings.EqualFold(agent.Name, name) {
return fmt.Errorf("agent %s already exists with this name", name)
}
}
return nil
})
var name string
var description string

if len(args) > 0 {
name = args[0]
}

description := tui.Input(logger, "How should we describe what the "+name+" agent does?", "The description of the agent is optional but helpful for understanding the role of the agent")
if len(args) > 1 {
description = args[1]
}

name, description = getAgentInfoFlow(logger, remoteAgents, name, description)

action := func() {
agentID, err := agent.CreateAgent(logger, apiUrl, apikey, theproject.Project.ProjectId, name, description)
Expand All @@ -124,10 +154,12 @@ var agentCreateCmd = &cobra.Command{
}

if err := rules.NewAgent(templates.TemplateContext{
Logger: logger,
Name: name,
Description: description,
ProjectDir: theproject.Dir,
Logger: logger,
AgentName: name,
Name: name,
Description: description,
AgentDescription: description,
ProjectDir: theproject.Dir,
}); err != nil {
errsystem.New(errsystem.ErrApiRequest, err, errsystem.WithAttributes(map[string]any{"name": name})).ShowErrorAndExit()
}
Expand Down
16 changes: 9 additions & 7 deletions cmd/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,12 @@ type projectContext struct {
Token string
}

func ensureProject(cmd *cobra.Command) projectContext {
logger := env.NewLogger(cmd)
dir := resolveProjectDir(cmd)
apiUrl, appUrl := getURLs(logger)
token, _ := ensureLoggedIn()

func loadProject(logger logger.Logger, dir string, apiUrl string, appUrl string, token string) projectContext {
theproject := project.NewProject()
if err := theproject.Load(dir); err != nil {
errsystem.New(errsystem.ErrInvalidConfiguration, err,
errsystem.WithContextMessage("Error loading project from disk")).ShowErrorAndExit()
}

return projectContext{
Logger: logger,
Project: theproject,
Expand All @@ -93,6 +87,14 @@ func ensureProject(cmd *cobra.Command) projectContext {
}
}

func ensureProject(cmd *cobra.Command) projectContext {
logger := env.NewLogger(cmd)
dir := resolveProjectDir(cmd)
apiUrl, appUrl := getURLs(logger)
token, _ := ensureLoggedIn()
return loadProject(logger, dir, apiUrl, appUrl, token)
}

var cloudDeployCmd = &cobra.Command{
Use: "deploy",
Short: "Deploy project to the cloud",
Expand Down
44 changes: 22 additions & 22 deletions cmd/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var projectCmd = &cobra.Command{
Expand Down Expand Up @@ -231,17 +230,13 @@ func showProjectSelector(items []list.Item) *templates.Template {
}

var projectNewCmd = &cobra.Command{
Use: "create [name]",
Use: "create [name] [description] [agent-name] [agent-description]",
Short: "Create a new project",
Aliases: []string{"new"},
Args: cobra.MaximumNArgs(1),
Args: cobra.MaximumNArgs(4),
Run: func(cmd *cobra.Command, args []string) {
logger := env.NewLogger(cmd)
apikey := viper.GetString("auth.api_key")
if apikey == "" {
logger.Fatal("You are not logged in. Please run `agentuity login` to login.")
}

apikey, _ := ensureLoggedIn()
apiUrl, appUrl := getURLs(logger)
initScreenWithLogo()

Expand All @@ -252,7 +247,7 @@ var projectNewCmd = &cobra.Command{

orgId := promptForOrganization(logger, apiUrl, apikey)

var name string
var name, description, agentName, agentDescription string

if len(args) > 0 {
name = args[0]
Expand All @@ -279,7 +274,9 @@ var projectNewCmd = &cobra.Command{
})
}

description := tui.Input(logger, "How should we describe what the "+name+" project does?", "The description of the project is optional but helpful")
if description == "" {
description = tui.Input(logger, "How should we describe what the "+name+" project does?", "The description of the project is optional but helpful")
}

projectDir := filepath.Join(cwd, util.SafeFilename(name))
dir, _ := cmd.Flags().GetString("dir")
Expand Down Expand Up @@ -358,15 +355,21 @@ var projectNewCmd = &cobra.Command{
}
}

if agentName == "" {
agentName, agentDescription = getAgentInfoFlow(logger, nil, agentName, agentDescription)
}

var projectData *project.ProjectData

tui.ShowSpinner("creating project ...", func() {
rules, err := provider.NewProject(templates.TemplateContext{
Context: context.Background(),
Logger: logger,
Name: name,
Description: description,
ProjectDir: projectDir,
Context: context.Background(),
Logger: logger,
Name: name,
Description: description,
ProjectDir: projectDir,
AgentName: agentName,
AgentDescription: agentDescription,
})
if err != nil {
errsystem.New(errsystem.ErrCreateProject, err, errsystem.WithContextMessage("Failed to create project")).ShowErrorAndExit()
Expand All @@ -380,8 +383,8 @@ var projectNewCmd = &cobra.Command{
Name: name,
Description: description,
Provider: rules,
AgentName: rules.NewProjectSteps.InitialAgent.Name,
AgentDescription: rules.NewProjectSteps.InitialAgent.Description,
AgentName: agentName,
AgentDescription: agentDescription,
})
})

Expand Down Expand Up @@ -450,10 +453,7 @@ var projectDeleteCmd = &cobra.Command{
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
logger := env.NewLogger(cmd)
apikey := viper.GetString("auth.api_key")
if apikey == "" {
logger.Fatal("You are not logged in. Please run `agentuity login` to login.")
}
apikey, _ := ensureLoggedIn()
apiUrl, _ := getURLs(logger)
var projects []project.ProjectListData
action := func() {
Expand Down Expand Up @@ -516,5 +516,5 @@ func init() {
projectCmd.AddCommand(projectDeleteCmd)

projectNewCmd.Flags().StringP("dir", "d", "", "The directory to create the project in")
projectNewCmd.Flags().StringP("provider", "p", "", "The provider to use for the project")
projectNewCmd.Flags().StringP("provider", "p", "", "The provider template to use for the project")
}
4 changes: 3 additions & 1 deletion internal/errsystem/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ func (e *errSystem) writeCrashReportFile(stackTrace string) string {
report.Attributes = e.attributes
report.CLIVersion = Version
report.StackTrace = stackTrace
json.NewEncoder(tmp).Encode(report)
enc := json.NewEncoder(tmp)
enc.SetIndent(" ", " ")
enc.Encode(report)
return tmp.Name()
}

Expand Down
5 changes: 1 addition & 4 deletions internal/templates/data/bunjs/rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ new_agent:
filename: "src/agents/{{ .Name | safe_filename }}/index.ts"
from: "common/js/agent.ts"
new_project:
initial:
name: "MyFirstAgent"
description: "This is my first agent which uses the Vercel AI SDK to generate a text response"
steps:
- command: bun
args:
Expand Down Expand Up @@ -92,7 +89,7 @@ new_project:
filename: "index.ts"
from: "common/js/boot.ts"
- action: create_file
filename: "src/agents/MyFirstAgent/index.ts"
filename: "src/agents/{{ .AgentName | safe_filename }}/index.ts"
from: "common/js/agent.ts"
- action: copy_dir
from: "common/js/cursor"
Expand Down
5 changes: 1 addition & 4 deletions internal/templates/data/nodejs/rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ new_agent:
filename: "src/agents/{{ .Name | safe_filename }}/index.ts"
from: "common/js/agent.ts"
new_project:
initial:
name: "MyFirstAgent"
description: "This is my first agent which uses the Vercel AI SDK to generate a text response"
steps:
- command: npm
args:
Expand Down Expand Up @@ -84,7 +81,7 @@ new_project:
filename: ".gitignore"
from: "data/nodejs/gitignore"
- action: create_file
filename: "src/agents/MyFirstAgent/index.ts"
filename: "src/agents/{{ .AgentName | safe_filename }}/index.ts"
from: "common/js/agent.ts"
- action: copy_dir
from: "common/js/cursor"
Expand Down
7 changes: 2 additions & 5 deletions internal/templates/data/python-uv/rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ new_agent:
filename: "agents/{{ .Name | safe_filename }}/agent.py"
from: "common/py/agent.py"
new_project:
initial:
name: "myfirstagent"
description: "This is my first agent which uses the LiteLLM to generate a text response"
steps:
- command: uv
args:
Expand All @@ -44,7 +41,7 @@ new_project:
args:
- init
- --name
- "{{ .Name }}"
- "{{ .Name | safe_filename }}"
- --no-package
- --python
- ">=3.10"
Expand Down Expand Up @@ -72,5 +69,5 @@ new_project:
filename: ".gitignore"
from: "data/common/py/gitignore"
- action: create_file
filename: "agents/myfirstagent/agent.py"
filename: "agents/{{ .AgentName | safe_filename }}/agent.py"
from: "common/py/agent.py"
2 changes: 1 addition & 1 deletion internal/templates/steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ func resolveStep(ctx TemplateContext, step any) (Step, bool) {
}
var name string
if val, ok := kv["name"].(string); ok {
name = ctx.Interpolate(val).(string)
name = util.SafeFilename(ctx.Interpolate(val).(string))
}
var version string
if val, ok := kv["version"].(string); ok {
Expand Down
22 changes: 9 additions & 13 deletions internal/templates/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import (
)

type TemplateContext struct {
Context context.Context
Logger logger.Logger
Name string
Description string
ProjectDir string
Template *Template
Context context.Context
Logger logger.Logger
Name string
Description string
AgentName string
AgentDescription string
ProjectDir string
Template *Template
}

func funcTemplates(t *template.Template) *template.Template {
Expand Down Expand Up @@ -50,8 +52,7 @@ func (t *TemplateContext) Interpolate(val any) any {
}

type NewProjectSteps struct {
InitialAgent InitialAgent `yaml:"initial"`
Steps []any `yaml:"steps"`
Steps []any `yaml:"steps"`
}

type NewAgentSteps struct {
Expand Down Expand Up @@ -86,11 +87,6 @@ type Deployment struct {
Args []string `yaml:"args"`
}

type InitialAgent struct {
Name string `yaml:"name"`
Description string `yaml:"description"`
}

type TemplateRules struct {
Identifier string `yaml:"identifier"`
Runtime string `yaml:"runtime"`
Expand Down