Skip to content

Commit 86387ed

Browse files
Add --list-tools
1 parent 2dc8c61 commit 86387ed

File tree

9 files changed

+250
-113
lines changed

9 files changed

+250
-113
lines changed

examples/summarize-syntax.gpt

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
tools: ls, cat
1+
tools: ls, sys.read, help
22

3-
Read all gpt files and then write a README that describes the syntax of the gpt files
3+
Write a README.md for this github repo that describes this project, it's usage, and a description of the
4+
GPT file syntax. Example GPT files can be found by listing and read them. Also document the help of the
5+
gptscript command.
46

57
---
68
name: ls
@@ -11,10 +13,7 @@ description: list all gpt files
1113
find . -name '*.gpt'
1214

1315
---
14-
name: cat
15-
description: Reads the contents of a file
16-
arg: file: The filename to read
16+
name: help
17+
description: Get the help output of gptscript
1718

18-
#!/bin/bash
19-
20-
cat ${FILE} </dev/null
19+
#!gptscript --help

pkg/builtin/builtin.go

+122-96
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io"
88
"net/http"
99
"os"
10+
"sort"
1011
"strings"
1112

1213
"github.com/acorn-io/gptscript/pkg/types"
@@ -17,133 +18,158 @@ var Tools = map[string]types.Tool{
1718
Description: "Reads the contents of a file",
1819
Arguments: types.ObjectSchema(
1920
"filename", "The name of the file to read"),
20-
BuiltinFunc: func(ctx context.Context, env []string, input string) (string, error) {
21-
var params struct {
22-
Filename string `json:"filename,omitempty"`
23-
}
24-
if err := json.Unmarshal([]byte(input), &params); err != nil {
25-
return "", err
26-
}
27-
28-
log.Debugf("Reading file %s", params.Filename)
29-
data, err := os.ReadFile(params.Filename)
30-
if err != nil {
31-
return "", err
32-
}
33-
34-
return string(data), nil
35-
},
21+
BuiltinFunc: SysRead,
3622
},
3723
"sys.write": {
3824
Description: "Write the contents to a file",
3925
Arguments: types.ObjectSchema(
4026
"filename", "The name of the file to write to",
4127
"content", "The content to write"),
42-
BuiltinFunc: func(ctx context.Context, env []string, input string) (string, error) {
43-
var params struct {
44-
Filename string `json:"filename,omitempty"`
45-
Content string `json:"content,omitempty"`
46-
}
47-
if err := json.Unmarshal([]byte(input), &params); err != nil {
48-
return "", err
49-
}
50-
51-
data := []byte(params.Content)
52-
msg := fmt.Sprintf("Wrote %d bytes to file %s", len(data), params.Filename)
53-
log.Debugf(msg)
54-
55-
return "", os.WriteFile(params.Filename, data, 0644)
56-
},
28+
BuiltinFunc: SysWrite,
5729
},
5830
"sys.http.get": {
5931
Description: "Download the contents of a http or https URL",
6032
Arguments: types.ObjectSchema(
6133
"url", "The URL to download"),
62-
BuiltinFunc: func(ctx context.Context, env []string, input string) (string, error) {
63-
var params struct {
64-
URL string `json:"url,omitempty"`
65-
}
66-
if err := json.Unmarshal([]byte(input), &params); err != nil {
67-
return "", err
68-
}
69-
70-
log.Debugf("http get %s", params.URL)
71-
resp, err := http.Get(params.URL)
72-
if err != nil {
73-
return "", err
74-
}
75-
defer resp.Body.Close()
76-
if resp.StatusCode != http.StatusOK {
77-
return "", fmt.Errorf("failed to download %s: %s", params.URL, resp.Status)
78-
}
79-
80-
data, err := io.ReadAll(resp.Body)
81-
if err != nil {
82-
return "", err
83-
}
84-
85-
return string(data), nil
86-
},
34+
BuiltinFunc: SysHTTPGet,
8735
},
8836
"sys.abort": {
8937
Description: "Aborts execution",
9038
Arguments: types.ObjectSchema(
9139
"message", "The description of the error or unexpected result that caused abort to be called",
9240
),
93-
BuiltinFunc: func(ctx context.Context, env []string, input string) (string, error) {
94-
var params struct {
95-
Message string `json:"message,omitempty"`
96-
}
97-
if err := json.Unmarshal([]byte(input), &params); err != nil {
98-
return "", err
99-
}
100-
return "", fmt.Errorf("ABORT: %s", params.Message)
101-
},
41+
BuiltinFunc: SysAbort,
10242
},
10343
"sys.http.post": {
10444
Description: "Write contents to a http or https URL using the POST method",
10545
Arguments: types.ObjectSchema(
10646
"url", "The URL to POST to",
10747
"content", "The content to POST",
10848
"contentType", "The \"content type\" of the content such as application/json or text/plain"),
109-
BuiltinFunc: func(ctx context.Context, env []string, input string) (string, error) {
110-
var params struct {
111-
URL string `json:"url,omitempty"`
112-
Content string `json:"content,omitempty"`
113-
ContentType string `json:"contentType,omitempty"`
114-
}
115-
if err := json.Unmarshal([]byte(input), &params); err != nil {
116-
return "", err
117-
}
118-
119-
req, err := http.NewRequestWithContext(ctx, http.MethodPost, params.URL, strings.NewReader(params.Content))
120-
if err != nil {
121-
return "", err
122-
}
123-
if params.ContentType != "" {
124-
req.Header.Set("Content-Type", params.ContentType)
125-
}
126-
127-
resp, err := http.DefaultClient.Do(req)
128-
if err != nil {
129-
return "", err
130-
}
131-
defer resp.Body.Close()
132-
133-
_, _ = io.ReadAll(resp.Body)
134-
if resp.StatusCode > 399 {
135-
return "", fmt.Errorf("failed to post %s: %s", params.URL, resp.Status)
136-
}
137-
138-
return fmt.Sprintf("Wrote %d to %s", len([]byte(params.Content)), params.URL), nil
139-
},
49+
BuiltinFunc: SysHTTPPost,
14050
},
14151
}
14252

