@agentspan/agentspan 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cmd/init.go ADDED
@@ -0,0 +1,83 @@
1
+ // Copyright (c) 2025 AgentSpan
2
+ // Licensed under the MIT License. See LICENSE file in the project root for details.
3
+
4
+ package cmd
5
+
6
+ import (
7
+ "encoding/json"
8
+ "fmt"
9
+ "os"
10
+
11
+ "github.com/fatih/color"
12
+ "github.com/spf13/cobra"
13
+ "gopkg.in/yaml.v3"
14
+ )
15
+
16
+ var (
17
+ initModel string
18
+ initStrategy string
19
+ initFormat string
20
+ )
21
+
22
+ var initCmd = &cobra.Command{
23
+ Use: "init <agent-name>",
24
+ Short: "Create a new agent config file",
25
+ Long: "Generate a starter agent config YAML/JSON file with sensible defaults.",
26
+ Args: cobra.ExactArgs(1),
27
+ RunE: func(cmd *cobra.Command, args []string) error {
28
+ name := args[0]
29
+ model := initModel
30
+ if model == "" {
31
+ model = "openai/gpt-4o"
32
+ }
33
+
34
+ agentConfig := map[string]interface{}{
35
+ "name": name,
36
+ "description": fmt.Sprintf("%s agent", name),
37
+ "model": model,
38
+ "instructions": fmt.Sprintf("You are %s, a helpful AI assistant.", name),
39
+ "maxTurns": 25,
40
+ "tools": []interface{}{},
41
+ }
42
+
43
+ if initStrategy != "" {
44
+ agentConfig["strategy"] = initStrategy
45
+ }
46
+
47
+ var data []byte
48
+ var ext string
49
+ var err error
50
+
51
+ if initFormat == "json" {
52
+ ext = "json"
53
+ data, err = marshalJSON(agentConfig)
54
+ } else {
55
+ ext = "yaml"
56
+ data, err = yaml.Marshal(agentConfig)
57
+ }
58
+ if err != nil {
59
+ return err
60
+ }
61
+
62
+ filename := fmt.Sprintf("%s.%s", name, ext)
63
+ if err := os.WriteFile(filename, data, 0o644); err != nil {
64
+ return fmt.Errorf("write file: %w", err)
65
+ }
66
+
67
+ color.Green("Created %s", filename)
68
+ fmt.Println("\nEdit the file to add tools, instructions, and other settings.")
69
+ fmt.Printf("Run with: agentspan agent run --name %s \"your prompt here\"\n", name)
70
+ return nil
71
+ },
72
+ }
73
+
74
+ func marshalJSON(v interface{}) ([]byte, error) {
75
+ return json.MarshalIndent(v, "", " ")
76
+ }
77
+
78
+ func init() {
79
+ initCmd.Flags().StringVarP(&initModel, "model", "m", "", "LLM model (default: openai/gpt-4o)")
80
+ initCmd.Flags().StringVarP(&initStrategy, "strategy", "s", "", "Multi-agent strategy (handoff, sequential, parallel, etc.)")
81
+ initCmd.Flags().StringVarP(&initFormat, "format", "f", "yaml", "Output format: yaml or json")
82
+ agentCmd.AddCommand(initCmd)
83
+ }
package/cmd/list.go ADDED
@@ -0,0 +1,55 @@
1
+ // Copyright (c) 2025 AgentSpan
2
+ // Licensed under the MIT License. See LICENSE file in the project root for details.
3
+
4
+ package cmd
5
+
6
+ import (
7
+ "fmt"
8
+ "os"
9
+ "text/tabwriter"
10
+ "time"
11
+
12
+ "github.com/fatih/color"
13
+ "github.com/spf13/cobra"
14
+ )
15
+
16
+ var listCmd = &cobra.Command{
17
+ Use: "list",
18
+ Short: "List all registered agents",
19
+ RunE: func(cmd *cobra.Command, args []string) error {
20
+ cfg := getConfig()
21
+ c := newClient(cfg)
22
+
23
+ agents, err := c.ListAgents()
24
+ if err != nil {
25
+ return fmt.Errorf("failed to list agents: %w", err)
26
+ }
27
+
28
+ if len(agents) == 0 {
29
+ color.Yellow("No agents registered.")
30
+ return nil
31
+ }
32
+
33
+ w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
34
+ fmt.Fprintln(w, "NAME\tVERSION\tTYPE\tDESCRIPTION\tUPDATED")
35
+ fmt.Fprintln(w, "----\t-------\t----\t-----------\t-------")
36
+
37
+ for _, a := range agents {
38
+ updated := ""
39
+ if a.UpdateTime != nil {
40
+ t := time.UnixMilli(*a.UpdateTime)
41
+ updated = t.Format("2006-01-02 15:04")
42
+ }
43
+ desc := truncate(a.Description, 40)
44
+ fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\n", a.Name, a.Version, a.Type, desc, updated)
45
+ }
46
+ w.Flush()
47
+
48
+ fmt.Printf("\n%d agent(s) found.\n", len(agents))
49
+ return nil
50
+ },
51
+ }
52
+
53
+ func init() {
54
+ agentCmd.AddCommand(listCmd)
55
+ }
package/cmd/respond.go ADDED
@@ -0,0 +1,56 @@
1
+ // Copyright (c) 2025 AgentSpan
2
+ // Licensed under the MIT License. See LICENSE file in the project root for details.
3
+
4
+ package cmd
5
+
6
+ import (
7
+ "fmt"
8
+
9
+ "github.com/fatih/color"
10
+ "github.com/spf13/cobra"
11
+ )
12
+
13
+ var (
14
+ respondApprove bool
15
+ respondDeny bool
16
+ respondReason string
17
+ respondMessage string
18
+ )
19
+
20
+ var respondCmd = &cobra.Command{
21
+ Use: "respond <workflow-id>",
22
+ Short: "Respond to a human-in-the-loop task",
23
+ Args: cobra.ExactArgs(1),
24
+ RunE: func(cmd *cobra.Command, args []string) error {
25
+ cfg := getConfig()
26
+ c := newClient(cfg)
27
+
28
+ approved := true
29
+ if respondDeny {
30
+ approved = false
31
+ }
32
+
33
+ if err := c.Respond(args[0], approved, respondReason, respondMessage); err != nil {
34
+ return fmt.Errorf("failed to respond: %w", err)
35
+ }
36
+
37
+ if approved {
38
+ color.Green("Response sent: approved")
39
+ } else {
40
+ color.Yellow("Response sent: denied")
41
+ }
42
+ if respondReason != "" {
43
+ fmt.Printf(" Reason: %s\n", respondReason)
44
+ }
45
+
46
+ return nil
47
+ },
48
+ }
49
+
50
+ func init() {
51
+ respondCmd.Flags().BoolVar(&respondApprove, "approve", false, "Approve the pending action")
52
+ respondCmd.Flags().BoolVar(&respondDeny, "deny", false, "Deny the pending action")
53
+ respondCmd.Flags().StringVar(&respondReason, "reason", "", "Reason for the response")
54
+ respondCmd.Flags().StringVarP(&respondMessage, "message", "m", "", "Message to send back")
55
+ agentCmd.AddCommand(respondCmd)
56
+ }
package/cmd/root.go ADDED
@@ -0,0 +1,44 @@
1
+ // Copyright (c) 2025 AgentSpan
2
+ // Licensed under the MIT License. See LICENSE file in the project root for details.
3
+
4
+ package cmd
5
+
6
+ import (
7
+ "fmt"
8
+ "os"
9
+
10
+ "github.com/spf13/cobra"
11
+ )
12
+
13
+ var (
14
+ serverURL string
15
+ Version = "dev"
16
+ Commit = "none"
17
+ Date = "unknown"
18
+ )
19
+
20
+ var rootCmd = &cobra.Command{
21
+ Use: "agentspan",
22
+ Short: "CLI for the AgentSpan runtime",
23
+ Long: "Create, run, and manage AI agents powered by the AgentSpan runtime.",
24
+ }
25
+
26
+ var versionCmd = &cobra.Command{
27
+ Use: "version",
28
+ Short: "Print the CLI version",
29
+ Run: func(cmd *cobra.Command, args []string) {
30
+ fmt.Printf("agentspan %s (commit: %s, built: %s)\n", Version, Commit, Date)
31
+ },
32
+ }
33
+
34
+ func Execute() {
35
+ if err := rootCmd.Execute(); err != nil {
36
+ fmt.Fprintln(os.Stderr, err)
37
+ os.Exit(1)
38
+ }
39
+ }
40
+
41
+ func init() {
42
+ rootCmd.PersistentFlags().StringVar(&serverURL, "server", "", "Runtime server URL (default: http://localhost:8080)")
43
+ rootCmd.AddCommand(versionCmd)
44
+ }
package/cmd/run.go ADDED
@@ -0,0 +1,116 @@
1
+ // Copyright (c) 2025 AgentSpan
2
+ // Licensed under the MIT License. See LICENSE file in the project root for details.
3
+
4
+ package cmd
5
+
6
+ import (
7
+ "fmt"
8
+ "strings"
9
+
10
+ "github.com/agentspan/agentspan/cli/client"
11
+ "github.com/fatih/color"
12
+ "github.com/spf13/cobra"
13
+ )
14
+
15
+ var (
16
+ runAgentName string
17
+ runSessionID string
18
+ runNoStream bool
19
+ )
20
+
21
+ var runCmd = &cobra.Command{
22
+ Use: "run [prompt]",
23
+ Short: "Start an agent and stream its output",
24
+ Long: `Start a registered agent by name with a prompt,
25
+ and stream the execution events in real-time.
26
+
27
+ The agent must have been previously registered via the /api/agent/start endpoint.
28
+ Alternatively, provide a config file with --config.`,
29
+ Args: cobra.MinimumNArgs(1),
30
+ RunE: runAgent,
31
+ }
32
+
33
+ var runConfigFile string
34
+
35
+ func init() {
36
+ runCmd.Flags().StringVar(&runAgentName, "name", "", "Name of a registered agent to run")
37
+ runCmd.Flags().StringVar(&runConfigFile, "config", "", "Path to agent config file (YAML/JSON)")
38
+ runCmd.Flags().StringVar(&runSessionID, "session", "", "Session ID for conversation continuity")
39
+ runCmd.Flags().BoolVar(&runNoStream, "no-stream", false, "Don't stream events, just return the workflow ID")
40
+ agentCmd.AddCommand(runCmd)
41
+ }
42
+
43
+ func runAgent(cmd *cobra.Command, args []string) error {
44
+ prompt := strings.Join(args, " ")
45
+
46
+ cfg := getConfig()
47
+ c := newClient(cfg)
48
+
49
+ var startReq *client.StartRequest
50
+
51
+ if runConfigFile != "" {
52
+ // Config file mode (existing behavior)
53
+ agentConfig, err := loadAgentConfig(runConfigFile)
54
+ if err != nil {
55
+ return err
56
+ }
57
+ bold := color.New(color.Bold)
58
+ bold.Printf("Starting agent: %s\n", agentConfig["name"])
59
+ startReq = &client.StartRequest{
60
+ AgentConfig: agentConfig,
61
+ Prompt: prompt,
62
+ }
63
+ } else if runAgentName != "" {
64
+ // Name mode: fetch agent def, then start with it
65
+ bold := color.New(color.Bold)
66
+ bold.Printf("Starting agent: %s\n", runAgentName)
67
+
68
+ agentDef, err := c.GetAgent(runAgentName, nil)
69
+ if err != nil {
70
+ return fmt.Errorf("failed to get agent '%s': %w", runAgentName, err)
71
+ }
72
+ startReq = &client.StartRequest{
73
+ AgentConfig: agentDef,
74
+ Prompt: prompt,
75
+ }
76
+ } else {
77
+ return fmt.Errorf("specify either --name or --config")
78
+ }
79
+
80
+ if runSessionID != "" {
81
+ startReq.SessionID = runSessionID
82
+ }
83
+
84
+ resp, err := c.Start(startReq)
85
+ if err != nil {
86
+ return fmt.Errorf("failed to start agent: %w", err)
87
+ }
88
+
89
+ fmt.Printf("Workflow: %s (ID: %s)\n", resp.WorkflowName, resp.WorkflowID)
90
+
91
+ if runNoStream {
92
+ return nil
93
+ }
94
+
95
+ fmt.Println()
96
+ return streamWorkflow(c, resp.WorkflowID)
97
+ }
98
+
99
+ func streamWorkflow(c *client.Client, workflowID string) error {
100
+ events := make(chan client.SSEEvent, 100)
101
+ done := make(chan error, 1)
102
+
103
+ c.Stream(workflowID, "", events, done)
104
+
105
+ for {
106
+ select {
107
+ case evt, ok := <-events:
108
+ if !ok {
109
+ return nil
110
+ }
111
+ printSSEEvent(evt)
112
+ case err := <-done:
113
+ return err
114
+ }
115
+ }
116
+ }