Skip to content

Commit 79a84d1

Browse files
committed
feat: add workspace API
Signed-off-by: Donnie Adams <[email protected]>
1 parent 96d3724 commit 79a84d1

File tree

2 files changed

+211
-14
lines changed

2 files changed

+211
-14
lines changed

src/gptscript.ts

+89-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface GlobalOpts {
1313
DefaultModel?: string
1414
DefaultModelProvider?: string
1515
DatasetToolRepo?: string
16+
WorkspaceTool?: string
1617
Env?: string[]
1718
}
1819

@@ -140,9 +141,12 @@ export class GPTScript {
140141
if (!this.opts.URL) {
141142
this.opts.URL = GPTScript.serverURL
142143
}
144+
if (this.opts.URL !== "" && !this.opts.URL.startsWith("http://") && !this.opts.URL.startsWith("https://")) {
145+
this.opts.URL = "http://" + this.opts.URL
146+
}
143147

144148
if (!this.opts.Env) {
145-
this.opts.Env = []
149+
this.opts.Env = Object.entries(process.env).map(([k, v]) => `${k}=${v}`)
146150
}
147151
if (this.opts.URL) {
148152
this.opts.Env.push(`GPTSCRIPT_URL=${this.opts.URL}`)
@@ -469,6 +473,90 @@ export class GPTScript {
469473
return JSON.parse(result) as DatasetElement
470474
}
471475

476+
async createWorkspace(providerType: string, ...fromWorkspaces: string[]): Promise<string> {
477+
const out = await this.runBasicCommand("workspaces/create", {
478+
providerType: providerType,
479+
fromWorkspaceIDs: fromWorkspaces,
480+
workspaceTool: this.opts.WorkspaceTool,
481+
env: this.opts.Env,
482+
})
483+
return out.trim()
484+
}
485+
486+
async deleteWorkspace(workspaceID?: string): Promise<void> {
487+
if (!workspaceID) {
488+
workspaceID = process.env.GPTSCRIPT_WORKSPACE_ID ?? ""
489+
}
490+
await this.runBasicCommand("workspaces/delete", {
491+
id: workspaceID,
492+
workspaceTool: this.opts.WorkspaceTool,
493+
env: this.opts.Env,
494+
})
495+
}
496+
497+
async listFilesInWorkspace(prefix?: string, workspaceID?: string): Promise<Array<string>> {
498+
if (!workspaceID) {
499+
workspaceID = process.env.GPTSCRIPT_WORKSPACE_ID ?? ""
500+
}
501+
const out = await this.runBasicCommand("workspaces/list", {
502+
id: workspaceID,
503+
prefix: prefix,
504+
workspaceTool: this.opts.WorkspaceTool,
505+
env: this.opts.Env,
506+
})
507+
return JSON.parse(out)
508+
}
509+
510+
async removeAll(withPrefix?: string, workspaceID?: string): Promise<void> {
511+
if (!workspaceID) {
512+
workspaceID = process.env.GPTSCRIPT_WORKSPACE_ID ?? ""
513+
}
514+
await this.runBasicCommand("workspaces/remove-all-with-prefix", {
515+
id: workspaceID,
516+
prefix: withPrefix,
517+
workspaceTool: this.opts.WorkspaceTool,
518+
env: this.opts.Env,
519+
})
520+
}
521+
522+
async writeFileInWorkspace(filePath: string, content: ArrayBuffer, workspaceID?: string): Promise<void> {
523+
if (!workspaceID) {
524+
workspaceID = process.env.GPTSCRIPT_WORKSPACE_ID ?? ""
525+
}
526+
await this.runBasicCommand("workspaces/write-file", {
527+
id: workspaceID,
528+
filePath: filePath,
529+
contents: Buffer.from(content).toString("base64"),
530+
workspaceTool: this.opts.WorkspaceTool,
531+
env: this.opts.Env,
532+
})
533+
}
534+
535+
async deleteFileInWorkspace(filePath: string, workspaceID?: string): Promise<void> {
536+
if (!workspaceID) {
537+
workspaceID = process.env.GPTSCRIPT_WORKSPACE_ID ?? ""
538+
}
539+
await this.runBasicCommand("workspaces/delete-file", {
540+
id: workspaceID,
541+
filePath: filePath,
542+
workspaceTool: this.opts.WorkspaceTool,
543+
env: this.opts.Env,
544+
})
545+
}
546+
547+
async readFileInWorkspace(filePath: string, workspaceID?: string): Promise<ArrayBuffer> {
548+
if (!workspaceID) {
549+
workspaceID = process.env.GPTSCRIPT_WORKSPACE_ID ?? ""
550+
}
551+
const out = await this.runBasicCommand("workspaces/read-file", {
552+
id: workspaceID,
553+
filePath: filePath,
554+
workspaceTool: this.opts.WorkspaceTool,
555+
env: this.opts.Env,
556+
})
557+
return Buffer.from(out.trim(), "base64")
558+
}
559+
472560
/**
473561
* Helper method to handle the common logic for loading.
474562
*

tests/gptscript.test.ts

+122-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as gptscript from "../src/gptscript"
22
import {
33
ArgumentSchemaType,
4-
CredentialType, Dataset,
4+
CredentialType,
55
getEnv,
66
PropertyType,
77
RunEventType,
@@ -13,7 +13,7 @@ import path from "path"
1313
import {fileURLToPath} from "url"
1414
import * as fs from "node:fs"
1515
import {randomBytes} from "node:crypto"
16-
import {tmpdir} from "node:os";
16+
import {tmpdir} from "node:os"
1717

1818
let gFirst: gptscript.GPTScript
1919
let g: gptscript.GPTScript
@@ -908,21 +908,21 @@ describe("gptscript module", () => {
908908
// Add elements
909909
try {
910910
const e1 = await g.addDatasetElement(
911-
workspace,
912-
datasetID,
913-
"element1",
914-
"",
915-
"this is element 1 contents"
911+
workspace,
912+
datasetID,
913+
"element1",
914+
"",
915+
"this is element 1 contents"
916916
)
917917
expect(e1.name).toEqual("element1")
918918
expect(e1.description).toEqual("")
919919

920920
const e2 = await g.addDatasetElement(
921-
workspace,
922-
datasetID,
923-
"element2",
924-
"a description",
925-
"this is element 2 contents"
921+
workspace,
922+
datasetID,
923+
"element2",
924+
"a description",
925+
"this is element 2 contents"
926926
)
927927
expect(e2.name).toEqual("element2")
928928
expect(e2.description).toEqual("a description")
@@ -963,5 +963,114 @@ describe("gptscript module", () => {
963963
} catch (e) {
964964
throw new Error("failed to list datasets: " + e)
965965
}
966-
}, 20000)
966+
}, 60000)
967+
968+
test("create and delete workspace", async () => {
969+
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
970+
console.log("AWS credentials not set, skipping test")
971+
return
972+
}
973+
974+
const workspaceID = await g.createWorkspace("directory")
975+
expect(workspaceID).toBeDefined()
976+
await g.deleteWorkspace(workspaceID)
977+
}, 60000)
978+
979+
test("write, read, and delete file", async () => {
980+
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
981+
console.log("AWS credentials not set, skipping test")
982+
return
983+
}
984+
985+
const workspaceID = await g.createWorkspace("directory")
986+
expect(workspaceID).toBeDefined()
987+
988+
await g.writeFileInWorkspace("test.txt", Buffer.from("test"), workspaceID)
989+
const content = await g.readFileInWorkspace("test.txt", workspaceID)
990+
expect(content.toString()).toEqual("test")
991+
await g.deleteWorkspace(workspaceID)
992+
}, 60000)
993+
994+
test("test complex ls", async () => {
995+
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
996+
console.log("AWS credentials not set, skipping test")
997+
return
998+
}
999+
1000+
const workspaceID = await g.createWorkspace("directory")
1001+
1002+
// Write files in the workspace
1003+
await g.writeFileInWorkspace("test/test1.txt", Buffer.from("hello1"), workspaceID)
1004+
await g.writeFileInWorkspace("test1/test2.txt", Buffer.from("hello2"), workspaceID)
1005+
await g.writeFileInWorkspace("test1/test3.txt", Buffer.from("hello3"), workspaceID)
1006+
await g.writeFileInWorkspace(".hidden.txt", Buffer.from("hidden"), workspaceID)
1007+
1008+
let content = await g.listFilesInWorkspace(undefined, workspaceID)
1009+
expect(content.length).toEqual(4)
1010+
expect(content).toContain("test1/test2.txt")
1011+
expect(content).toContain("test1/test3.txt")
1012+
expect(content).toContain("test/test1.txt")
1013+
expect(content).toContain(".hidden.txt")
1014+
1015+
content = await g.listFilesInWorkspace("test1", workspaceID)
1016+
expect(content.length).toEqual(2)
1017+
expect(content).toContain("test1/test2.txt")
1018+
expect(content).toContain("test1/test3.txt")
1019+
1020+
await g.removeAll("test1", workspaceID)
1021+
1022+
content = await g.listFilesInWorkspace("", workspaceID)
1023+
expect(content.length).toEqual(2)
1024+
expect(content).toContain("test/test1.txt")
1025+
expect(content).toContain(".hidden.txt")
1026+
1027+
await g.deleteWorkspace(workspaceID)
1028+
}, 60000)
1029+
1030+
test("create and delete workspace in s3", async () => {
1031+
const workspaceID = await g.createWorkspace("s3")
1032+
expect(workspaceID).toBeDefined()
1033+
await g.deleteWorkspace(workspaceID)
1034+
}, 60000)
1035+
1036+
test("write, read, and delete file in s3", async () => {
1037+
const workspaceID = await g.createWorkspace("s3")
1038+
expect(workspaceID).toBeDefined()
1039+
1040+
await g.writeFileInWorkspace("test.txt", Buffer.from("test"), workspaceID)
1041+
const content = await g.readFileInWorkspace("test.txt", workspaceID)
1042+
expect(content.toString()).toEqual("test")
1043+
await g.deleteWorkspace(workspaceID)
1044+
}, 60000)
1045+
1046+
test("test complex ls in s3", async () => {
1047+
const workspaceID = await g.createWorkspace("s3")
1048+
1049+
// Write files in the workspace
1050+
await g.writeFileInWorkspace("test/test1.txt", Buffer.from("hello1"), workspaceID)
1051+
await g.writeFileInWorkspace("test1/test2.txt", Buffer.from("hello2"), workspaceID)
1052+
await g.writeFileInWorkspace("test1/test3.txt", Buffer.from("hello3"), workspaceID)
1053+
await g.writeFileInWorkspace(".hidden.txt", Buffer.from("hidden"), workspaceID)
1054+
1055+
let content = await g.listFilesInWorkspace(undefined, workspaceID)
1056+
expect(content.length).toEqual(4)
1057+
expect(content).toContain("test1/test2.txt")
1058+
expect(content).toContain("test1/test3.txt")
1059+
expect(content).toContain("test/test1.txt")
1060+
expect(content).toContain(".hidden.txt")
1061+
1062+
content = await g.listFilesInWorkspace("test1", workspaceID)
1063+
expect(content.length).toEqual(2)
1064+
expect(content).toContain("test1/test2.txt")
1065+
expect(content).toContain("test1/test3.txt")
1066+
1067+
await g.removeAll("test1", workspaceID)
1068+
1069+
content = await g.listFilesInWorkspace("", workspaceID)
1070+
expect(content.length).toEqual(2)
1071+
expect(content).toContain("test/test1.txt")
1072+
expect(content).toContain(".hidden.txt")
1073+
1074+
await g.deleteWorkspace(workspaceID)
1075+
}, 60000)
9671076
})

0 commit comments

Comments
 (0)