@@ -174,42 +174,124 @@ type context struct {
174
174
instructions []string
175
175
inBody bool
176
176
skipNode bool
177
+ skipLines []string
177
178
seenParam bool
178
179
}
179
180
180
- func (c * context ) finish (tools * []types. Tool ) {
181
+ func (c * context ) finish (tools * []Node ) {
181
182
c .tool .Instructions = strings .TrimSpace (strings .Join (c .instructions , "" ))
182
183
if c .tool .Instructions != "" || c .tool .Parameters .Name != "" ||
183
184
len (c .tool .Export ) > 0 || len (c .tool .Tools ) > 0 ||
184
185
c .tool .GlobalModelName != "" ||
185
186
len (c .tool .GlobalTools ) > 0 ||
186
187
c .tool .Chat {
187
- * tools = append (* tools , c .tool )
188
+ * tools = append (* tools , Node {
189
+ ToolNode : & ToolNode {
190
+ Tool : c .tool ,
191
+ },
192
+ })
193
+ }
194
+ if c .skipNode && len (c .skipLines ) > 0 {
195
+ * tools = append (* tools , Node {
196
+ TextNode : & TextNode {
197
+ Text : strings .Join (c .skipLines , "" ),
198
+ },
199
+ })
188
200
}
189
201
* c = context {}
190
202
}
191
203
192
204
type Options struct {
193
205
AssignGlobals bool
206
+ Location string
194
207
}
195
208
196
209
func complete (opts ... Options ) (result Options ) {
197
210
for _ , opt := range opts {
198
211
result .AssignGlobals = types .FirstSet (opt .AssignGlobals , result .AssignGlobals )
212
+ result .Location = types .FirstSet (opt .Location , result .Location )
199
213
}
200
214
return
201
215
}
202
216
203
- func Parse (input io.Reader , opts ... Options ) ([]types.Tool , error ) {
204
- tools , err := parse (input )
217
+ type Document struct {
218
+ Nodes []Node `json:"nodes,omitempty"`
219
+ }
220
+
221
+ func writeSep (buf * strings.Builder , lastText bool ) {
222
+ if buf .Len () > 0 {
223
+ if ! lastText {
224
+ buf .WriteString ("\n " )
225
+ }
226
+ buf .WriteString ("---\n " )
227
+ }
228
+ }
229
+
230
+ func (d Document ) String () string {
231
+ buf := strings.Builder {}
232
+ lastText := false
233
+ for _ , node := range d .Nodes {
234
+ if node .TextNode != nil {
235
+ writeSep (& buf , lastText )
236
+ buf .WriteString (node .TextNode .Text )
237
+ lastText = true
238
+ }
239
+ if node .ToolNode != nil {
240
+ writeSep (& buf , lastText )
241
+ buf .WriteString (node .ToolNode .Tool .String ())
242
+ lastText = false
243
+ }
244
+ }
245
+ return buf .String ()
246
+ }
247
+
248
+ type Node struct {
249
+ TextNode * TextNode `json:"textNode,omitempty"`
250
+ ToolNode * ToolNode `json:"toolNode,omitempty"`
251
+ }
252
+
253
+ type TextNode struct {
254
+ Text string `json:"text,omitempty"`
255
+ }
256
+
257
+ type ToolNode struct {
258
+ Tool types.Tool `json:"tool,omitempty"`
259
+ }
260
+
261
+ func ParseTools (input io.Reader , opts ... Options ) (result []types.Tool , _ error ) {
262
+ doc , err := Parse (input , opts ... )
205
263
if err != nil {
206
264
return nil , err
207
265
}
266
+ for _ , node := range doc .Nodes {
267
+ if node .ToolNode != nil {
268
+ result = append (result , node .ToolNode .Tool )
269
+ }
270
+ }
271
+
272
+ return
273
+ }
274
+
275
+ func Parse (input io.Reader , opts ... Options ) (Document , error ) {
276
+ nodes , err := parse (input )
277
+ if err != nil {
278
+ return Document {}, err
279
+ }
208
280
209
281
opt := complete (opts ... )
210
282
283
+ if opt .Location != "" {
284
+ for _ , node := range nodes {
285
+ if node .ToolNode != nil && node .ToolNode .Tool .Source .Location == "" {
286
+ node .ToolNode .Tool .Source .Location = opt .Location
287
+ }
288
+ }
289
+ }
290
+
211
291
if ! opt .AssignGlobals {
212
- return tools , nil
292
+ return Document {
293
+ Nodes : nodes ,
294
+ }, nil
213
295
}
214
296
215
297
var (
@@ -218,10 +300,14 @@ func Parse(input io.Reader, opts ...Options) ([]types.Tool, error) {
218
300
globalTools []string
219
301
)
220
302
221
- for _ , tool := range tools {
303
+ for _ , node := range nodes {
304
+ if node .ToolNode == nil {
305
+ continue
306
+ }
307
+ tool := node .ToolNode .Tool
222
308
if tool .GlobalModelName != "" {
223
309
if globalModel != "" {
224
- return nil , fmt .Errorf ("global model name defined multiple times" )
310
+ return Document {} , fmt .Errorf ("global model name defined multiple times" )
225
311
}
226
312
globalModel = tool .GlobalModelName
227
313
}
@@ -234,26 +320,30 @@ func Parse(input io.Reader, opts ...Options) ([]types.Tool, error) {
234
320
}
235
321
}
236
322
237
- for i , tool := range tools {
238
- if globalModel != "" && tool .ModelName == "" {
239
- tool .ModelName = globalModel
323
+ for _ , node := range nodes {
324
+ if node .ToolNode == nil {
325
+ continue
326
+ }
327
+ if globalModel != "" && node .ToolNode .Tool .ModelName == "" {
328
+ node .ToolNode .Tool .ModelName = globalModel
240
329
}
241
330
for _ , globalTool := range globalTools {
242
- if ! slices .Contains (tool .Tools , globalTool ) {
243
- tool . Tools = append (tool .Tools , globalTool )
331
+ if ! slices .Contains (node . ToolNode . Tool .Tools , globalTool ) {
332
+ node . ToolNode . Tool . Tools = append (node . ToolNode . Tool .Tools , globalTool )
244
333
}
245
334
}
246
- tools [i ] = tool
247
335
}
248
336
249
- return tools , nil
337
+ return Document {
338
+ Nodes : nodes ,
339
+ }, nil
250
340
}
251
341
252
- func parse (input io.Reader ) ([]types. Tool , error ) {
342
+ func parse (input io.Reader ) ([]Node , error ) {
253
343
scan := bufio .NewScanner (input )
254
344
255
345
var (
256
- tools []types. Tool
346
+ tools []Node
257
347
context context
258
348
lineNo int
259
349
)
@@ -277,6 +367,7 @@ func parse(input io.Reader) ([]types.Tool, error) {
277
367
}
278
368
279
369
if context .skipNode {
370
+ context .skipLines = append (context .skipLines , line )
280
371
continue
281
372
}
282
373
@@ -292,6 +383,7 @@ func parse(input io.Reader) ([]types.Tool, error) {
292
383
}
293
384
294
385
if ! context .seenParam && skipRegex .MatchString (line ) {
386
+ context .skipLines = append (context .skipLines , line )
295
387
context .skipNode = true
296
388
continue
297
389
}
0 commit comments