@@ -64,9 +64,10 @@ func withExecutedTools(executedTools map[string]string) ToolsNodeOption {
64
64
// Invoke(ctx context.Context, input *schema.Message, opts ...ToolsNodeOption) ([]*schema.Message, error)
65
65
// Stream(ctx context.Context, input *schema.Message, opts ...ToolsNodeOption) (*schema.StreamReader[[]*schema.Message], error)
66
66
type ToolsNode struct {
67
- tuple * toolsTuple
68
- unknownToolHandler func (ctx context.Context , name , input string ) (string , error )
69
- executeSequentially bool
67
+ tuple * toolsTuple
68
+ unknownToolHandler func (ctx context.Context , name , input string ) (string , error )
69
+ executeSequentially bool
70
+ toolArgumentsHandler func (ctx context.Context , name , input string ) (string , error )
70
71
}
71
72
72
73
// ToolsNodeConfig is the config for ToolsNode.
@@ -91,6 +92,17 @@ type ToolsNodeConfig struct {
91
92
// When set to true, tool calls will be executed one after another in the order they appear in the input message.
92
93
// When set to false (default), tool calls will be executed in parallel.
93
94
ExecuteSequentially bool
95
+
96
+ // ToolArgumentsHandler allows handling of tool arguments before execution.
97
+ // When provided, this function will be called for each tool call to process the arguments.
98
+ // Parameters:
99
+ // - ctx: The context for the tool call
100
+ // - name: The name of the tool being called
101
+ // - arguments: The original arguments string for the tool
102
+ // Returns:
103
+ // - string: The processed arguments string to be used for tool execution
104
+ // - error: Any error that occurred during preprocessing
105
+ ToolArgumentsHandler func (ctx context.Context , name , arguments string ) (string , error )
94
106
}
95
107
96
108
// NewToolNode creates a new ToolsNode.
@@ -107,9 +119,10 @@ func NewToolNode(ctx context.Context, conf *ToolsNodeConfig) (*ToolsNode, error)
107
119
}
108
120
109
121
return & ToolsNode {
110
- tuple : tuple ,
111
- unknownToolHandler : conf .UnknownToolsHandler ,
112
- executeSequentially : conf .ExecuteSequentially ,
122
+ tuple : tuple ,
123
+ unknownToolHandler : conf .UnknownToolsHandler ,
124
+ executeSequentially : conf .ExecuteSequentially ,
125
+ toolArgumentsHandler : conf .ToolArgumentsHandler ,
113
126
}, nil
114
127
}
115
128
@@ -191,7 +204,7 @@ type toolCallTask struct {
191
204
err error
192
205
}
193
206
194
- func (tn * ToolsNode ) genToolCallTasks (tuple * toolsTuple , input * schema.Message , executedTools map [string ]string ) ([]toolCallTask , error ) {
207
+ func (tn * ToolsNode ) genToolCallTasks (ctx context. Context , tuple * toolsTuple , input * schema.Message , executedTools map [string ]string , isStream bool ) ([]toolCallTask , error ) {
195
208
if input .Role != schema .Assistant {
196
209
return nil , fmt .Errorf ("expected message role is Assistant, got %s" , input .Role )
197
210
}
@@ -210,7 +223,11 @@ func (tn *ToolsNode) genToolCallTasks(tuple *toolsTuple, input *schema.Message,
210
223
toolCallTasks [i ].arg = toolCall .Function .Arguments
211
224
toolCallTasks [i ].callID = toolCall .ID
212
225
toolCallTasks [i ].executed = true
213
- toolCallTasks [i ].output = result
226
+ if isStream {
227
+ toolCallTasks [i ].sOutput = schema .StreamReaderFromArray ([]string {result })
228
+ } else {
229
+ toolCallTasks [i ].output = result
230
+ }
214
231
continue
215
232
}
216
233
index , ok := tuple .indexes [toolCall .Function .Name ]
@@ -223,8 +240,16 @@ func (tn *ToolsNode) genToolCallTasks(tuple *toolsTuple, input *schema.Message,
223
240
toolCallTasks [i ].r = tuple .rps [index ]
224
241
toolCallTasks [i ].meta = tuple .meta [index ]
225
242
toolCallTasks [i ].name = toolCall .Function .Name
226
- toolCallTasks [i ].arg = toolCall .Function .Arguments
227
243
toolCallTasks [i ].callID = toolCall .ID
244
+ if tn .toolArgumentsHandler != nil {
245
+ arg , err := tn .toolArgumentsHandler (ctx , toolCall .Function .Name , toolCall .Function .Arguments )
246
+ if err != nil {
247
+ return nil , fmt .Errorf ("failed to executed tool[name:%s arguments:%s] arguments handler: %w" , toolCall .Function .Name , toolCall .Function .Arguments , err )
248
+ }
249
+ toolCallTasks [i ].arg = arg
250
+ } else {
251
+ toolCallTasks [i ].arg = toolCall .Function .Arguments
252
+ }
228
253
}
229
254
}
230
255
@@ -280,6 +305,9 @@ func runToolCallTaskByStream(ctx context.Context, task *toolCallTask, opts ...to
280
305
281
306
func sequentialRunToolCall (ctx context.Context , run func (ctx2 context.Context , callTask * toolCallTask , opts ... tool.Option ), tasks []toolCallTask , opts ... tool.Option ) {
282
307
for i := 0 ; i < len (tasks ); i ++ {
308
+ if tasks [i ].executed {
309
+ continue
310
+ }
283
311
run (ctx , & tasks [i ], opts ... )
284
312
}
285
313
}
@@ -294,6 +322,9 @@ func parallelRunToolCall(ctx context.Context,
294
322
295
323
var wg sync.WaitGroup
296
324
for i := 1 ; i < len (tasks ); i ++ {
325
+ if tasks [i ].executed {
326
+ continue
327
+ }
297
328
wg .Add (1 )
298
329
go func (ctx_ context.Context , t * toolCallTask , opts ... tool.Option ) {
299
330
defer wg .Done ()
@@ -326,7 +357,7 @@ func (tn *ToolsNode) Invoke(ctx context.Context, input *schema.Message,
326
357
}
327
358
}
328
359
329
- tasks , err := tn .genToolCallTasks (tuple , input , opt .executedTools )
360
+ tasks , err := tn .genToolCallTasks (ctx , tuple , input , opt .executedTools , false )
330
361
if err != nil {
331
362
return nil , err
332
363
}
@@ -385,7 +416,7 @@ func (tn *ToolsNode) Stream(ctx context.Context, input *schema.Message,
385
416
}
386
417
}
387
418
388
- tasks , err := tn .genToolCallTasks (tuple , input , opt .executedTools )
419
+ tasks , err := tn .genToolCallTasks (ctx , tuple , input , opt .executedTools , true )
389
420
if err != nil {
390
421
return nil , err
391
422
}
0 commit comments