Skip to content

Commit b89dbcf

Browse files
committed
fix: better error reporting
This change also includes change to Text nodes when parsing files for parity with other SDKs. Signed-off-by: Donnie Adams <[email protected]>
1 parent 8111c2b commit b89dbcf

File tree

5 files changed

+73
-48
lines changed

5 files changed

+73
-48
lines changed

README.md

+13-14
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ These are optional options that can be passed to the various `exec` functions.
3535
None of the options is required, and the defaults will reduce the number of calls made to the Model API.
3636
As noted above, the Global Options are also available to specify here. These options would take precedence.
3737

38-
- `cache`: Enable or disable caching. Default (true).
39-
- `cacheDir`: Specify the cache directory.
38+
- `disableCache`: Enable or disable caching. Default (false).
4039
- `subTool`: Use tool of this name, not the first tool
4140
- `input`: Input arguments for the tool run
4241
- `workspace`: Directory to use for the workspace, if specified it will not be deleted on exit
@@ -88,7 +87,7 @@ import (
8887
)
8988

9089
func listModels(ctx context.Context) ([]string, error) {
91-
g, err := gptscript.NewGPTScript()
90+
g, err := gptscript.NewGPTScript(gptscript.GlobalOptions{})
9291
if err != nil {
9392
return nil, err
9493
}
@@ -111,7 +110,7 @@ import (
111110
)
112111

113112
func parse(ctx context.Context, fileName string) ([]gptscript.Node, error) {
114-
g, err := gptscript.NewGPTScript()
113+
g, err := gptscript.NewGPTScript(gptscript.GlobalOptions{})
115114
if err != nil {
116115
return nil, err
117116
}
@@ -135,7 +134,7 @@ import (
135134
)
136135

137136
func parseTool(ctx context.Context, contents string) ([]gptscript.Node, error) {
138-
g, err := gptscript.NewGPTScript()
137+
g, err := gptscript.NewGPTScript(gptscript.GlobalOptions{})
139138
if err != nil {
140139
return nil, err
141140
}
@@ -159,7 +158,7 @@ import (
159158
)
160159

161160
func parse(ctx context.Context, nodes []gptscript.Node) (string, error) {
162-
g, err := gptscript.NewGPTScript()
161+
g, err := gptscript.NewGPTScript(gptscript.GlobalOptions{})
163162
if err != nil {
164163
return "", err
165164
}
@@ -187,7 +186,7 @@ func runTool(ctx context.Context) (string, error) {
187186
Instructions: "who was the president of the united states in 1928?",
188187
}
189188

190-
g, err := gptscript.NewGPTScript()
189+
g, err := gptscript.NewGPTScript(gptscript.GlobalOptions{})
191190
if err != nil {
192191
return "", err
193192
}
@@ -221,7 +220,7 @@ func runFile(ctx context.Context) (string, error) {
221220
Input: "--input hello",
222221
}
223222

224-
g, err := gptscript.NewGPTScript()
223+
g, err := gptscript.NewGPTScript(gptscript.GlobalOptions{})
225224
if err != nil {
226225
return "", err
227226
}
@@ -238,7 +237,7 @@ func runFile(ctx context.Context) (string, error) {
238237

239238
### Streaming events
240239

241-
In order to stream events, you must set `IncludeEvents` option to `true`. You if you don't set this and try to stream events, then it will succeed, but you will not get any events. More importantly, if you set `IncludeEvents` to `true`, you must stream the events for the script to complete.
240+
In order to stream events, you must set `IncludeEvents` option to `true`. If you don't set this and try to stream events, then it will succeed, but you will not get any events. More importantly, if you set `IncludeEvents` to `true`, you must stream the events for the script to complete.
242241

243242
```go
244243
package main
@@ -250,13 +249,13 @@ import (
250249
)
251250

252251
func streamExecTool(ctx context.Context) error {
253-
opts := gptscript.Opts{
252+
opts := gptscript.Options{
254253
DisableCache: &[]bool{true}[0],
255254
IncludeEvents: true,
256255
Input: "--input world",
257256
}
258257

259-
g, err := gptscript.NewGPTScript()
258+
g, err := gptscript.NewGPTScript(gptscript.GlobalOptions{})
260259
if err != nil {
261260
return "", err
262261
}
@@ -278,7 +277,7 @@ func streamExecTool(ctx context.Context) error {
278277

279278
### Confirm
280279

281-
Using the `confirm: true` option allows a user to inspect potentially dangerous commands before they are run. The caller has the ability to allow or disallow their running. In order to do this, a caller should look for the `CallConfirm` event. This also means that `IncludeEvent` should be `true`.
280+
Using the `Confirm: true` option allows a user to inspect potentially dangerous commands before they are run. The caller has the ability to allow or disallow their running. In order to do this, a caller should look for the `CallConfirm` event. This also means that `IncludeEvent` should be `true`.
282281

283282
```go
284283
package main
@@ -297,7 +296,7 @@ func runFileWithConfirm(ctx context.Context) (string, error) {
297296
IncludeEvents: true,
298297
}
299298

300-
g, err := gptscript.NewGPTScript()
299+
g, err := gptscript.NewGPTScript(gptscript.GlobalOptions{})
301300
if err != nil {
302301
return "", err
303302
}
@@ -351,7 +350,7 @@ func runFileWithPrompt(ctx context.Context) (string, error) {
351350
IncludeEvents: true,
352351
}
353352

354-
g, err := gptscript.NewGPTScript()
353+
g, err := gptscript.NewGPTScript(gptscript.GlobalOptions{})
355354
if err != nil {
356355
return "", err
357356
}

gptscript.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func NewGPTScript(opts GlobalOptions) (GPTScript, error) {
4949
defer lock.Unlock()
5050
gptscriptCount++
5151

52-
disableServer := os.Getenv("GPT_SCRIPT_DISABLE_SERVER") == "true"
52+
disableServer := os.Getenv("GPTSCRIPT_DISABLE_SERVER") == "true"
5353

5454
if serverURL == "" && disableServer {
5555
serverURL = os.Getenv("GPTSCRIPT_URL")
@@ -165,6 +165,10 @@ func (g *gptscript) Parse(ctx context.Context, fileName string) ([]Node, error)
165165
return nil, err
166166
}
167167

168+
for _, node := range doc.Nodes {
169+
node.TextNode.process()
170+
}
171+
168172
return doc.Nodes, nil
169173
}
170174

@@ -180,11 +184,19 @@ func (g *gptscript) ParseTool(ctx context.Context, toolDef string) ([]Node, erro
180184
return nil, err
181185
}
182186

187+
for _, node := range doc.Nodes {
188+
node.TextNode.process()
189+
}
190+
183191
return doc.Nodes, nil
184192
}
185193

186194
// Fmt will format the given nodes into a string.
187195
func (g *gptscript) Fmt(ctx context.Context, nodes []Node) (string, error) {
196+
for _, node := range nodes {
197+
node.TextNode.combine()
198+
}
199+
188200
out, err := g.runBasicCommand(ctx, "fmt", Document{Nodes: nodes})
189201
if err != nil {
190202
return "", err

gptscript_test.go

+24-28
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ func TestEvaluateWithContext(t *testing.T) {
151151
},
152152
}
153153

154-
run, err := g.Evaluate(context.Background(), Options{DisableCache: true, IncludeEvents: true}, tool)
154+
run, err := g.Evaluate(context.Background(), Options{}, tool)
155155
if err != nil {
156156
t.Errorf("Error executing tool: %v", err)
157157
}
@@ -214,7 +214,7 @@ func TestEvaluateWithToolList(t *testing.T) {
214214
Tools: []string{"sys.exec"},
215215
Description: "Echoes the input",
216216
Arguments: ObjectSchema("input", "The string input to echo"),
217-
Instructions: shebang + "\n echo ${input}",
217+
Instructions: shebang + "\necho ${input}",
218218
},
219219
}
220220

@@ -410,9 +410,12 @@ func TestParseToolWithTextNode(t *testing.T) {
410410
t.Fatalf("No text node found")
411411
}
412412

413-
if tools[1].TextNode.Text != "!markdown\nhello\n" {
413+
if tools[1].TextNode.Text != "hello\n" {
414414
t.Errorf("Unexpected text: %s", tools[1].TextNode.Text)
415415
}
416+
if tools[1].TextNode.Fmt != "markdown" {
417+
t.Errorf("Unexpected fmt: %s", tools[1].TextNode.Fmt)
418+
}
416419
}
417420

418421
func TestFmt(t *testing.T) {
@@ -484,7 +487,8 @@ func TestFmtWithTextNode(t *testing.T) {
484487
},
485488
{
486489
TextNode: &TextNode{
487-
Text: "!markdown\nWe now echo hello there\n",
490+
Fmt: "markdown",
491+
Text: "We now echo hello there\n",
488492
},
489493
},
490494
{
@@ -686,14 +690,12 @@ func TestToolWithGlobalTools(t *testing.T) {
686690

687691
func TestConfirm(t *testing.T) {
688692
var eventContent string
689-
tools := []ToolDef{
690-
{
691-
Instructions: "List the files in the current directory",
692-
Tools: []string{"sys.exec"},
693-
},
693+
tools := ToolDef{
694+
Instructions: "List the files in the current directory",
695+
Tools: []string{"sys.exec"},
694696
}
695697

696-
run, err := g.Evaluate(context.Background(), Options{IncludeEvents: true, Confirm: true}, tools...)
698+
run, err := g.Evaluate(context.Background(), Options{IncludeEvents: true, Confirm: true}, tools)
697699
if err != nil {
698700
t.Errorf("Error executing tool: %v", err)
699701
}
@@ -771,14 +773,12 @@ func TestConfirm(t *testing.T) {
771773

772774
func TestConfirmDeny(t *testing.T) {
773775
var eventContent string
774-
tools := []ToolDef{
775-
{
776-
Instructions: "List the files in the current directory",
777-
Tools: []string{"sys.exec"},
778-
},
776+
tools := ToolDef{
777+
Instructions: "List the files in the current directory",
778+
Tools: []string{"sys.exec"},
779779
}
780780

781-
run, err := g.Evaluate(context.Background(), Options{IncludeEvents: true, Confirm: true}, tools...)
781+
run, err := g.Evaluate(context.Background(), Options{IncludeEvents: true, Confirm: true}, tools)
782782
if err != nil {
783783
t.Errorf("Error executing tool: %v", err)
784784
}
@@ -843,14 +843,12 @@ func TestConfirmDeny(t *testing.T) {
843843

844844
func TestPrompt(t *testing.T) {
845845
var eventContent string
846-
tools := []ToolDef{
847-
{
848-
Instructions: "Use the sys.prompt user to ask the user for 'first name' which is not sensitive. After you get their first name, say hello.",
849-
Tools: []string{"sys.prompt"},
850-
},
846+
tools := ToolDef{
847+
Instructions: "Use the sys.prompt user to ask the user for 'first name' which is not sensitive. After you get their first name, say hello.",
848+
Tools: []string{"sys.prompt"},
851849
}
852850

853-
run, err := g.Evaluate(context.Background(), Options{IncludeEvents: true, Prompt: true}, tools...)
851+
run, err := g.Evaluate(context.Background(), Options{IncludeEvents: true, Prompt: true}, tools)
854852
if err != nil {
855853
t.Errorf("Error executing tool: %v", err)
856854
}
@@ -926,14 +924,12 @@ func TestPrompt(t *testing.T) {
926924
}
927925

928926
func TestPromptWithoutPromptAllowed(t *testing.T) {
929-
tools := []ToolDef{
930-
{
931-
Instructions: "Use the sys.prompt user to ask the user for 'first name' which is not sensitive. After you get their first name, say hello.",
932-
Tools: []string{"sys.prompt"},
933-
},
927+
tools := ToolDef{
928+
Instructions: "Use the sys.prompt user to ask the user for 'first name' which is not sensitive. After you get their first name, say hello.",
929+
Tools: []string{"sys.prompt"},
934930
}
935931

936-
run, err := g.Evaluate(context.Background(), Options{IncludeEvents: true}, tools...)
932+
run, err := g.Evaluate(context.Background(), Options{IncludeEvents: true}, tools)
937933
if err != nil {
938934
t.Errorf("Error executing tool: %v", err)
939935
}

run.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (r *Run) Text() (string, error) {
4343
r.lock.Lock()
4444
defer r.lock.Unlock()
4545
if r.err != nil {
46-
return "", r.err
46+
return "", fmt.Errorf("run encounterd an error: %w with error output: %s", r.err, r.errput)
4747
}
4848

4949
return r.output, nil
@@ -237,11 +237,11 @@ func (r *Run) request(ctx context.Context, payload any) (err error) {
237237

238238
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest {
239239
r.state = Error
240-
r.err = fmt.Errorf("unexpected response status: %s", resp.Status)
241-
return r.err
240+
r.err = fmt.Errorf("run encountered an error")
241+
} else {
242+
r.state = Running
242243
}
243244

244-
r.state = Running
245245
r.events = make(chan Frame, 100)
246246
r.lock.Lock()
247247
go func() {

tool.go

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package gptscript
22

33
import (
4+
"fmt"
5+
"strings"
6+
47
"github.com/getkin/kin-openapi/openapi3"
58
)
69

@@ -56,11 +59,26 @@ type Node struct {
5659
}
5760

5861
type TextNode struct {
62+
Fmt string `json:"fmt,omitempty"`
5963
Text string `json:"text,omitempty"`
6064
}
6165

66+
func (n *TextNode) combine() {
67+
if n != nil && n.Fmt != "" {
68+
n.Text = fmt.Sprintf("!%s\n%s", n.Fmt, n.Text)
69+
n.Fmt = ""
70+
}
71+
}
72+
73+
func (n *TextNode) process() {
74+
if n != nil && strings.HasPrefix(n.Text, "!") {
75+
n.Fmt, n.Text, _ = strings.Cut(strings.TrimPrefix(n.Text, "!"), "\n")
76+
}
77+
}
78+
6279
type ToolNode struct {
63-
Tool Tool `json:"tool,omitempty"`
80+
Fmt string `json:"fmt,omitempty"`
81+
Tool Tool `json:"tool,omitempty"`
6482
}
6583

6684
type Tool struct {

0 commit comments

Comments
 (0)