2
2
import type { SSE } from "sse.js"
3
3
4
4
export interface RunOpts {
5
- gptscriptURL ?: string
6
5
input ?: string
7
6
cacheDir ?: string
8
7
disableCache ?: boolean
@@ -40,15 +39,132 @@ export enum RunEventType {
40
39
CallFinish = "callFinish" ,
41
40
}
42
41
42
+ export class Client {
43
+ public readonly gptscriptURL ?: string
44
+ public gptscriptBin ?: string
45
+
46
+ constructor ( gptscriptURL ?: string , gptscriptBin ?: string ) {
47
+ this . gptscriptURL = gptscriptURL
48
+ this . gptscriptBin = gptscriptBin
49
+ }
50
+
51
+ listTools ( ) : Promise < string > {
52
+ return this . runBasicCommand ( "list-tools" )
53
+ }
54
+
55
+ listModels ( ) : Promise < string > {
56
+ return this . runBasicCommand ( "list-models" )
57
+ }
58
+
59
+ version ( ) : Promise < string > {
60
+ return this . runBasicCommand ( "version" )
61
+ }
62
+
63
+ async runBasicCommand ( cmd : string ) : Promise < string > {
64
+ const r = new RunSubcommand ( cmd , "" , "" , { } , this . gptscriptBin , this . gptscriptURL )
65
+ if ( this . gptscriptURL ) {
66
+ r . request ( null )
67
+ } else {
68
+ await r . exec ( [ "--" + cmd ] )
69
+ }
70
+ return r . text ( )
71
+ }
72
+
73
+ /**
74
+ * Runs a tool with the specified name and options.
75
+ *
76
+ * @param {string } toolName - The name of the tool to run. Can be a file path, URL, or GitHub URL.
77
+ * @param {RunOpts } [opts={}] - The options for running the tool.
78
+ * @return {Run } The Run object representing the running tool.
79
+ */
80
+ run ( toolName : string , opts : RunOpts = { } ) : Run {
81
+ return ( new Run ( "run-file-stream-with-events" , toolName , "" , opts ) ) . nextChat ( opts . input )
82
+ }
83
+
84
+ /**
85
+ * Evaluates the given tool and returns a Run object.
86
+ *
87
+ * @param {ToolDef | ToolDef[] | string } tool - The tool to be evaluated. Can be a single ToolDef object, an array of ToolDef objects, or a string representing the tool contents.
88
+ * @param {RunOpts } [opts={}] - Optional options for the evaluation.
89
+ * @return {Run } The Run object representing the evaluation.
90
+ */
91
+ evaluate ( tool : ToolDef | ToolDef [ ] | string , opts : RunOpts = { } ) : Run {
92
+ let toolString : string = ""
93
+
94
+ if ( Array . isArray ( tool ) ) {
95
+ toolString = toolArrayToContents ( tool )
96
+ } else if ( typeof tool === "string" ) {
97
+ toolString = tool
98
+ } else {
99
+ toolString = toolDefToString ( tool )
100
+ }
101
+
102
+ return ( new Run ( "run-tool-stream-with-event" , "" , toolString , opts ) ) . nextChat ( opts . input )
103
+ }
104
+
105
+ async parse ( fileName : string ) : Promise < Block [ ] > {
106
+ const r : Run = new RunSubcommand ( "parse" , fileName , "" , { } , this . gptscriptBin , this . gptscriptURL )
107
+ if ( this . gptscriptURL ) {
108
+ r . request ( { file : fileName } )
109
+ } else {
110
+ await r . exec ( [ "parse" ] )
111
+ }
112
+ return parseBlocksFromNodes ( ( await r . json ( ) ) . nodes )
113
+ }
114
+
115
+ async parseTool ( toolContent : string ) : Promise < Block [ ] > {
116
+ const r : Run = new RunSubcommand ( "parse" , "" , toolContent , { } , this . gptscriptBin , this . gptscriptURL )
117
+ if ( this . gptscriptURL ) {
118
+ r . request ( { input : toolContent } )
119
+ } else {
120
+ await r . exec ( [ "parse" ] )
121
+ }
122
+ return parseBlocksFromNodes ( ( await r . json ( ) ) . nodes )
123
+ }
124
+
125
+ async stringify ( blocks : Block [ ] ) : Promise < string > {
126
+ const nodes : any [ ] = [ ]
127
+
128
+ for ( const block of blocks ) {
129
+ if ( block . type === "tool" ) {
130
+ nodes . push ( {
131
+ toolNode : {
132
+ tool : block
133
+ }
134
+ } )
135
+ } else if ( block . type === "text" ) {
136
+ nodes . push ( {
137
+ textNode : {
138
+ text : "!" + ( block . format || "text" ) + "\n" + block . content
139
+ }
140
+ } )
141
+ }
142
+ }
143
+
144
+ const r : Run = new RunSubcommand ( "fmt" , "" , JSON . stringify ( { nodes : nodes } ) , { } , this . gptscriptBin , this . gptscriptURL )
145
+ if ( this . gptscriptURL ) {
146
+ r . request ( { nodes : nodes } )
147
+ } else {
148
+ await r . exec ( [ "fmt" ] )
149
+ }
150
+
151
+ return r . text ( )
152
+ }
153
+ }
154
+
43
155
export class Run {
44
156
public readonly id : string
45
157
public readonly opts : RunOpts
46
- public state : RunState = RunState . Creating
47
- public calls : Call [ ] = [ ]
48
- public err = ""
49
158
public readonly filePath : string
50
159
public readonly content : string
160
+ public state : RunState = RunState . Creating
161
+ public calls : Call [ ] = [ ]
162
+ public err : string = ""
163
+
51
164
protected stdout ?: string
165
+
166
+ private readonly bin ?: string
167
+ private readonly gptscriptURL ?: string
52
168
private readonly requestPath : string = ""
53
169
private promise ?: Promise < string >
54
170
private process ?: any
@@ -58,12 +174,17 @@ export class Run {
58
174
private callbacks : Record < string , ( ( f : Frame ) => void ) [ ] > = { }
59
175
private chatState : string | undefined
60
176
61
- constructor ( subCommand : string , path : string , content : string , opts : RunOpts ) {
177
+ constructor ( subCommand : string , path : string , content : string , opts : RunOpts , bin ?: string , gptscriptURL ?: string ) {
62
178
this . id = randomId ( "run-" )
63
179
this . requestPath = subCommand
64
180
this . opts = opts
65
181
this . filePath = path
66
182
this . content = content
183
+
184
+ if ( bin ) {
185
+ this . bin = bin
186
+ }
187
+ this . gptscriptURL = gptscriptURL
67
188
}
68
189
69
190
nextChat ( input : string = "" ) : Run {
@@ -78,16 +199,16 @@ export class Run {
78
199
79
200
run . chatState = this . chatState
80
201
run . opts . input = input
81
- if ( run . opts . gptscriptURL ) {
202
+ if ( run . gptscriptURL ) {
82
203
if ( run . content !== "" ) {
83
204
run . request ( { content : this . content } )
84
205
} else {
85
206
run . request ( { file : this . filePath } )
86
207
}
87
208
} else {
88
209
run . exec ( ) . catch ( ( e ) => {
89
- run . state = RunState . Error
90
210
run . err = e . toString ( )
211
+ run . state = RunState . Error
91
212
}
92
213
)
93
214
}
@@ -146,7 +267,7 @@ export class Run {
146
267
147
268
const child_process = await import ( "child_process" )
148
269
149
- this . process = child_process . spawn ( await getCmdPath ( ) , extraArgs , spawnOptions as any )
270
+ this . process = child_process . spawn ( this . bin || await getCmdPath ( ) , extraArgs , spawnOptions as any )
150
271
if ( process . platform !== "win32" ) {
151
272
// We don't need the named pipe for streaming events.
152
273
server . close ( )
@@ -165,8 +286,8 @@ export class Run {
165
286
}
166
287
167
288
if ( ! this . process ) {
168
- this . state = RunState . Error
169
289
this . err = "Run failed to start"
290
+ this . state = RunState . Error
170
291
server . close ( )
171
292
this . promise = Promise . reject ( this . err )
172
293
return
@@ -199,11 +320,11 @@ export class Run {
199
320
server . close ( )
200
321
201
322
if ( signal ) {
202
- this . state = RunState . Error
203
323
this . err = "Run has been aborted"
204
- } else if ( code !== 0 ) {
205
324
this . state = RunState . Error
325
+ } else if ( code !== 0 ) {
206
326
this . err = this . stderr || ""
327
+ this . state = RunState . Error
207
328
} else if ( this . state !== RunState . Continue ) {
208
329
this . state = RunState . Finished
209
330
}
@@ -243,18 +364,18 @@ export class Run {
243
364
}
244
365
245
366
request ( tool : any ) {
246
- if ( ! this . opts . gptscriptURL ) {
367
+ if ( ! this . gptscriptURL ) {
247
368
throw new Error ( "request() requires gptscriptURL to be set" )
248
369
}
249
370
const postData = JSON . stringify ( { ...tool , ...this . opts } )
250
- const options = this . requestOptions ( this . opts . gptscriptURL , this . requestPath , postData , tool )
371
+ const options = this . requestOptions ( this . gptscriptURL , this . requestPath , postData , tool )
251
372
252
373
this . promise = new Promise < string > ( async ( resolve , reject ) => {
253
374
// This checks that the code is running in a browser. If it is, then we use SSE.
254
375
if ( typeof window !== "undefined" && typeof window . document !== "undefined" ) {
255
376
// @ts -ignore
256
377
const { SSE } = await import ( "sse.js" )
257
- this . sse = new SSE ( this . opts . gptscriptURL + "/" + this . filePath , {
378
+ this . sse = new SSE ( this . gptscriptURL + "/" + this . filePath , {
258
379
headers : { "Content-Type" : "application/json" } ,
259
380
payload : postData
260
381
} as any )
@@ -530,8 +651,8 @@ export class Run {
530
651
}
531
652
532
653
class RunSubcommand extends Run {
533
- constructor ( subCommand : string , path : string , content : string , opts : RunOpts ) {
534
- super ( subCommand , path , content , opts )
654
+ constructor ( subCommand : string , path : string , content : string , opts : RunOpts , bin ?: string , gptscriptURL ?: string ) {
655
+ super ( subCommand , path , content , opts , bin , gptscriptURL )
535
656
}
536
657
537
658
processStdout ( data : string | object ) {
@@ -777,109 +898,6 @@ async function getCmdPath(): Promise<string> {
777
898
return path . join ( path . dirname ( url . fileURLToPath ( import . meta. url ) ) , ".." , "bin" , "gptscript" )
778
899
}
779
900
780
- export function listTools ( gptscriptURL ?: string ) : Promise < string > {
781
- return runBasicCommand ( "list-tools" , gptscriptURL )
782
- }
783
-
784
- export function listModels ( gptscriptURL ?: string ) : Promise < string > {
785
- return runBasicCommand ( "list-models" , gptscriptURL )
786
- }
787
-
788
- export function version ( gptscriptURL ?: string ) : Promise < string > {
789
- return runBasicCommand ( "version" , gptscriptURL )
790
- }
791
-
792
- async function runBasicCommand ( cmd : string , gptscriptURL ?: string ) : Promise < string > {
793
- const r = new RunSubcommand ( cmd , "" , "" , { gptscriptURL : gptscriptURL } )
794
- if ( gptscriptURL ) {
795
- r . request ( null )
796
- } else {
797
- await r . exec ( [ "--" + cmd ] )
798
- }
799
- return r . text ( )
800
- }
801
-
802
- /**
803
- * Runs a tool with the specified name and options.
804
- *
805
- * @param {string } toolName - The name of the tool to run. Can be a file path, URL, or GitHub URL.
806
- * @param {RunOpts } [opts={}] - The options for running the tool.
807
- * @return {Run } The Run object representing the running tool.
808
- */
809
- export function run ( toolName : string , opts : RunOpts = { } ) : Run {
810
- return ( new Run ( "run-file-stream-with-events" , toolName , "" , opts ) ) . nextChat ( opts . input )
811
- }
812
-
813
- /**
814
- * Evaluates the given tool and returns a Run object.
815
- *
816
- * @param {ToolDef | ToolDef[] | string } tool - The tool to be evaluated. Can be a single ToolDef object, an array of ToolDef objects, or a string representing the tool contents.
817
- * @param {RunOpts } [opts={}] - Optional options for the evaluation.
818
- * @return {Run } The Run object representing the evaluation.
819
- */
820
- export function evaluate ( tool : ToolDef | ToolDef [ ] | string , opts : RunOpts = { } ) : Run {
821
- let toolString : string = ""
822
-
823
- if ( Array . isArray ( tool ) ) {
824
- toolString = toolArrayToContents ( tool )
825
- } else if ( typeof tool === "string" ) {
826
- toolString = tool
827
- } else {
828
- toolString = toolDefToString ( tool )
829
- }
830
-
831
- return ( new Run ( "run-tool-stream-with-event" , "" , toolString , opts ) ) . nextChat ( opts . input )
832
- }
833
-
834
- export async function parse ( fileName : string , gptscriptURL ?: string ) : Promise < Block [ ] > {
835
- const r : Run = new RunSubcommand ( "parse" , fileName , "" , { gptscriptURL : gptscriptURL } )
836
- if ( gptscriptURL ) {
837
- r . request ( { file : fileName } )
838
- } else {
839
- await r . exec ( [ "parse" ] )
840
- }
841
- return parseBlocksFromNodes ( ( await r . json ( ) ) . nodes )
842
- }
843
-
844
- export async function parseTool ( toolContent : string , gptscriptURL ?: string ) : Promise < Block [ ] > {
845
- const r : Run = new RunSubcommand ( "parse" , "" , toolContent , { gptscriptURL : gptscriptURL } )
846
- if ( gptscriptURL ) {
847
- r . request ( { input : toolContent } )
848
- } else {
849
- await r . exec ( [ "parse" ] )
850
- }
851
- return parseBlocksFromNodes ( ( await r . json ( ) ) . nodes )
852
- }
853
-
854
- export async function stringify ( blocks : Block [ ] , gptscriptURL ?: string ) : Promise < string > {
855
- const nodes : any [ ] = [ ]
856
-
857
- for ( const block of blocks ) {
858
- if ( block . type === "tool" ) {
859
- nodes . push ( {
860
- toolNode : {
861
- tool : block
862
- }
863
- } )
864
- } else if ( block . type === "text" ) {
865
- nodes . push ( {
866
- textNode : {
867
- text : "!" + ( block . format || "text" ) + "\n" + block . content
868
- }
869
- } )
870
- }
871
- }
872
-
873
- const r : Run = new RunSubcommand ( "fmt" , "" , JSON . stringify ( { nodes : nodes } ) , { gptscriptURL : gptscriptURL } )
874
- if ( gptscriptURL ) {
875
- r . request ( { nodes : nodes } )
876
- } else {
877
- await r . exec ( [ "fmt" ] )
878
- }
879
-
880
- return r . text ( )
881
- }
882
-
883
901
function parseBlocksFromNodes ( nodes : any [ ] ) : Block [ ] {
884
902
const blocks : Block [ ] = [ ]
885
903
for ( const node of nodes ) {
0 commit comments