Skip to content

Commit 8faaae3

Browse files
authored
Merge pull request #55 from thedadams/add-load
feat: add load API
2 parents ef58327 + e0876d7 commit 8faaae3

File tree

2 files changed

+166
-7
lines changed

2 files changed

+166
-7
lines changed

gptscript.go

+49-2
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,8 @@ func (g *GPTScript) Parse(ctx context.Context, fileName string, opts ...ParseOpt
181181
return doc.Nodes, nil
182182
}
183183

184-
// ParseTool will parse the given string into a tool.
185-
func (g *GPTScript) ParseTool(ctx context.Context, toolDef string) ([]Node, error) {
184+
// ParseContent will parse the given string into a tool.
185+
func (g *GPTScript) ParseContent(ctx context.Context, toolDef string) ([]Node, error) {
186186
out, err := g.runBasicCommand(ctx, "parse", map[string]any{"content": toolDef})
187187
if err != nil {
188188
return nil, err
@@ -214,6 +214,53 @@ func (g *GPTScript) Fmt(ctx context.Context, nodes []Node) (string, error) {
214214
return out, nil
215215
}
216216

217+
type LoadOptions struct {
218+
DisableCache bool
219+
SubTool string
220+
}
221+
222+
// LoadFile will load the given file into a Program.
223+
func (g *GPTScript) LoadFile(ctx context.Context, fileName string, opts ...LoadOptions) (*Program, error) {
224+
return g.load(ctx, map[string]any{"file": fileName}, opts...)
225+
}
226+
227+
// LoadContent will load the given content into a Program.
228+
func (g *GPTScript) LoadContent(ctx context.Context, content string, opts ...LoadOptions) (*Program, error) {
229+
return g.load(ctx, map[string]any{"content": content}, opts...)
230+
}
231+
232+
// LoadTools will load the given tools into a Program.
233+
func (g *GPTScript) LoadTools(ctx context.Context, toolDefs []ToolDef, opts ...LoadOptions) (*Program, error) {
234+
return g.load(ctx, map[string]any{"toolDefs": toolDefs}, opts...)
235+
}
236+
237+
func (g *GPTScript) load(ctx context.Context, payload map[string]any, opts ...LoadOptions) (*Program, error) {
238+
for _, opt := range opts {
239+
if opt.DisableCache {
240+
payload["disableCache"] = true
241+
}
242+
if opt.SubTool != "" {
243+
payload["subTool"] = opt.SubTool
244+
}
245+
}
246+
247+
out, err := g.runBasicCommand(ctx, "load", payload)
248+
if err != nil {
249+
return nil, err
250+
}
251+
252+
type loadResponse struct {
253+
Program *Program `json:"program"`
254+
}
255+
256+
prg := new(loadResponse)
257+
if err = json.Unmarshal([]byte(out), prg); err != nil {
258+
return nil, err
259+
}
260+
261+
return prg.Program, nil
262+
}
263+
217264
// Version will return the output of `gptscript --version`
218265
func (g *GPTScript) Version(ctx context.Context) (string, error) {
219266
out, err := g.runBasicCommand(ctx, "version", nil)

gptscript_test.go

+117-5
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ func TestParseFileWithMetadata(t *testing.T) {
498498
}
499499

500500
func TestParseTool(t *testing.T) {
501-
tools, err := g.ParseTool(context.Background(), "echo hello")
501+
tools, err := g.ParseContent(context.Background(), "echo hello")
502502
if err != nil {
503503
t.Errorf("Error parsing tool: %v", err)
504504
}
@@ -517,7 +517,7 @@ func TestParseTool(t *testing.T) {
517517
}
518518

519519
func TestEmptyParseTool(t *testing.T) {
520-
tools, err := g.ParseTool(context.Background(), "")
520+
tools, err := g.ParseContent(context.Background(), "")
521521
if err != nil {
522522
t.Errorf("Error parsing tool: %v", err)
523523
}
@@ -528,7 +528,7 @@ func TestEmptyParseTool(t *testing.T) {
528528
}
529529

530530
func TestParseToolWithTextNode(t *testing.T) {
531-
tools, err := g.ParseTool(context.Background(), "echo hello\n---\n!markdown\nhello")
531+
tools, err := g.ParseContent(context.Background(), "echo hello\n---\n!markdown\nhello")
532532
if err != nil {
533533
t.Errorf("Error parsing tool: %v", err)
534534
}
@@ -735,8 +735,8 @@ func TestFileChat(t *testing.T) {
735735
}
736736
inputs := []string{
737737
"List the 3 largest of the Great Lakes by volume.",
738-
"What is the volume of the second in the list in cubic miles?",
739-
"What is the total area of the third in the list in square miles?",
738+
"For the second one in the list: what is the volume cubic miles?",
739+
"For the third one in the list: what is the total area in square miles?",
740740
}
741741

742742
expectedOutputs := []string{
@@ -1220,3 +1220,115 @@ func TestParseThenEvaluateWithMetadata(t *testing.T) {
12201220
t.Errorf("Unexpected output: %s", out)
12211221
}
12221222
}
1223+
1224+
func TestLoadFile(t *testing.T) {
1225+
wd, err := os.Getwd()
1226+
if err != nil {
1227+
t.Fatalf("Error getting working directory: %v", err)
1228+
}
1229+
1230+
prg, err := g.LoadFile(context.Background(), wd+"/test/global-tools.gpt")
1231+
if err != nil {
1232+
t.Fatalf("Error loading file: %v", err)
1233+
}
1234+
1235+
if prg.EntryToolID == "" {
1236+
t.Errorf("Unexpected entry tool ID: %s", prg.EntryToolID)
1237+
}
1238+
1239+
if len(prg.ToolSet) == 0 {
1240+
t.Errorf("Unexpected number of tools: %d", len(prg.ToolSet))
1241+
}
1242+
1243+
if prg.Name == "" {
1244+
t.Errorf("Unexpected name: %s", prg.Name)
1245+
}
1246+
}
1247+
1248+
func TestLoadRemoteFile(t *testing.T) {
1249+
prg, err := g.LoadFile(context.Background(), "github.com/gptscript-ai/context/workspace")
1250+
if err != nil {
1251+
t.Fatalf("Error loading file: %v", err)
1252+
}
1253+
1254+
if prg.EntryToolID == "" {
1255+
t.Errorf("Unexpected entry tool ID: %s", prg.EntryToolID)
1256+
}
1257+
1258+
if len(prg.ToolSet) == 0 {
1259+
t.Errorf("Unexpected number of tools: %d", len(prg.ToolSet))
1260+
}
1261+
1262+
if prg.Name == "" {
1263+
t.Errorf("Unexpected name: %s", prg.Name)
1264+
}
1265+
}
1266+
1267+
func TestLoadContent(t *testing.T) {
1268+
wd, err := os.Getwd()
1269+
if err != nil {
1270+
t.Fatalf("Error getting working directory: %v", err)
1271+
}
1272+
1273+
content, err := os.ReadFile(wd + "/test/global-tools.gpt")
1274+
if err != nil {
1275+
t.Fatalf("Error reading file: %v", err)
1276+
}
1277+
1278+
prg, err := g.LoadContent(context.Background(), string(content))
1279+
if err != nil {
1280+
t.Fatalf("Error loading file: %v", err)
1281+
}
1282+
1283+
if prg.EntryToolID == "" {
1284+
t.Errorf("Unexpected entry tool ID: %s", prg.EntryToolID)
1285+
}
1286+
1287+
if len(prg.ToolSet) == 0 {
1288+
t.Errorf("Unexpected number of tools: %d", len(prg.ToolSet))
1289+
}
1290+
1291+
// Name won't be set in this case
1292+
if prg.Name != "" {
1293+
t.Errorf("Unexpected name: %s", prg.Name)
1294+
}
1295+
}
1296+
1297+
func TestLoadTools(t *testing.T) {
1298+
tools := []ToolDef{
1299+
{
1300+
Tools: []string{"echo"},
1301+
Instructions: "echo 'hello there'",
1302+
},
1303+
{
1304+
Name: "other",
1305+
Tools: []string{"echo"},
1306+
Instructions: "echo 'hello somewhere else'",
1307+
},
1308+
{
1309+
Name: "echo",
1310+
Tools: []string{"sys.exec"},
1311+
Description: "Echoes the input",
1312+
Arguments: ObjectSchema("input", "The string input to echo"),
1313+
Instructions: "#!/bin/bash\n echo ${input}",
1314+
},
1315+
}
1316+
1317+
prg, err := g.LoadTools(context.Background(), tools)
1318+
if err != nil {
1319+
t.Fatalf("Error loading file: %v", err)
1320+
}
1321+
1322+
if prg.EntryToolID == "" {
1323+
t.Errorf("Unexpected entry tool ID: %s", prg.EntryToolID)
1324+
}
1325+
1326+
if len(prg.ToolSet) == 0 {
1327+
t.Errorf("Unexpected number of tools: %d", len(prg.ToolSet))
1328+
}
1329+
1330+
// Name won't be set in this case
1331+
if prg.Name != "" {
1332+
t.Errorf("Unexpected name: %s", prg.Name)
1333+
}
1334+
}

0 commit comments

Comments
 (0)