1
1
package parser
2
2
3
3
import (
4
- "bufio"
5
4
"fmt"
6
5
"io"
7
6
"maps"
@@ -17,8 +16,10 @@ import (
17
16
18
17
var (
19
18
sepRegex = regexp .MustCompile (`^\s*---+\s*$` )
19
+ endHeaderRegex = regexp .MustCompile (`^\s*===+\s*$` )
20
20
strictSepRegex = regexp .MustCompile (`^---\n$` )
21
21
skipRegex = regexp .MustCompile (`^![-.:*\w]+\s*$` )
22
+ nameRegex = regexp .MustCompile (`^[a-z]+$` )
22
23
)
23
24
24
25
func normalize (key string ) string {
@@ -56,6 +57,9 @@ func addArg(line string, tool *types.Tool) error {
56
57
tool .Parameters .Arguments = & openapi3.Schema {
57
58
Type : & openapi3.Types {"object" },
58
59
Properties : openapi3.Schemas {},
60
+ AdditionalProperties : openapi3.AdditionalProperties {
61
+ Has : new (bool ),
62
+ },
59
63
}
60
64
}
61
65
@@ -74,7 +78,7 @@ func addArg(line string, tool *types.Tool) error {
74
78
return nil
75
79
}
76
80
77
- func isParam (line string , tool * types.Tool ) (_ bool , err error ) {
81
+ func isParam (line string , tool * types.Tool , scan * simplescanner ) (_ bool , err error ) {
78
82
key , value , ok := strings .Cut (line , ":" )
79
83
if ! ok {
80
84
return false , nil
@@ -90,7 +94,7 @@ func isParam(line string, tool *types.Tool) (_ bool, err error) {
90
94
case "globalmodel" , "globalmodelname" :
91
95
tool .Parameters .GlobalModelName = value
92
96
case "description" :
93
- tool .Parameters .Description = value
97
+ tool .Parameters .Description = scan . AddMultiline ( value )
94
98
case "internalprompt" :
95
99
v , err := toBool (value )
96
100
if err != nil {
@@ -104,27 +108,33 @@ func isParam(line string, tool *types.Tool) (_ bool, err error) {
104
108
}
105
109
tool .Parameters .Chat = v
106
110
case "export" , "exporttool" , "exports" , "exporttools" , "sharetool" , "sharetools" , "sharedtool" , "sharedtools" :
107
- tool .Parameters .Export = append (tool .Parameters .Export , csv (value )... )
111
+ tool .Parameters .Export = append (tool .Parameters .Export , csv (scan . AddMultiline ( value ) )... )
108
112
case "tool" , "tools" :
109
- tool .Parameters .Tools = append (tool .Parameters .Tools , csv (value )... )
113
+ tool .Parameters .Tools = append (tool .Parameters .Tools , csv (scan . AddMultiline ( value ) )... )
110
114
case "inputfilter" , "inputfilters" :
111
- tool .Parameters .InputFilters = append (tool .Parameters .InputFilters , csv (value )... )
115
+ tool .Parameters .InputFilters = append (tool .Parameters .InputFilters , csv (scan . AddMultiline ( value ) )... )
112
116
case "shareinputfilter" , "shareinputfilters" , "sharedinputfilter" , "sharedinputfilters" :
113
- tool .Parameters .ExportInputFilters = append (tool .Parameters .ExportInputFilters , csv (value )... )
117
+ tool .Parameters .ExportInputFilters = append (tool .Parameters .ExportInputFilters , csv (scan . AddMultiline ( value ) )... )
114
118
case "outputfilter" , "outputfilters" :
115
- tool .Parameters .OutputFilters = append (tool .Parameters .OutputFilters , csv (value )... )
119
+ tool .Parameters .OutputFilters = append (tool .Parameters .OutputFilters , csv (scan . AddMultiline ( value ) )... )
116
120
case "shareoutputfilter" , "shareoutputfilters" , "sharedoutputfilter" , "sharedoutputfilters" :
117
- tool .Parameters .ExportOutputFilters = append (tool .Parameters .ExportOutputFilters , csv (value )... )
121
+ tool .Parameters .ExportOutputFilters = append (tool .Parameters .ExportOutputFilters , csv (scan . AddMultiline ( value ) )... )
118
122
case "agent" , "agents" :
119
- tool .Parameters .Agents = append (tool .Parameters .Agents , csv (value )... )
123
+ tool .Parameters .Agents = append (tool .Parameters .Agents , csv (scan . AddMultiline ( value ) )... )
120
124
case "globaltool" , "globaltools" :
121
- tool .Parameters .GlobalTools = append (tool .Parameters .GlobalTools , csv (value )... )
125
+ tool .Parameters .GlobalTools = append (tool .Parameters .GlobalTools , csv (scan . AddMultiline ( value ) )... )
122
126
case "exportcontext" , "exportcontexts" , "sharecontext" , "sharecontexts" , "sharedcontext" , "sharedcontexts" :
123
- tool .Parameters .ExportContext = append (tool .Parameters .ExportContext , csv (value )... )
127
+ tool .Parameters .ExportContext = append (tool .Parameters .ExportContext , csv (scan . AddMultiline ( value ) )... )
124
128
case "context" :
125
- tool .Parameters .Context = append (tool .Parameters .Context , csv (value )... )
129
+ tool .Parameters .Context = append (tool .Parameters .Context , csv (scan .AddMultiline (value ))... )
130
+ case "metadata" :
131
+ mkey , mvalue , _ := strings .Cut (scan .AddMultiline (value ), ":" )
132
+ if tool .MetaData == nil {
133
+ tool .MetaData = map [string ]string {}
134
+ }
135
+ tool .MetaData [strings .TrimSpace (mkey )] = strings .TrimSpace (mvalue )
126
136
case "args" , "arg" , "param" , "params" , "parameters" , "parameter" :
127
- if err := addArg (value , tool ); err != nil {
137
+ if err := addArg (scan . AddMultiline ( value ) , tool ); err != nil {
128
138
return false , err
129
139
}
130
140
case "maxtoken" , "maxtokens" :
@@ -149,13 +159,13 @@ func isParam(line string, tool *types.Tool) (_ bool, err error) {
149
159
return false , err
150
160
}
151
161
case "credentials" , "creds" , "credential" , "cred" :
152
- tool .Parameters .Credentials = append (tool .Parameters .Credentials , value )
162
+ tool .Parameters .Credentials = append (tool .Parameters .Credentials , csv ( scan . AddMultiline ( value )) ... )
153
163
case "sharecredentials" , "sharecreds" , "sharecredential" , "sharecred" , "sharedcredentials" , "sharedcreds" , "sharedcredential" , "sharedcred" :
154
- tool .Parameters .ExportCredentials = append (tool .Parameters .ExportCredentials , value )
164
+ tool .Parameters .ExportCredentials = append (tool .Parameters .ExportCredentials , scan . AddMultiline ( value ) )
155
165
case "type" :
156
166
tool .Type = types .ToolType (strings .ToLower (value ))
157
167
default :
158
- return false , nil
168
+ return nameRegex . MatchString ( key ) , nil
159
169
}
160
170
161
171
return true , nil
@@ -206,6 +216,7 @@ func (c *context) finish(tools *[]Node) {
206
216
len (c .tool .ExportInputFilters ) > 0 ||
207
217
len (c .tool .ExportOutputFilters ) > 0 ||
208
218
len (c .tool .Agents ) > 0 ||
219
+ len (c .tool .ExportCredentials ) > 0 ||
209
220
c .tool .Chat {
210
221
* tools = append (* tools , Node {
211
222
ToolNode : & ToolNode {
@@ -391,7 +402,10 @@ func assignMetadata(nodes []Node) (result []Node) {
391
402
392
403
for _ , node := range nodes {
393
404
if node .ToolNode != nil {
394
- node .ToolNode .Tool .MetaData = metadata [node .ToolNode .Tool .Name ]
405
+ if node .ToolNode .Tool .MetaData == nil {
406
+ node .ToolNode .Tool .MetaData = map [string ]string {}
407
+ }
408
+ maps .Copy (node .ToolNode .Tool .MetaData , metadata [node .ToolNode .Tool .Name ])
395
409
for wildcard := range metadata {
396
410
if strings .Contains (wildcard , "*" ) {
397
411
if m , err := path .Match (wildcard , node .ToolNode .Tool .Name ); m && err == nil {
@@ -433,15 +447,64 @@ func isGPTScriptHashBang(line string) bool {
433
447
return false
434
448
}
435
449
436
- func parse (input io.Reader ) ([]Node , error ) {
437
- scan := bufio .NewScanner (input )
450
+ type simplescanner struct {
451
+ lines []string
452
+ }
453
+
454
+ func newSimpleScanner (data []byte ) * simplescanner {
455
+ if len (data ) == 0 {
456
+ return & simplescanner {}
457
+ }
458
+ lines := strings .Split (string (data ), "\n " )
459
+ return & simplescanner {
460
+ lines : append ([]string {"" }, lines ... ),
461
+ }
462
+ }
463
+
464
+ func (s * simplescanner ) AddMultiline (current string ) string {
465
+ result := current
466
+ for {
467
+ if len (s .lines ) < 2 || len (s .lines [1 ]) == 0 {
468
+ return result
469
+ }
470
+ if strings .HasPrefix (s .lines [1 ], " " ) || strings .HasPrefix (s .lines [1 ], "\t " ) {
471
+ result += " " + s .lines [1 ]
472
+ s .lines = s .lines [1 :]
473
+ } else {
474
+ return result
475
+ }
476
+ }
477
+ }
438
478
479
+ func (s * simplescanner ) Text () string {
480
+ if len (s .lines ) == 0 {
481
+ return ""
482
+ }
483
+ return s .lines [0 ]
484
+ }
485
+
486
+ func (s * simplescanner ) Scan () bool {
487
+ if len (s .lines ) == 0 {
488
+ return false
489
+ }
490
+ s .lines = s .lines [1 :]
491
+ return true
492
+ }
493
+
494
+ func parse (input io.Reader ) ([]Node , error ) {
439
495
var (
440
496
tools []Node
441
497
context context
442
498
lineNo int
443
499
)
444
500
501
+ data , err := io .ReadAll (input )
502
+ if err != nil {
503
+ return nil , err
504
+ }
505
+
506
+ scan := newSimpleScanner (data )
507
+
445
508
for scan .Scan () {
446
509
lineNo ++
447
510
if context .tool .Source .LineNo == 0 {
@@ -488,11 +551,15 @@ func parse(input io.Reader) ([]Node, error) {
488
551
}
489
552
490
553
// Look for params
491
- if isParam , err := isParam (line , & context .tool ); err != nil {
554
+ if isParam , err := isParam (line , & context .tool , scan ); err != nil {
492
555
return nil , NewErrLine ("" , lineNo , err )
493
556
} else if isParam {
494
557
context .seenParam = true
495
558
continue
559
+ } else if endHeaderRegex .MatchString (line ) {
560
+ // force the end of the header and don't include the current line in the header
561
+ context .inBody = true
562
+ continue
496
563
}
497
564
}
498
565
0 commit comments