applyBeforeLLMCallTransforms runs every registered [MessageTransform] in chain order, just before the model call and AFTER [LocalRuntime.executeBeforeLLMCallHooks] has approved it. Errors from individual transforms are logged at warn level and the chain continues with the previous slice — a transfor
( ctx context.Context, sess *session.Session, a *agent.Agent, modelID string, msgs []chat.Message, )
| 72 | // agent.Model() from a transform would re-randomize the alloy pick |
| 73 | // and miss the per-tool override. |
| 74 | func (r *LocalRuntime) applyBeforeLLMCallTransforms( |
| 75 | ctx context.Context, |
| 76 | sess *session.Session, |
| 77 | a *agent.Agent, |
| 78 | modelID string, |
| 79 | msgs []chat.Message, |
| 80 | ) []chat.Message { |
| 81 | if len(r.transforms) == 0 { |
| 82 | return msgs |
| 83 | } |
| 84 | in := &hooks.Input{ |
| 85 | SessionID: sess.ID, |
| 86 | AgentName: a.Name(), |
| 87 | ModelID: modelID, |
| 88 | HookEventName: hooks.EventBeforeLLMCall, |
| 89 | Cwd: r.workingDir, |
| 90 | } |
| 91 | for _, t := range r.transforms { |
| 92 | out, err := t.fn(ctx, in, msgs) |
| 93 | if err != nil { |
| 94 | slog.WarnContext(ctx, "Message transform failed; continuing with previous messages", |
| 95 | "transform", t.name, "agent", a.Name(), "error", err) |
| 96 | continue |
| 97 | } |
| 98 | msgs = out |
| 99 | } |
| 100 | return msgs |
| 101 | } |