From 97480b2ebd8160bb9cd33a4546db42ffdd3fce94 Mon Sep 17 00:00:00 2001 From: Donnie Adams Date: Fri, 16 Aug 2024 18:02:28 -0400 Subject: [PATCH 1/9] chore: update GitHub actions for upcoming changes Signed-off-by: Donnie Adams --- .github/workflows/run_tests.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/run_tests.yaml b/.github/workflows/run_tests.yaml index dfd7770..9847bcb 100644 --- a/.github/workflows/run_tests.yaml +++ b/.github/workflows/run_tests.yaml @@ -47,15 +47,12 @@ jobs: - name: Install gptscript run: | curl https://get.gptscript.ai/releases/default_windows_amd64_v1/gptscript.exe -o gptscript.exe - - name: Create config file - run: | - echo '{"credsStore":"file"}' > config - name: Install dependencies run: npm install - name: Run Tests env: GPTSCRIPT_BIN: .\gptscript.exe - GPTSCRIPT_CONFIG_FILE: .\config OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} NODE_GPTSCRIPT_SKIP_INSTALL_BINARY: true run: npm test From 923de60fd6e0291f04cee8f6c4854a13eb47a88b Mon Sep 17 00:00:00 2001 From: Donnie Adams Date: Fri, 16 Aug 2024 18:06:34 -0400 Subject: [PATCH 2/9] feat: add ability to list models from other providers Signed-off-by: Donnie Adams --- src/gptscript.ts | 53 +++++++++++++++++++++++++++-------------- tests/gptscript.test.ts | 38 +++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 18 deletions(-) diff --git a/src/gptscript.ts b/src/gptscript.ts index 393752c..14a8ecb 100644 --- a/src/gptscript.ts +++ b/src/gptscript.ts @@ -73,8 +73,10 @@ export class GPTScript { private ready: boolean + private opts: GlobalOpts constructor(opts?: GlobalOpts) { + this.opts = opts || {} this.ready = false GPTScript.instanceCount++ if (!GPTScript.serverURL) { @@ -82,9 +84,9 @@ export class GPTScript { } if (GPTScript.instanceCount === 1 && process.env.GPTSCRIPT_DISABLE_SERVER !== "true") { let env = process.env - if (opts && opts.Env) { + if (this.opts.Env) { env = {} - for (const v of opts.Env) { + for (const v of this.opts.Env) { const equalIndex = v.indexOf("=") if (equalIndex === -1) { env[v] = "" @@ -94,7 +96,7 @@ export class GPTScript { } } - globalOptsToEnv(env, opts) + globalOptsToEnv(env, this.opts) process.on("exit", (code) => { if (GPTScript.serverProcess) { GPTScript.serverProcess.stdin?.end() @@ -133,20 +135,30 @@ export class GPTScript { return this.runBasicCommand("list-tools") } - listModels(): Promise { - return this.runBasicCommand("list-models") + listModels(providers?: string[], credentialOverrides?: string[]): Promise { + if (this.opts.DefaultModelProvider) { + if (!providers) { + providers = [] + } + providers.push(this.opts.DefaultModelProvider) + } + return this.runBasicCommand("list-models", { + "providers": providers, + "env": this.opts.Env, + "credentialOverrides": credentialOverrides + }) } version(): Promise { return this.runBasicCommand("version") } - async runBasicCommand(cmd: string): Promise { + async runBasicCommand(cmd: string, body?: any): Promise { if (!this.ready) { this.ready = await this.testGPTScriptURL(20) } const r = new RunSubcommand(cmd, "", {}, GPTScript.serverURL) - r.requestNoStream(null) + r.requestNoStream(body) return r.text() } @@ -161,7 +173,8 @@ export class GPTScript { if (!this.ready) { this.ready = await this.testGPTScriptURL(20) } - return (new Run("run", toolName, opts, GPTScript.serverURL)).nextChat(opts.input) + + return (new Run("run", toolName, {...this.opts, ...opts}, GPTScript.serverURL)).nextChat(opts.input) } /** @@ -176,7 +189,7 @@ export class GPTScript { this.ready = await this.testGPTScriptURL(20) } - return (new Run("evaluate", tool, opts, GPTScript.serverURL)).nextChat(opts.input) + return (new Run("evaluate", tool, {...this.opts, ...opts}, GPTScript.serverURL)).nextChat(opts.input) } async parse(fileName: string, disableCache?: boolean): Promise { @@ -265,7 +278,7 @@ export class GPTScript { disableCache?: boolean, subTool?: string ): Promise { - return this._load({ file: fileName, disableCache, subTool }); + return this._load({file: fileName, disableCache, subTool}) } /** @@ -281,7 +294,7 @@ export class GPTScript { disableCache?: boolean, subTool?: string ): Promise { - return this._load({ content, disableCache, subTool }); + return this._load({content, disableCache, subTool}) } /** @@ -297,7 +310,7 @@ export class GPTScript { disableCache?: boolean, subTool?: string ): Promise { - return this._load({ toolDefs, disableCache, subTool }); + return this._load({toolDefs, disableCache, subTool}) } /** @@ -308,12 +321,12 @@ export class GPTScript { */ private async _load(payload: any): Promise { if (!this.ready) { - this.ready = await this.testGPTScriptURL(20); + this.ready = await this.testGPTScriptURL(20) } - const r: Run = new RunSubcommand("load", payload.toolDefs || [], {}, GPTScript.serverURL); + const r: Run = new RunSubcommand("load", payload.toolDefs || [], {}, GPTScript.serverURL) - r.request(payload); - return (await r.json()) as LoadResponse; + r.request(payload) + return (await r.json()) as LoadResponse } private async testGPTScriptURL(count: number): Promise { @@ -511,12 +524,16 @@ export class Run { const options = this.requestOptions(this.gptscriptURL, this.requestPath, tool) as any if (tool) { - options.body = {...tool, ...this.opts} + options.body = JSON.stringify({...tool, ...this.opts}) } const req = new Request(this.gptscriptURL + "/" + this.requestPath, options) this.promise = new Promise(async (resolve, reject) => { - fetch(req).then(resp => resp.json()).then(res => resolve(res.stdout)).catch(e => { + fetch(req).then(resp => { + return resp.json() + }).then(res => { + resolve(res.stdout) + }).catch(e => { reject(e) }) }) diff --git a/tests/gptscript.test.ts b/tests/gptscript.test.ts index cdac726..a267c10 100644 --- a/tests/gptscript.test.ts +++ b/tests/gptscript.test.ts @@ -3,6 +3,7 @@ import {ArgumentSchemaType, getEnv, PropertyType, RunEventType, ToolType} from " import path from "path" import {fileURLToPath} from "url" +let gFirst: gptscript.GPTScript let g: gptscript.GPTScript const __dirname = path.dirname(fileURLToPath(import.meta.url)) @@ -12,9 +13,13 @@ describe("gptscript module", () => { throw new Error("neither OPENAI_API_KEY nor GPTSCRIPT_URL is set") } + // Start an initial GPTScript instance. + // This one doesn't have any options, but it's there to ensure that using another instance works as expected in all cases. + gFirst = new gptscript.GPTScript() g = new gptscript.GPTScript({APIKey: process.env.OPENAI_API_KEY}) }) afterAll(() => { + gFirst.close() g.close() }) @@ -35,6 +40,39 @@ describe("gptscript module", () => { expect(models).toBeDefined() }) + test("listModels with providers returns a list of models from that provider", async () => { + if (!process.env.ANTHROPIC_API_KEY) { + return + } + + let models = await g.listModels(["github.com/gptscript-ai/claude3-anthropic-provider"], ["github.com/gptscript-ai/claude3-anthropic-provider/credential:ANTHROPIC_API_KEY"]) + expect(models).toBeDefined() + for (let model of models.split("\n")) { + expect(model).toBeDefined() + expect(model.startsWith("claude-3-")).toBe(true) + expect(model.endsWith("from github.com/gptscript-ai/claude3-anthropic-provider")).toBe(true) + } + }) + + test("listModels with default provider returns a list of models from that provider", async () => { + if (!process.env.ANTHROPIC_API_KEY) { + return + } + + const newg = new gptscript.GPTScript({DefaultModelProvider: "github.com/gptscript-ai/claude3-anthropic-provider"}) + try { + let models = await newg.listModels(undefined, ["github.com/gptscript-ai/claude3-anthropic-provider/credential:ANTHROPIC_API_KEY"]) + expect(models).toBeDefined() + for (let model of models.split("\n")) { + expect(model).toBeDefined() + expect(model.startsWith("claude-3-")).toBe(true) + expect(model.endsWith("from github.com/gptscript-ai/claude3-anthropic-provider")).toBe(true) + } + } finally { + newg.close() + } + }) + test("version returns a gptscript version", async () => { // Similar structure to listTools let version = await g.version() From f69a760b0f91cf3d5f3ed19ad9e4237b88555be4 Mon Sep 17 00:00:00 2001 From: Donnie Adams Date: Fri, 16 Aug 2024 18:39:46 -0400 Subject: [PATCH 3/9] chore: pass anthropic key secret to test action Signed-off-by: Donnie Adams --- .github/workflows/pull_request.yaml | 1 + .github/workflows/push_main.yaml | 1 + .github/workflows/run_tests.yaml | 2 ++ 3 files changed, 4 insertions(+) diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml index e4b61eb..6ec42cc 100644 --- a/.github/workflows/pull_request.yaml +++ b/.github/workflows/pull_request.yaml @@ -38,3 +38,4 @@ jobs: git_ref: ${{ github.event.pull_request.head.sha }} secrets: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} diff --git a/.github/workflows/push_main.yaml b/.github/workflows/push_main.yaml index c7db5c9..8e7b2cb 100644 --- a/.github/workflows/push_main.yaml +++ b/.github/workflows/push_main.yaml @@ -13,3 +13,4 @@ jobs: git_ref: '' secrets: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} diff --git a/.github/workflows/run_tests.yaml b/.github/workflows/run_tests.yaml index 9847bcb..daba21e 100644 --- a/.github/workflows/run_tests.yaml +++ b/.github/workflows/run_tests.yaml @@ -9,6 +9,8 @@ on: secrets: OPENAI_API_KEY: required: true + ANTHROPIC_API_KEY: + required: true jobs: test-linux: From 99836de89dfbc15641f0b671f9061d7f50170f81 Mon Sep 17 00:00:00 2001 From: Donnie Adams Date: Fri, 16 Aug 2024 18:45:01 -0400 Subject: [PATCH 4/9] chore: add anthropic key to linux tests Signed-off-by: Donnie Adams --- .github/workflows/run_tests.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/run_tests.yaml b/.github/workflows/run_tests.yaml index daba21e..64f3a71 100644 --- a/.github/workflows/run_tests.yaml +++ b/.github/workflows/run_tests.yaml @@ -33,6 +33,7 @@ jobs: env: GPTSCRIPT_BIN: ./gptscriptexe OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} NODE_GPTSCRIPT_SKIP_INSTALL_BINARY: true run: npm test From 30f55939c83c088c2e37488affeb7d716d04faa3 Mon Sep 17 00:00:00 2001 From: Donnie Adams Date: Fri, 16 Aug 2024 18:47:34 -0400 Subject: [PATCH 5/9] chore: bump timeout for models tests that need to launch provider Signed-off-by: Donnie Adams --- tests/gptscript.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/gptscript.test.ts b/tests/gptscript.test.ts index a267c10..519457f 100644 --- a/tests/gptscript.test.ts +++ b/tests/gptscript.test.ts @@ -52,7 +52,7 @@ describe("gptscript module", () => { expect(model.startsWith("claude-3-")).toBe(true) expect(model.endsWith("from github.com/gptscript-ai/claude3-anthropic-provider")).toBe(true) } - }) + }, 15000) test("listModels with default provider returns a list of models from that provider", async () => { if (!process.env.ANTHROPIC_API_KEY) { @@ -71,7 +71,7 @@ describe("gptscript module", () => { } finally { newg.close() } - }) + }, 15000) test("version returns a gptscript version", async () => { // Similar structure to listTools From b0796da475f118f1484de9d5019caeacace1a77f Mon Sep 17 00:00:00 2001 From: Donnie Adams Date: Fri, 16 Aug 2024 21:08:57 -0400 Subject: [PATCH 6/9] chore: bump list models timeout to allow for provider launch Signed-off-by: Donnie Adams --- tests/gptscript.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/gptscript.test.ts b/tests/gptscript.test.ts index 519457f..c63a7c2 100644 --- a/tests/gptscript.test.ts +++ b/tests/gptscript.test.ts @@ -52,7 +52,7 @@ describe("gptscript module", () => { expect(model.startsWith("claude-3-")).toBe(true) expect(model.endsWith("from github.com/gptscript-ai/claude3-anthropic-provider")).toBe(true) } - }, 15000) + }, 60000) test("listModels with default provider returns a list of models from that provider", async () => { if (!process.env.ANTHROPIC_API_KEY) { From 65b8d83e0f4a9c6d137b437b4d461e1acf8b7b6e Mon Sep 17 00:00:00 2001 From: Donnie Adams Date: Tue, 20 Aug 2024 09:47:44 -0400 Subject: [PATCH 7/9] feat: add prompt metadata field Signed-off-by: Donnie Adams --- src/gptscript.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gptscript.ts b/src/gptscript.ts index 14a8ecb..c47e56a 100644 --- a/src/gptscript.ts +++ b/src/gptscript.ts @@ -878,6 +878,7 @@ export interface PromptFrame { message: string fields: string[] sensitive: boolean + metadata: Record } export type Frame = RunFrame | CallFrame | PromptFrame From de914911013bf9da02046906b88a5613dce508e1 Mon Sep 17 00:00:00 2001 From: Donnie Adams Date: Tue, 20 Aug 2024 12:18:01 -0400 Subject: [PATCH 8/9] chore: add test for prompt with metadata Signed-off-by: Donnie Adams --- tests/gptscript.test.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/gptscript.test.ts b/tests/gptscript.test.ts index c63a7c2..1352840 100644 --- a/tests/gptscript.test.ts +++ b/tests/gptscript.test.ts @@ -545,6 +545,27 @@ describe("gptscript module", () => { expect(promptFound).toBeTruthy() }) + test("prompt with metadata", async () => { + let promptFound = false + const run = await g.run("sys.prompt", { + prompt: true, + input: "{\"fields\":\"first name\",\"metadata\":{\"key\":\"value\"}}" + }) + run.on(gptscript.RunEventType.Prompt, async (data: gptscript.PromptFrame) => { + expect(data.fields.length).toEqual(1) + expect(data.fields[0]).toEqual("first name") + expect(data.metadata).toEqual({key: "value"}) + expect(data.sensitive).toBeFalsy() + + promptFound = true + await g.promptResponse({id: data.id, responses: {[data.fields[0]]: "Clicky"}}) + }) + + expect(await run.text()).toContain("Clicky") + expect(run.err).toEqual("") + expect(promptFound).toBeTruthy() + }) + test("prompt without prompt allowed should fail", async () => { let promptFound = false const t = { From cc958546001f2cb22cc3d7dcf078b02d62189762 Mon Sep 17 00:00:00 2001 From: acorn-io-bot Date: Wed, 21 Aug 2024 17:39:16 +0000 Subject: [PATCH 9/9] Automated GPTScript Version Update --- package-lock.json | 4 ++-- package.json | 2 +- scripts/install-binary.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 45674ae..af8c116 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@gptscript-ai/gptscript", - "version": "v0.9.5-rc3", + "version": "v0.9.5-rc4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@gptscript-ai/gptscript", - "version": "v0.9.5-rc3", + "version": "v0.9.5-rc4", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 5e7e2cb..300cf69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@gptscript-ai/gptscript", - "version": "v0.9.5-rc3", + "version": "v0.9.5-rc4", "description": "Run gptscript in node.js", "source": "src/gptscript.ts", "main": "dist/gptscript.js", diff --git a/scripts/install-binary.js b/scripts/install-binary.js index 3988e9e..9e04cfd 100644 --- a/scripts/install-binary.js +++ b/scripts/install-binary.js @@ -72,7 +72,7 @@ if (process.platform === 'win32') { const gptscript_info = { name: "gptscript", url: "https://github.com/gptscript-ai/gptscript/releases/download/", - version: "v0.9.5-rc3" + version: "v0.9.5-rc4" } const pltfm = {