runAgentLoop runs the full agentic loop: stream completions, process tool calls, handle handoffs, and loop until the model says stop or we hit maxIterations.
(ctx context.Context, agentName string, messages []chat.Message)
| 249 | // calls, handle handoffs, and loop until the model says stop or we hit |
| 250 | // maxIterations. |
| 251 | func (rt *wasmRuntime) runAgentLoop(ctx context.Context, agentName string, messages []chat.Message) (map[string]any, error) { |
| 252 | if agentName == "" { |
| 253 | agentName = rt.cfg.Agents[0].Name |
| 254 | } |
| 255 | rt.currentAgent = agentName |
| 256 | |
| 257 | a, ok := rt.agents[rt.currentAgent] |
| 258 | if !ok { |
| 259 | return nil, fmt.Errorf("agent %q not found", rt.currentAgent) |
| 260 | } |
| 261 | |
| 262 | // Prepend system instruction. |
| 263 | if a.Instruction() != "" && (len(messages) == 0 || messages[0].Role != chat.MessageRoleSystem) { |
| 264 | sys := chat.Message{Role: chat.MessageRoleSystem, Content: a.Instruction()} |
| 265 | messages = append([]chat.Message{sys}, messages...) |
| 266 | } |
| 267 | |
| 268 | // Fire session_start hook. |
| 269 | rt.fireHook(ctx, rt.currentAgent, hooks.EventSessionStart, &hooks.Input{}) |
| 270 | |
| 271 | var totalUsage chat.Usage |
| 272 | iteration := 0 |
| 273 | |
| 274 | for iteration < maxIterations { |
| 275 | iteration++ |
| 276 | |
| 277 | if ctx.Err() != nil { |
| 278 | return nil, ctx.Err() |
| 279 | } |
| 280 | |
| 281 | a = rt.agents[rt.currentAgent] |
| 282 | |
| 283 | // Fire turn_start hook. |
| 284 | turnCtx := rt.fireHook(ctx, rt.currentAgent, hooks.EventTurnStart, &hooks.Input{}) |
| 285 | if turnCtx != nil && turnCtx.AdditionalContext != "" { |
| 286 | // Inject context as a transient system message. |
| 287 | ctxMsg := chat.Message{Role: chat.MessageRoleSystem, Content: turnCtx.AdditionalContext} |
| 288 | messages = append(messages, ctxMsg) |
| 289 | } |
| 290 | |
| 291 | // Get tools for this agent. |
| 292 | agentTools, err := a.Tools(ctx) |
| 293 | if err != nil { |
| 294 | slog.WarnContext(ctx, "Failed to get tools", "agent", rt.currentAgent, "error", err) |
| 295 | agentTools = nil |
| 296 | } |
| 297 | |
| 298 | // Add delegation tools if agent has handoffs or sub-agents. |
| 299 | agentTools = rt.addDelegationTools(a, agentTools) |
| 300 | |
| 301 | // Try primary model with fallback chain. |
| 302 | streamResult, err := rt.streamWithFallback(ctx, a, messages, agentTools) |
| 303 | if err != nil { |
| 304 | return nil, fmt.Errorf("model call failed: %w", err) |
| 305 | } |
| 306 | |
| 307 | // Accumulate usage. |
| 308 | if streamResult.usage != nil { |
no test coverage detected