executeTools runs all tool calls concurrently after the stream completes. Results are published via onResult in the original tool-call order after all tools finish, preserving deterministic event ordering for SSE subscribers.
( ctx context.Context, allTools []fantasy.AgentTool, activeTools []string, providerTools []ProviderTool, toolCalls []fantasy.ToolCallContent, metrics *Metrics, logger slog.Logger, provider, model string, builtinToolNames map[string]bool, onResult func(fantasy.ToolResultContent, time.Time), )
| 1153 | // tool-call order after all tools finish, preserving deterministic |
| 1154 | // event ordering for SSE subscribers. |
| 1155 | func executeTools( |
| 1156 | ctx context.Context, |
| 1157 | allTools []fantasy.AgentTool, |
| 1158 | activeTools []string, |
| 1159 | providerTools []ProviderTool, |
| 1160 | toolCalls []fantasy.ToolCallContent, |
| 1161 | metrics *Metrics, |
| 1162 | logger slog.Logger, |
| 1163 | provider, model string, |
| 1164 | builtinToolNames map[string]bool, |
| 1165 | onResult func(fantasy.ToolResultContent, time.Time), |
| 1166 | ) []fantasy.ToolResultContent { |
| 1167 | if len(toolCalls) == 0 { |
| 1168 | return nil |
| 1169 | } |
| 1170 | |
| 1171 | // Filter out provider-executed tool calls. These were |
| 1172 | // handled server-side by the LLM provider (e.g., web |
| 1173 | // search) and their results are already in the stream |
| 1174 | // content. |
| 1175 | localToolCalls := make([]fantasy.ToolCallContent, 0, len(toolCalls)) |
| 1176 | for _, tc := range toolCalls { |
| 1177 | if !tc.ProviderExecuted { |
| 1178 | localToolCalls = append(localToolCalls, tc) |
| 1179 | } |
| 1180 | } |
| 1181 | if len(localToolCalls) == 0 { |
| 1182 | return nil |
| 1183 | } |
| 1184 | |
| 1185 | toolMap := make(map[string]fantasy.AgentTool, len(allTools)) |
| 1186 | for _, t := range allTools { |
| 1187 | toolMap[t.Info().Name] = t |
| 1188 | } |
| 1189 | providerRunnerNames := make(map[string]struct{}, len(providerTools)) |
| 1190 | resultProviderMetadata := make( |
| 1191 | map[string]func(fantasy.ToolResponse) fantasy.ProviderMetadata, |
| 1192 | len(providerTools), |
| 1193 | ) |
| 1194 | // Include runners from provider tools so locally-executed |
| 1195 | // provider tools (e.g. computer use) can be dispatched. |
| 1196 | for _, pt := range providerTools { |
| 1197 | if pt.Runner == nil { |
| 1198 | continue |
| 1199 | } |
| 1200 | |
| 1201 | name := pt.Runner.Info().Name |
| 1202 | toolMap[name] = pt.Runner |
| 1203 | providerRunnerNames[name] = struct{}{} |
| 1204 | if pt.ResultProviderMetadata != nil { |
| 1205 | resultProviderMetadata[name] = pt.ResultProviderMetadata |
| 1206 | } |
| 1207 | } |
| 1208 | |
| 1209 | results := make([]fantasy.ToolResultContent, len(localToolCalls)) |
| 1210 | completedAt := make([]time.Time, len(localToolCalls)) |
| 1211 | var wg sync.WaitGroup |
| 1212 | wg.Add(len(localToolCalls)) |
no test coverage detected