22import type { SSE } from "sse.js"
33
44export interface RunOpts {
5- gptscriptURL ?: string
65 input ?: string
76 cacheDir ?: string
87 disableCache ?: boolean
@@ -40,15 +39,132 @@ export enum RunEventType {
4039 CallFinish = "callFinish" ,
4140}
4241
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+
43155export class Run {
44156 public readonly id : string
45157 public readonly opts : RunOpts
46- public state : RunState = RunState . Creating
47- public calls : Call [ ] = [ ]
48- public err = ""
49158 public readonly filePath : string
50159 public readonly content : string
160+ public state : RunState = RunState . Creating
161+ public calls : Call [ ] = [ ]
162+ public err : string = ""
163+
51164 protected stdout ?: string
165+
166+ private readonly bin ?: string
167+ private readonly gptscriptURL ?: string
52168 private readonly requestPath : string = ""
53169 private promise ?: Promise < string >
54170 private process ?: any
@@ -58,12 +174,17 @@ export class Run {
58174 private callbacks : Record < string , ( ( f : Frame ) => void ) [ ] > = { }
59175 private chatState : string | undefined
60176
61- constructor ( subCommand : string , path : string , content : string , opts : RunOpts ) {
177+ constructor ( subCommand : string , path : string , content : string , opts : RunOpts , bin ?: string , gptscriptURL ?: string ) {
62178 this . id = randomId ( "run-" )
63179 this . requestPath = subCommand
64180 this . opts = opts
65181 this . filePath = path
66182 this . content = content
183+
184+ if ( bin ) {
185+ this . bin = bin
186+ }
187+ this . gptscriptURL = gptscriptURL
67188 }
68189
69190 nextChat ( input : string = "" ) : Run {
@@ -78,16 +199,16 @@ export class Run {
78199
79200 run . chatState = this . chatState
80201 run . opts . input = input
81- if ( run . opts . gptscriptURL ) {
202+ if ( run . gptscriptURL ) {
82203 if ( run . content !== "" ) {
83204 run . request ( { content : this . content } )
84205 } else {
85206 run . request ( { file : this . filePath } )
86207 }
87208 } else {
88209 run . exec ( ) . catch ( ( e ) => {
89- run . state = RunState . Error
90210 run . err = e . toString ( )
211+ run . state = RunState . Error
91212 }
92213 )
93214 }
@@ -146,7 +267,7 @@ export class Run {
146267
147268 const child_process = await import ( "child_process" )
148269
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 )
150271 if ( process . platform !== "win32" ) {
151272 // We don't need the named pipe for streaming events.
152273 server . close ( )
@@ -165,8 +286,8 @@ export class Run {
165286 }
166287
167288 if ( ! this . process ) {
168- this . state = RunState . Error
169289 this . err = "Run failed to start"
290+ this . state = RunState . Error
170291 server . close ( )
171292 this . promise = Promise . reject ( this . err )
172293 return
@@ -199,11 +320,11 @@ export class Run {
199320 server . close ( )
200321
201322 if ( signal ) {
202- this . state = RunState . Error
203323 this . err = "Run has been aborted"
204- } else if ( code !== 0 ) {
205324 this . state = RunState . Error
325+ } else if ( code !== 0 ) {
206326 this . err = this . stderr || ""
327+ this . state = RunState . Error
207328 } else if ( this . state !== RunState . Continue ) {
208329 this . state = RunState . Finished
209330 }
@@ -243,18 +364,18 @@ export class Run {
243364 }
244365
245366 request ( tool : any ) {
246- if ( ! this . opts . gptscriptURL ) {
367+ if ( ! this . gptscriptURL ) {
247368 throw new Error ( "request() requires gptscriptURL to be set" )
248369 }
249370 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 )
251372
252373 this . promise = new Promise < string > ( async ( resolve , reject ) => {
253374 // This checks that the code is running in a browser. If it is, then we use SSE.
254375 if ( typeof window !== "undefined" && typeof window . document !== "undefined" ) {
255376 // @ts -ignore
256377 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 , {
258379 headers : { "Content-Type" : "application/json" } ,
259380 payload : postData
260381 } as any )
@@ -530,8 +651,8 @@ export class Run {
530651}
531652
532653class 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 )
535656 }
536657
537658 processStdout ( data : string | object ) {
@@ -777,109 +898,6 @@ async function getCmdPath(): Promise<string> {
777898 return path . join ( path . dirname ( url . fileURLToPath ( import . meta. url ) ) , ".." , "bin" , "gptscript" )
778899}
779900
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-
883901function parseBlocksFromNodes ( nodes : any [ ] ) : Block [ ] {
884902 const blocks : Block [ ] = [ ]
885903 for ( const node of nodes ) {
0 commit comments