53+
func ListTools() (result []types.Tool) {
54+
var keys []string
55+
for k := range Tools {
56+
keys = append(keys, k)
57+
}
58+
59+
sort.Strings(keys)
60+
for _, key := range keys {
61+
t, _ := Builtin(key)
62+
result = append(result, t)
63+
}
64+
65+
return
66+
}
67+
14368
func Builtin(name string) (types.Tool, bool) {
14469
t, ok := Tools[name]
14570
t.Name = name
14671
t.ID = name
14772
t.Instructions = "#!" + name
14873
return t, ok
14974
}
75+
76+
func SysRead(ctx context.Context, env []string, input string) (string, error) {
77+
var params struct {
78+
Filename string `json:"filename,omitempty"`
79+
}
80+
if err := json.Unmarshal([]byte(input), &params); err != nil {
81+
return "", err
82+
}
83+
84+
log.Debugf("Reading file %s", params.Filename)
85+
data, err := os.ReadFile(params.Filename)
86+
if err != nil {
87+
return "", err
88+
}
89+
90+
return string(data), nil
91+
}
92+
93+
func SysWrite(ctx context.Context, env []string, input string) (string, error) {
94+
var params struct {
95+
Filename string `json:"filename,omitempty"`
96+
Content string `json:"content,omitempty"`
97+
}
98+
if err := json.Unmarshal([]byte(input), &params); err != nil {
99+
return "", err
100+
}
101+
102+
data := []byte(params.Content)
103+
msg := fmt.Sprintf("Wrote %d bytes to file %s", len(data), params.Filename)
104+
log.Debugf(msg)
105+
106+
return "", os.WriteFile(params.Filename, data, 0644)
107+
}
108+
109+
func SysHTTPGet(ctx context.Context, env []string, input string) (string, error) {
110+
var params struct {
111+
URL string `json:"url,omitempty"`
112+
}
113+
if err := json.Unmarshal([]byte(input), &params); err != nil {
114+
return "", err
115+
}
116+
117+
log.Debugf("http get %s", params.URL)
118+
resp, err := http.Get(params.URL)
119+
if err != nil {
120+
return "", err
121+
}
122+
defer resp.Body.Close()
123+
if resp.StatusCode != http.StatusOK {
124+
return "", fmt.Errorf("failed to download %s: %s", params.URL, resp.Status)
125+
}
126+
127+
data, err := io.ReadAll(resp.Body)
128+
if err != nil {
129+
return "", err
130+
}
131+
132+
return string(data), nil
133+
}
134+
135+
func SysHTTPPost(ctx context.Context, env []string, input string) (string, error) {
136+
var params struct {
137+
URL string `json:"url,omitempty"`
138+
Content string `json:"content,omitempty"`
139+
ContentType string `json:"contentType,omitempty"`
140+
}
141+
if err := json.Unmarshal([]byte(input), &params); err != nil {
142+
return "", err
143+
}
144+
145+
req, err := http.NewRequestWithContext(ctx, http.MethodPost, params.URL, strings.NewReader(params.Content))
146+
if err != nil {
147+
return "", err
148+
}
149+
if params.ContentType != "" {
150+
req.Header.Set("Content-Type", params.ContentType)
151+
}
152+
153+
resp, err := http.DefaultClient.Do(req)
154+
if err != nil {
155+
return "", err
156+
}
157+
defer resp.Body.Close()
158+
159+
_, _ = io.ReadAll(resp.Body)
160+
if resp.StatusCode > 399 {
161+
return "", fmt.Errorf("failed to post %s: %s", params.URL, resp.Status)
162+
}
163+
164+
return fmt.Sprintf("Wrote %d to %s", len([]byte(params.Content)), params.URL), nil
165+
}
166+
167+
func SysAbort(ctx context.Context, env []string, input string) (string, error) {
168+
var params struct {
169+
Message string `json:"message,omitempty"`
170+
}
171+
if err := json.Unmarshal([]byte(input), &params); err != nil {
172+
return "", err
173+
}
174+
return "", fmt.Errorf("ABORT: %s", params.Message)
175+
}

