Skip to content

Commit

Permalink
Merge pull request #82 from thedadams/list-models-from-providers
Browse files Browse the repository at this point in the history
feat: add ability to list models from other providers
  • Loading branch information
thedadams authored Aug 16, 2024
2 parents 97480b2 + 923de60 commit f50289f
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 18 deletions.
53 changes: 35 additions & 18 deletions src/gptscript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,20 @@ export class GPTScript {


private ready: boolean
private opts: GlobalOpts

constructor(opts?: GlobalOpts) {
this.opts = opts || {}
this.ready = false
GPTScript.instanceCount++
if (!GPTScript.serverURL) {
GPTScript.serverURL = "http://" + (process.env.GPTSCRIPT_URL || "127.0.0.1:0")
}
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] = ""
Expand All @@ -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()
Expand Down Expand Up @@ -133,20 +135,30 @@ export class GPTScript {
return this.runBasicCommand("list-tools")
}

listModels(): Promise<string> {
return this.runBasicCommand("list-models")
listModels(providers?: string[], credentialOverrides?: string[]): Promise<string> {
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<string> {
return this.runBasicCommand("version")
}

async runBasicCommand(cmd: string): Promise<string> {
async runBasicCommand(cmd: string, body?: any): Promise<string> {
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()
}

Expand All @@ -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)
}

/**
Expand All @@ -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<Block[]> {
Expand Down Expand Up @@ -265,7 +278,7 @@ export class GPTScript {
disableCache?: boolean,
subTool?: string
): Promise<LoadResponse> {
return this._load({ file: fileName, disableCache, subTool });
return this._load({file: fileName, disableCache, subTool})
}

/**
Expand All @@ -281,7 +294,7 @@ export class GPTScript {
disableCache?: boolean,
subTool?: string
): Promise<LoadResponse> {
return this._load({ content, disableCache, subTool });
return this._load({content, disableCache, subTool})
}

/**
Expand All @@ -297,7 +310,7 @@ export class GPTScript {
disableCache?: boolean,
subTool?: string
): Promise<LoadResponse> {
return this._load({ toolDefs, disableCache, subTool });
return this._load({toolDefs, disableCache, subTool})
}

/**
Expand All @@ -308,12 +321,12 @@ export class GPTScript {
*/
private async _load(payload: any): Promise<LoadResponse> {
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<boolean> {
Expand Down Expand Up @@ -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<string>(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)
})
})
Expand Down
38 changes: 38 additions & 0 deletions tests/gptscript.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand All @@ -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()
})

Expand All @@ -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()
Expand Down

0 comments on commit f50289f

Please sign in to comment.