Skip to content

Commit 83b962c

Browse files
committed
fix: allow retry of failed runs
1 parent 601eda7 commit 83b962c

File tree

3 files changed

+41
-9
lines changed

3 files changed

+41
-9
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ None of the options is required, and the defaults will reduce the number of call
5050
- `chatState`: The chat state to continue, or null to start a new chat and return the state
5151
- `confirm`: Prompt before running potentially dangerous commands
5252
- `prompt`: Allow scripts to prompt the user for input
53+
- `env`: Extra environment variables to pass to the script in the form `KEY=VAL`
5354

5455
## Functions
5556

@@ -240,7 +241,7 @@ const gptscript = require('@gptscript-ai/gptscript');
240241
const opts = {
241242
disableCache: true,
242243
input: "--testin how high is that there mouse?",
243-
confirm: true
244+
prompt: true
244245
};
245246

246247
async function streamExecFileWithEvents() {

src/gptscript.ts

+9-8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface RunOpts {
1313
chatState?: string
1414
confirm?: boolean
1515
prompt?: boolean
16+
env?: string[]
1617
}
1718

1819
export enum RunEventType {
@@ -242,25 +243,25 @@ export class Run {
242243
}
243244

244245
nextChat(input: string = ""): Run {
245-
if (this.state === RunState.Finished || this.state === RunState.Error) {
246-
throw (new Error("Run already finished"))
246+
if (this.state !== RunState.Continue && this.state !== RunState.Creating && this.state !== RunState.Error) {
247+
throw (new Error(`Run must in creating, continue or error state, not ${this.state}`))
247248
}
248249

249250
let run = this
250251
if (run.state !== RunState.Creating) {
251252
run = new (this.constructor as any)(this.requestPath, this.filePath, this.content, this.opts, this.gptscriptURL)
252253
}
253254

254-
if (this.chatState) {
255-
run.chatState = this.chatState
256-
} else if (this.opts.chatState) {
257-
run.chatState = this.opts.chatState
255+
if (this.chatState && this.state === RunState.Continue) {
256+
// Only update the chat state if the previous run didn't error.
257+
// The chat state on opts will be the chat state for the last successful run.
258+
this.opts.chatState = this.chatState
258259
}
259260
run.opts.input = input
260261
if (run.content !== "") {
261-
run.request({content: this.content, chatState: run.chatState})
262+
run.request({content: this.content, ...this.opts})
262263
} else {
263-
run.request({file: this.filePath, chatState: run.chatState})
264+
run.request({file: this.filePath, ...this.opts})
264265
}
265266

266267
return run

tests/gptscript.test.ts

+30
Original file line numberDiff line numberDiff line change
@@ -470,4 +470,34 @@ describe("gptscript module", () => {
470470
expect(run.err).toContain("prompt occurred")
471471
expect(promptFound).toBeFalsy()
472472
})
473+
474+
test("retry failed run", async () => {
475+
let shebang = `#!/bin/bash\nexit \${EXIT_CODE}`
476+
if (process.platform == "win32") {
477+
shebang = "#!/usr/bin/env powershell.exe\n$e = $env:EXIT_CODE;\nif ($e) { Exit 1; }"
478+
}
479+
const t = {
480+
instructions: "say hello",
481+
context: ["my-context"]
482+
} as gptscript.ToolDef
483+
const contextTool = {
484+
name: "my-context",
485+
instructions: `${shebang}\nexit \${EXIT_CODE}`
486+
} as gptscript.ToolDef
487+
488+
let run = await client.evaluate([t, contextTool], {disableCache: true, env: ["EXIT_CODE=1"]})
489+
try {
490+
await run.text()
491+
} catch {
492+
}
493+
494+
expect(run.err).not.toEqual("")
495+
496+
run.opts.env = []
497+
run = run.nextChat()
498+
499+
await run.text()
500+
501+
expect(run.err).toEqual("")
502+
})
473503
})

0 commit comments

Comments
 (0)