@@ -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+
1524func (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
2235func (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}
0 commit comments