@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/README.md +227 -0
- package/build.sh +35 -0
- package/cli.js +28 -0
- package/client/client.go +365 -0
- package/cmd/agent.go +120 -0
- package/cmd/compile.go +37 -0
- package/cmd/configure.go +48 -0
- package/cmd/delete.go +44 -0
- package/cmd/doctor.go +486 -0
- package/cmd/execution.go +155 -0
- package/cmd/get.go +40 -0
- package/cmd/helpers.go +21 -0
- package/cmd/init.go +83 -0
- package/cmd/list.go +55 -0
- package/cmd/respond.go +56 -0
- package/cmd/root.go +44 -0
- package/cmd/run.go +116 -0
- package/cmd/server.go +446 -0
- package/cmd/server_unix.go +36 -0
- package/cmd/server_windows.go +37 -0
- package/cmd/status.go +72 -0
- package/cmd/stream.go +32 -0
- package/cmd/update.go +91 -0
- package/config/config.go +78 -0
- package/dist/agentspan_darwin_amd64 +0 -0
- package/dist/agentspan_darwin_arm64 +0 -0
- package/dist/agentspan_linux_amd64 +0 -0
- package/dist/agentspan_linux_arm64 +0 -0
- package/dist/agentspan_windows_amd64.exe +0 -0
- package/dist/agentspan_windows_arm64.exe +0 -0
- package/examples/multi-agent.yaml +22 -0
- package/examples/simple-agent.yaml +7 -0
- package/go.mod +17 -0
- package/go.sum +24 -0
- package/install.js +122 -0
- package/install.sh +104 -0
- package/internal/progress/bar.go +121 -0
- package/main.go +10 -0
- package/package.json +43 -0
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
|
+
}
|