Skip to content

Commit 0a7b10d

Browse files
committed
chore: update SDK for improved SDK server startup
Signed-off-by: Donnie Adams <[email protected]>
1 parent 5c0f789 commit 0a7b10d

File tree

1 file changed

+38
-41
lines changed

1 file changed

+38
-41
lines changed

gptscript.go

+38-41
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
package gptscript
22

33
import (
4+
"bufio"
45
"context"
56
"encoding/json"
67
"fmt"
78
"io"
89
"log/slog"
9-
"net"
10-
"net/http"
1110
"os"
1211
"os/exec"
1312
"path/filepath"
1413
"strings"
1514
"sync"
16-
"time"
1715
)
1816

1917
var (
@@ -42,70 +40,69 @@ func NewGPTScript(opts GlobalOptions) (*GPTScript, error) {
4240
}
4341

4442
if serverProcessCancel == nil && !disableServer {
45-
if serverURL == "" {
46-
l, err := net.Listen("tcp", "127.0.0.1:0")
47-
if err != nil {
48-
slog.Debug("failed to start gptscript listener", "err", err)
49-
return nil, fmt.Errorf("failed to start gptscript: %w", err)
50-
}
51-
52-
serverURL = l.Addr().String()
53-
if err = l.Close(); err != nil {
54-
slog.Debug("failed to close gptscript listener", "err", err)
55-
return nil, fmt.Errorf("failed to start gptscript: %w", err)
56-
}
57-
}
58-
5943
ctx, cancel := context.WithCancel(context.Background())
60-
6144
in, _ := io.Pipe()
45+
6246
serverProcess = exec.CommandContext(ctx, getCommand(), "sys.sdkserver", "--listen-address", serverURL)
6347
if opts.Env == nil {
6448
opts.Env = os.Environ()
6549
}
50+
6651
serverProcess.Env = append(opts.Env[:], opts.toEnv()...)
52+
6753
serverProcess.Stdin = in
54+
stdErr, err := serverProcess.StderrPipe()
55+
if err != nil {
56+
cancel()
57+
return nil, fmt.Errorf("failed to get stderr pipe: %w", err)
58+
}
6859

6960
serverProcessCancel = func() {
7061
cancel()
7162
_ = in.Close()
63+
_ = serverProcess.Wait()
7264
}
7365

74-
if err := serverProcess.Start(); err != nil {
66+
if err = serverProcess.Start(); err != nil {
7567
serverProcessCancel()
7668
return nil, fmt.Errorf("failed to start server: %w", err)
7769
}
7870

79-
timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
80-
defer cancel()
81-
if err := waitForServerReady(timeoutCtx, serverURL); err != nil {
71+
serverURL, err = readAddress(stdErr)
72+
if err != nil {
8273
serverProcessCancel()
83-
_ = serverProcess.Wait()
84-
return nil, fmt.Errorf("failed to wait for gptscript to be ready: %w", err)
74+
return nil, fmt.Errorf("failed to read server URL: %w", err)
8575
}
76+
77+
go func() {
78+
for {
79+
// Ensure that stdErr is drained as logs come in
80+
_, _, _ = bufio.NewReader(stdErr).ReadLine()
81+
}
82+
}()
83+
84+
if _, url, found := strings.Cut(serverURL, "addr="); found {
85+
// Ensure backwards compatibility with older versions of the SDK server
86+
serverURL = url
87+
}
88+
89+
serverURL = strings.TrimSpace(serverURL)
8690
}
8791
return &GPTScript{url: "http://" + serverURL}, nil
8892
}
8993

90-
func waitForServerReady(ctx context.Context, serverURL string) error {
91-
for {
92-
resp, err := http.Get("http://" + serverURL + "/healthz")
93-
if err != nil {
94-
slog.DebugContext(ctx, "waiting for server to become ready")
95-
} else {
96-
_ = resp.Body.Close()
97-
98-
if resp.StatusCode == http.StatusOK {
99-
return nil
100-
}
101-
}
94+
func readAddress(stdErr io.Reader) (string, error) {
95+
addr, err := bufio.NewReader(stdErr).ReadString('\n')
96+
if err != nil {
97+
return "", fmt.Errorf("failed to read server address: %w", err)
98+
}
10299

103-
select {
104-
case <-ctx.Done():
105-
return ctx.Err()
106-
case <-time.After(time.Second):
107-
}
100+
if _, url, found := strings.Cut(addr, "addr="); found {
101+
// For backward compatibility: older versions of the SDK server print the address in a slightly different way.
102+
addr = url
108103
}
104+
105+
return addr, nil
109106
}
110107

111108
func (g *GPTScript) Close() {

0 commit comments

Comments
 (0)