pkg/cli/gptscript.go

+15
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/acorn-io/cmd"
1111
"github.com/acorn-io/gptscript/pkg/assemble"
12+
"github.com/acorn-io/gptscript/pkg/builtin"
1213
"github.com/acorn-io/gptscript/pkg/input"
1314
"github.com/acorn-io/gptscript/pkg/loader"
1415
"github.com/acorn-io/gptscript/pkg/monitor"
@@ -34,6 +35,7 @@ type GPTScript struct {
3435
SubTool string `usage:"Use tool of this name, not the first tool in file"`
3536
Assemble bool `usage:"Assemble tool to a single artifact, saved to --output"`
3637
ListModels bool `usage:"List the models available and exit"`
38+
ListTools bool `usage:"List built-in tools and exit"`
3739
}
3840

3941
func New() *cobra.Command {
@@ -45,6 +47,15 @@ func (r *GPTScript) Customize(cmd *cobra.Command) {
4547
cmd.Flags().SetInterspersed(false)
4648
}
4749

50+
func (r *GPTScript) listTools(ctx context.Context) error {
51+
var lines []string
52+
for _, tool := range builtin.ListTools() {
53+
lines = append(lines, tool.String())
54+
}
55+
fmt.Println(strings.Join(lines, "\n---\n"))
56+
return nil
57+
}
58+
4859
func (r *GPTScript) listModels(ctx context.Context) error {
4960
c, err := openai.NewClient(openai.Options(r.OpenAIOptions))
5061
if err != nil {
@@ -80,6 +91,10 @@ func (r *GPTScript) Run(cmd *cobra.Command, args []string) error {
8091
return r.listModels(cmd.Context())
8192
}
8293

94+
if r.ListTools {
95+
return r.listTools(cmd.Context())
96+
}
97+
8398
if len(args) == 0 {
8499
return fmt.Errorf("scripts argument required")
85100
}

0 commit comments

Comments
 (0)