Skip to content

Commit ed39111

Browse files
Add support for serving UI
1 parent 01273d5 commit ed39111

File tree

7 files changed

+51
-28
lines changed

7 files changed

+51
-28
lines changed

pkg/engine/daemon.go

+41-17
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,45 @@ import (
77
"net/http"
88
"os"
99
"strings"
10+
"sync"
1011
"time"
1112

1213
"github.com/gptscript-ai/gptscript/pkg/types"
1314
)
1415

16+
var (
17+
daemonPorts map[string]int64
18+
daemonLock sync.Mutex
19+
20+
startPort, endPort int64
21+
nextPort int64
22+
)
23+
1524
func (e *Engine) getNextPort() int64 {
16-
count := e.endPort - e.startPort
17-
e.nextPort++
18-
e.nextPort = e.nextPort % count
19-
return e.startPort + e.nextPort
25+
if startPort == 0 {
26+
startPort = 10240
27+
endPort = 11240
28+
}
29+
count := endPort - startPort
30+
nextPort++
31+
nextPort = nextPort % count
32+
return startPort + nextPort
2033
}
2134

2235
func (e *Engine) startDaemon(ctx context.Context, tool types.Tool) (string, error) {
23-
e.daemonLock.Lock()
24-
defer e.daemonLock.Unlock()
36+
daemonLock.Lock()
37+
defer daemonLock.Unlock()
2538

26-
port, ok := e.daemonPorts[tool.ID]
39+
port, ok := daemonPorts[tool.ID]
2740
url := fmt.Sprintf("http://127.0.0.1:%d", port)
2841
if ok {
2942
return url, nil
3043
}
3144

3245
port = e.getNextPort()
46+
url = fmt.Sprintf("http://127.0.0.1:%d", port)
3347

34-
instructions := strings.TrimPrefix(tool.Instructions, "#!daemon ")
48+
instructions := types.CommandPrefix + strings.TrimPrefix(tool.Instructions, types.DaemonPrefix)
3549
cmd, close, err := e.newCommand(ctx, []string{
3650
fmt.Sprintf("PORT=%d", port),
3751
},
@@ -44,22 +58,31 @@ func (e *Engine) startDaemon(ctx context.Context, tool types.Tool) (string, erro
4458

4559
cmd.Stderr = os.Stderr
4660
cmd.Stdout = os.Stdout
47-
log.Infof("launching [%s] port [%d] %v", tool.Name, port, cmd.Args)
61+
log.Infof("launched [%s] port [%d] %v", tool.Name, port, cmd.Args)
4862
if err := cmd.Start(); err != nil {
4963
close()
5064
return url, err
5165
}
5266

67+
if daemonPorts == nil {
68+
daemonPorts = map[string]int64{}
69+
}
70+
71+
killedCtx, cancel := context.WithCancelCause(ctx)
72+
defer cancel(nil)
73+
5374
go func() {
54-
if err := cmd.Wait(); err != nil {
75+
err := cmd.Wait()
76+
if err != nil {
5577
log.Errorf("daemon exited tool [%s] %v: %v", tool.Name, cmd.Args, err)
5678
}
5779

80+
cancel(err)
5881
close()
59-
e.daemonLock.Lock()
60-
defer e.daemonLock.Unlock()
82+
daemonLock.Lock()
83+
defer daemonLock.Unlock()
6184

62-
delete(e.daemonPorts, tool.ID)
85+
delete(daemonPorts, tool.ID)
6386
}()
6487

6588
context.AfterFunc(ctx, func() {
@@ -78,8 +101,8 @@ func (e *Engine) startDaemon(ctx context.Context, tool types.Tool) (string, erro
78101
return url, nil
79102
}
80103
select {
81-
case <-ctx.Done():
82-
return url, ctx.Err()
104+
case <-killedCtx.Done():
105+
return url, fmt.Errorf("daemon failed to start: %w", context.Cause(killedCtx))
83106
case <-time.After(time.Second):
84107
}
85108
}
@@ -93,7 +116,8 @@ func (e *Engine) runDaemon(ctx context.Context, tool types.Tool, input string) (
93116
return nil, err
94117
}
95118

96-
tool.Instructions = strings.Join(append([]string{url},
97-
strings.Split(tool.Instructions, "\n")[1:]...), "\n")
119+
tool.Instructions = strings.Join(append([]string{
120+
types.CommandPrefix + url,
121+
}, strings.Split(tool.Instructions, "\n")[1:]...), "\n")
98122
return e.runHTTP(ctx, tool, input)
99123
}

pkg/engine/engine.go

-6
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,6 @@ type Engine struct {
5656
Client *openai.Client
5757
Env []string
5858
Progress chan<- openai.Status
59-
60-
daemonPorts map[string]int64
61-
daemonLock sync.Mutex
62-
63-
startPort, endPort int64
64-
nextPort int64
6559
}
6660

6761
type State struct {

pkg/engine/http.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import (
1313
func (e *Engine) runHTTP(ctx context.Context, tool types.Tool, input string) (cmdRet *Return, cmdErr error) {
1414
url := strings.Split(tool.Instructions, "\n")[0][2:]
1515

16-
req, err := http.NewRequestWithContext(ctx, url, http.MethodPost, strings.NewReader(input))
16+
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, strings.NewReader(input))
1717
if err != nil {
18-
return
18+
return nil, err
1919
}
2020

2121
req.Header.Set("X-GPTScript-Tool-Name", tool.Name)

pkg/types/tool.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ import (
77
"strings"
88
)
99

10+
const (
11+
DaemonPrefix = "#!sys.daemon "
12+
CommandPrefix = "#!"
13+
)
14+
1015
type ToolSet map[string]Tool
1116

1217
type Program struct {
@@ -94,11 +99,11 @@ func (t ToolSource) String() string {
9499
}
95100

96101
func (t Tool) IsCommand() bool {
97-
return strings.HasPrefix(t.Instructions, "#!")
102+
return strings.HasPrefix(t.Instructions, CommandPrefix)
98103
}
99104

100105
func (t Tool) IsDaemon() bool {
101-
return strings.HasPrefix(t.Instructions, "#!sys.daemon")
106+
return strings.HasPrefix(t.Instructions, DaemonPrefix)
102107
}
103108

104109
func (t Tool) IsHTTP() bool {

static/fs.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ import (
55
_ "embed"
66
)
77

8-
// /go:embed ui/** ui/**/_*
8+
//go:embed * ui/_nuxt/*
99
var UI embed.FS

static/ui/_nuxt/_placeholder

Whitespace-only changes.

static/ui/placeholder

Whitespace-only changes.

0 commit comments

Comments
 (0)