@@ -7,31 +7,45 @@ import (
7
7
"net/http"
8
8
"os"
9
9
"strings"
10
+ "sync"
10
11
"time"
11
12
12
13
"github.com/gptscript-ai/gptscript/pkg/types"
13
14
)
14
15
16
+ var (
17
+ daemonPorts map [string ]int64
18
+ daemonLock sync.Mutex
19
+
20
+ startPort , endPort int64
21
+ nextPort int64
22
+ )
23
+
15
24
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
20
33
}
21
34
22
35
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 ()
25
38
26
- port , ok := e . daemonPorts [tool .ID ]
39
+ port , ok := daemonPorts [tool .ID ]
27
40
url := fmt .Sprintf ("http://127.0.0.1:%d" , port )
28
41
if ok {
29
42
return url , nil
30
43
}
31
44
32
45
port = e .getNextPort ()
46
+ url = fmt .Sprintf ("http://127.0.0.1:%d" , port )
33
47
34
- instructions := strings .TrimPrefix (tool .Instructions , "#!daemon " )
48
+ instructions := types . CommandPrefix + strings .TrimPrefix (tool .Instructions , types . DaemonPrefix )
35
49
cmd , close , err := e .newCommand (ctx , []string {
36
50
fmt .Sprintf ("PORT=%d" , port ),
37
51
},
@@ -44,22 +58,31 @@ func (e *Engine) startDaemon(ctx context.Context, tool types.Tool) (string, erro
44
58
45
59
cmd .Stderr = os .Stderr
46
60
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 )
48
62
if err := cmd .Start (); err != nil {
49
63
close ()
50
64
return url , err
51
65
}
52
66
67
+ if daemonPorts == nil {
68
+ daemonPorts = map [string ]int64 {}
69
+ }
70
+
71
+ killedCtx , cancel := context .WithCancelCause (ctx )
72
+ defer cancel (nil )
73
+
53
74
go func () {
54
- if err := cmd .Wait (); err != nil {
75
+ err := cmd .Wait ()
76
+ if err != nil {
55
77
log .Errorf ("daemon exited tool [%s] %v: %v" , tool .Name , cmd .Args , err )
56
78
}
57
79
80
+ cancel (err )
58
81
close ()
59
- e . daemonLock .Lock ()
60
- defer e . daemonLock .Unlock ()
82
+ daemonLock .Lock ()
83
+ defer daemonLock .Unlock ()
61
84
62
- delete (e . daemonPorts , tool .ID )
85
+ delete (daemonPorts , tool .ID )
63
86
}()
64
87
65
88
context .AfterFunc (ctx , func () {
@@ -78,8 +101,8 @@ func (e *Engine) startDaemon(ctx context.Context, tool types.Tool) (string, erro
78
101
return url , nil
79
102
}
80
103
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 ) )
83
106
case <- time .After (time .Second ):
84
107
}
85
108
}
@@ -93,7 +116,8 @@ func (e *Engine) runDaemon(ctx context.Context, tool types.Tool, input string) (
93
116
return nil , err
94
117
}
95
118
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 " )
98
122
return e .runHTTP (ctx , tool , input )
99
123
}
0 commit comments