Skip to content

Commit 54191d3

Browse files
committed
fix: allow retry of failed runs
1 parent 0c8c0f1 commit 54191d3

File tree

3 files changed

+37
-9
lines changed

3 files changed

+37
-9
lines changed

Diff for: 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() {

Diff for: 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 {
@@ -238,25 +239,25 @@ export class Run {
238239
}
239240

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

245246
let run = this
246247
if (run.state !== RunState.Creating) {
247248
run = new (this.constructor as any)(this.requestPath, this.filePath, this.content, this.opts, this.gptscriptURL)
248249
}
249250

250-
if (this.chatState) {
251-
run.chatState = this.chatState
252-
} else if (this.opts.chatState) {
253-
run.chatState = this.opts.chatState
251+
if (this.chatState && this.state === RunState.Continue) {
252+
// Only update the chat state if the previous run didn't error.
253+
// The chat state on opts will be the chat state for the last successful run.
254+
this.opts.chatState = this.chatState
254255
}
255256
run.opts.input = input
256257
if (run.content !== "") {
257-
run.request({content: this.content, chatState: run.chatState})
258+
run.request({content: this.content, ...this.opts})
258259
} else {
259-
run.request({file: this.filePath, chatState: run.chatState})
260+
run.request({file: this.filePath, ...this.opts})
260261
}
261262

262263
return run

Diff for: tests/gptscript.test.ts

+26
Original file line numberDiff line numberDiff line change
@@ -470,4 +470,30 @@ describe("gptscript module", () => {
470470
expect(run.err).toContain("prompt occurred")
471471
expect(promptFound).toBeFalsy()
472472
})
473+
474+
test("retry failed run", async () => {
475+
const t = {
476+
instructions: "say hello",
477+
context: ["my-context"]
478+
} as gptscript.ToolDef
479+
const contextTool = {
480+
name: "my-context",
481+
instructions: "#!/usr/bin/env python3\n\nimport os, sys\n\nsys.exit(int(os.environ['EXIT_CODE']))"
482+
} as gptscript.ToolDef
483+
484+
let run = await client.evaluate([t, contextTool], {env: ["EXIT_CODE=1"]})
485+
try {
486+
await run.text()
487+
} catch {
488+
}
489+
490+
expect(run.err).not.toEqual("")
491+
492+
run.opts.env = ["EXIT_CODE=0"]
493+
run = run.nextChat()
494+
495+
await run.text()
496+
497+
expect(run.err).toEqual("")
498+
})
473499
})

0 commit comments

Comments
 (0)