Skip to content

Commit 66dc396

Browse files
committed
feat: add server URL and token options
If the server URL has a path, then the SDK will implicitly disable the server since the local SDK server cannot have a path. Signed-off-by: Donnie Adams <donnie@acorn.io>
1 parent c0fb2e8 commit 66dc396

File tree

3 files changed

+69
-26
lines changed

3 files changed

+69
-26
lines changed

gptscript.go

+43-14
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"fmt"
1111
"io"
1212
"log/slog"
13+
"net/url"
1314
"os"
1415
"os/exec"
1516
"path/filepath"
@@ -28,7 +29,6 @@ var (
2829
const relativeToBinaryPath = "<me>"
2930

3031
type GPTScript struct {
31-
url string
3232
globalOpts GlobalOptions
3333
}
3434

@@ -38,10 +38,11 @@ func NewGPTScript(opts ...GlobalOptions) (*GPTScript, error) {
3838
defer lock.Unlock()
3939
gptscriptCount++
4040

41-
disableServer := os.Getenv("GPTSCRIPT_DISABLE_SERVER") == "true"
42-
4341
if serverURL == "" {
44-
serverURL = os.Getenv("GPTSCRIPT_URL")
42+
serverURL = opt.URL
43+
if serverURL == "" {
44+
serverURL = os.Getenv("GPTSCRIPT_URL")
45+
}
4546
}
4647

4748
if opt.Env == nil {
@@ -50,11 +51,31 @@ func NewGPTScript(opts ...GlobalOptions) (*GPTScript, error) {
5051

5152
opt.Env = append(opt.Env, opt.toEnv()...)
5253

53-
if serverProcessCancel == nil && !disableServer {
54+
if serverProcessCancel == nil && os.Getenv("GPTSCRIPT_DISABLE_SERVER") != "true" {
55+
if serverURL != "" {
56+
u, err := url.Parse(serverURL)
57+
if err != nil {
58+
return nil, fmt.Errorf("failed to parse server URL: %w", err)
59+
}
60+
61+
// If the server URL has a path, then this implies that the server is already running.
62+
// In that case, we don't need to start the server.
63+
if u.Path != "" && u.Path != "/" {
64+
opt.URL = serverURL
65+
if !strings.HasPrefix(opt.URL, "http://") && !strings.HasPrefix(opt.URL, "https://") {
66+
opt.URL = "http://" + opt.URL
67+
}
68+
69+
return &GPTScript{
70+
globalOpts: opt,
71+
}, nil
72+
}
73+
}
74+
5475
ctx, cancel := context.WithCancel(context.Background())
5576
in, _ := io.Pipe()
5677

57-
serverProcess = exec.CommandContext(ctx, getCommand(), "sys.sdkserver", "--listen-address", serverURL)
78+
serverProcess = exec.CommandContext(ctx, getCommand(), "sys.sdkserver", "--listen-address", strings.TrimPrefix(serverURL, "http://"))
5879
serverProcess.Env = opt.Env[:]
5980

6081
serverProcess.Stdin = in
@@ -95,12 +116,14 @@ func NewGPTScript(opts ...GlobalOptions) (*GPTScript, error) {
95116

96117
serverURL = strings.TrimSpace(serverURL)
97118
}
98-
g := &GPTScript{
99-
url: "http://" + serverURL,
100-
globalOpts: opt,
101-
}
102119

103-
return g, nil
120+
opt.URL = serverURL
121+
if !strings.HasPrefix(opt.URL, "http://") && !strings.HasPrefix(opt.URL, "https://") {
122+
opt.URL = "http://" + opt.URL
123+
}
124+
return &GPTScript{
125+
globalOpts: opt,
126+
}, nil
104127
}
105128

106129
func readAddress(stdErr io.Reader) (string, error) {
@@ -117,6 +140,10 @@ func readAddress(stdErr io.Reader) (string, error) {
117140
return addr, nil
118141
}
119142

143+
func (g *GPTScript) URL() string {
144+
return g.globalOpts.URL
145+
}
146+
120147
func (g *GPTScript) Close() {
121148
lock.Lock()
122149
defer lock.Unlock()
@@ -131,7 +158,8 @@ func (g *GPTScript) Close() {
131158
func (g *GPTScript) Evaluate(ctx context.Context, opts Options, tools ...ToolDef) (*Run, error) {
132159
opts.GlobalOptions = completeGlobalOptions(g.globalOpts, opts.GlobalOptions)
133160
return (&Run{
134-
url: g.url,
161+
url: opts.URL,
162+
token: opts.Token,
135163
requestPath: "evaluate",
136164
state: Creating,
137165
opts: opts,
@@ -142,7 +170,8 @@ func (g *GPTScript) Evaluate(ctx context.Context, opts Options, tools ...ToolDef
142170
func (g *GPTScript) Run(ctx context.Context, toolPath string, opts Options) (*Run, error) {
143171
opts.GlobalOptions = completeGlobalOptions(g.globalOpts, opts.GlobalOptions)
144172
return (&Run{
145-
url: g.url,
173+
url: opts.URL,
174+
token: opts.Token,
146175
requestPath: "run",
147176
state: Creating,
148177
opts: opts,
@@ -309,7 +338,7 @@ func (g *GPTScript) PromptResponse(ctx context.Context, resp PromptResponse) err
309338

310339
func (g *GPTScript) runBasicCommand(ctx context.Context, requestPath string, body any) (string, error) {
311340
run := &Run{
312-
url: g.url,
341+
url: g.globalOpts.URL,
313342
requestPath: requestPath,
314343
state: Creating,
315344
basicCommand: true,

opts.go

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package gptscript
33
// GlobalOptions allows specification of settings that are used for every call made.
44
// These options can be overridden by the corresponding Options.
55
type GlobalOptions struct {
6+
URL string `json:"url"`
7+
Token string `json:"token"`
68
OpenAIAPIKey string `json:"APIKey"`
79
OpenAIBaseURL string `json:"BaseURL"`
810
DefaultModel string `json:"DefaultModel"`
@@ -33,6 +35,8 @@ func completeGlobalOptions(opts ...GlobalOptions) GlobalOptions {
3335
var result GlobalOptions
3436
for _, opt := range opts {
3537
result.CacheDir = firstSet(opt.CacheDir, result.CacheDir)
38+
result.URL = firstSet(opt.URL, result.URL)
39+
result.Token = firstSet(opt.Token, result.Token)
3640
result.OpenAIAPIKey = firstSet(opt.OpenAIAPIKey, result.OpenAIAPIKey)
3741
result.OpenAIBaseURL = firstSet(opt.OpenAIBaseURL, result.OpenAIBaseURL)
3842
result.DefaultModel = firstSet(opt.DefaultModel, result.DefaultModel)

run.go

+22-12
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ import (
1818
var errAbortRun = errors.New("run aborted")
1919

2020
type Run struct {
21-
url, requestPath, toolPath string
22-
tools []ToolDef
23-
opts Options
24-
state RunState
25-
chatState string
26-
cancel context.CancelCauseFunc
27-
err error
28-
wait func()
29-
basicCommand bool
21+
url, token, requestPath, toolPath string
22+
tools []ToolDef
23+
opts Options
24+
state RunState
25+
chatState string
26+
cancel context.CancelCauseFunc
27+
err error
28+
wait func()
29+
basicCommand bool
3030

3131
program *Program
3232
callsLock sync.RWMutex
@@ -175,18 +175,24 @@ func (r *Run) NextChat(ctx context.Context, input string) (*Run, error) {
175175
run.opts.ChatState = r.chatState
176176
}
177177

178-
var payload any
178+
var (
179+
payload any
180+
options = run.opts
181+
)
182+
// Remove the url and token because they shouldn't be sent with the payload.
183+
options.URL = ""
184+
options.Token = ""
179185
if len(r.tools) != 0 {
180186
payload = requestPayload{
181187
ToolDefs: r.tools,
182188
Input: input,
183-
Options: run.opts,
189+
Options: options,
184190
}
185191
} else if run.toolPath != "" {
186192
payload = requestPayload{
187193
File: run.toolPath,
188194
Input: input,
189-
Options: run.opts,
195+
Options: options,
190196
}
191197
}
192198

@@ -228,6 +234,10 @@ func (r *Run) request(ctx context.Context, payload any) (err error) {
228234
return r.err
229235
}
230236

237+
if r.opts.Token != "" {
238+
req.Header.Set("Authorization", "Bearer "+r.opts.Token)
239+
}
240+
231241
resp, err := http.DefaultClient.Do(req)
232242
if err != nil {
233243
r.state = Error

0 commit comments

Comments
 (0)