From 9fe6fd0711ea6df3d37b5d911718af9b7201398c Mon Sep 17 00:00:00 2001 From: Donnie Adams Date: Thu, 25 Apr 2024 19:48:11 -0400 Subject: [PATCH] fix: update SDK to be consistent with the other SDKs The Go SDK handled stdout and stderr differently from the other SDKs. This change bring the Go SDK into sync. Signed-off-by: Donnie Adams --- exec.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++++--- exec_test.go | 15 +++++++++-- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/exec.go b/exec.go index a905687..989b204 100644 --- a/exec.go +++ b/exec.go @@ -31,6 +31,12 @@ func (o Opts) toArgs() []string { return append(args, "--quiet="+fmt.Sprint(o.Quiet)) } +// Version will return the output of `gptscript --version` +func Version(ctx context.Context) (string, error) { + out, err := exec.CommandContext(ctx, getCommand(), "--version").CombinedOutput() + return string(out), err +} + // ListTools will list all the available tools. func ListTools(ctx context.Context) (string, error) { out, err := exec.CommandContext(ctx, getCommand(), "--list-tools").CombinedOutput() @@ -50,8 +56,36 @@ func ListModels(ctx context.Context) ([]string, error) { func ExecTool(ctx context.Context, opts Opts, tools ...fmt.Stringer) (string, error) { c := exec.CommandContext(ctx, getCommand(), append(opts.toArgs(), "-")...) c.Stdin = strings.NewReader(concatTools(tools)) - out, err := c.CombinedOutput() - return string(out), err + + stdout, err := c.StdoutPipe() + if err != nil { + return "", fmt.Errorf("failed to get stdout pipe: %w", err) + } + + stderr, err := c.StderrPipe() + if err != nil { + return "", fmt.Errorf("failed to get stderr pipe: %w", err) + } + + if err = c.Start(); err != nil { + return "", fmt.Errorf("failed to start command: %w", err) + } + + stdErr, err := io.ReadAll(stderr) + if err != nil { + return "", fmt.Errorf("failed to read stderr: %w", err) + } + + stdOut, err := io.ReadAll(stdout) + if err != nil { + return "", fmt.Errorf("failed to read stdout: %w", err) + } + + if err = c.Wait(); err != nil { + return "", fmt.Errorf("failed to wait for command, stderr: %s: %w", stdErr, err) + } + + return string(stdOut), err } // StreamExecTool will execute a tool. The tool must be a fmt.Stringer, and the string should be a valid gptscript file. @@ -115,8 +149,37 @@ func ExecFile(ctx context.Context, toolPath, input string, opts Opts) (string, e args = append(args, input) } - out, err := exec.CommandContext(ctx, getCommand(), args...).CombinedOutput() - return string(out), err + c := exec.CommandContext(ctx, getCommand(), args...) + + stdout, err := c.StdoutPipe() + if err != nil { + return "", fmt.Errorf("failed to get stdout pipe: %w", err) + } + + stderr, err := c.StderrPipe() + if err != nil { + return "", fmt.Errorf("failed to get stderr pipe: %w", err) + } + + if err = c.Start(); err != nil { + return "", fmt.Errorf("failed to start command: %w", err) + } + + stdErr, err := io.ReadAll(stderr) + if err != nil { + return "", fmt.Errorf("failed to read stderr: %w", err) + } + + stdOut, err := io.ReadAll(stdout) + if err != nil { + return "", fmt.Errorf("failed to read stdout: %w", err) + } + + if err = c.Wait(); err != nil { + return "", fmt.Errorf("failed to wait for command, stderr: %s: %w", stdErr, err) + } + + return string(stdOut), err } // StreamExecFile will execute the file at the given path with the given input. diff --git a/exec_test.go b/exec_test.go index 812e0bd..8b0ecca 100644 --- a/exec_test.go +++ b/exec_test.go @@ -18,6 +18,17 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestVersion(t *testing.T) { + out, err := Version(context.Background()) + if err != nil { + t.Errorf("Error getting version: %v", err) + } + + if !strings.HasPrefix(out, "gptscript version") { + t.Errorf("Unexpected output: %s", out) + } +} + func TestListTools(t *testing.T) { tools, err := ListTools(context.Background()) if err != nil { @@ -101,7 +112,7 @@ func TestExecWithToolList(t *testing.T) { tools := []fmt.Stringer{ &Tool{ Tools: []string{"echo"}, - Instructions: "echo hello times", + Instructions: "echo hello there", }, &Tool{ Name: "echo", @@ -119,7 +130,7 @@ func TestExecWithToolList(t *testing.T) { t.Errorf("Error executing tool: %v", err) } - if !strings.Contains(out, "hello times") { + if !strings.Contains(out, "hello there") { t.Errorf("Unexpected output: %s", out) } }