From 2546e43ee27e6c8f883824c489e0127c69eb06d0 Mon Sep 17 00:00:00 2001 From: Enmanuel Date: Thu, 9 Apr 2026 20:13:19 +0000 Subject: [PATCH] refactor: extraer campo sender en Agent para desacoplar envio de mensajes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Añade un campo `sender effects.MatrixSender` al struct Agent que reemplaza las llamadas directas a `a.matrix` para enviar mensajes (sendReply, typing, SendMarkdown en handleTaskEvent). En produccion, sender apunta al mismo *matrix.Client. Esto permite inyectar un spy en tests sin requerir una conexion real a Matrix. El campo `a.matrix` se mantiene para operaciones que no son de envio (SetPresence, Raw, etc.). Co-Authored-By: Claude Opus 4.6 (1M context) --- agents/handler.go | 16 ++++++++-------- agents/runtime.go | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/agents/handler.go b/agents/handler.go index 9eb3d66..c1f83da 100644 --- a/agents/handler.go +++ b/agents/handler.go @@ -29,8 +29,8 @@ func (a *Agent) handleEvent(ctx context.Context, msgCtx decision.MessageContext, a.roomCtx.Set(roomID) if a.cfg.Personality.Behavior.TypingIndicator { - _ = a.matrix.SendTyping(ctx, roomID, true) - defer a.matrix.SendTyping(ctx, roomID, false) + _ = a.sender.SendTyping(ctx, roomID, true) + defer a.sender.SendTyping(ctx, roomID, false) } // ── Command flow ───────────────────────────────────────────────── @@ -233,8 +233,8 @@ func (a *Agent) handleTaskEvent(ctx context.Context, msg bus.AgentMessage) { a.roomCtx.Set(roomID) if a.cfg.Personality.Behavior.TypingIndicator { - _ = a.matrix.SendTyping(ctx, roomID, true) - defer a.matrix.SendTyping(ctx, roomID, false) + _ = a.sender.SendTyping(ctx, roomID, true) + defer a.sender.SendTyping(ctx, roomID, false) } // Build a synthetic MessageContext from the task @@ -261,7 +261,7 @@ func (a *Agent) handleTaskEvent(ctx context.Context, msg bus.AgentMessage) { if rejected { a.logger.Warn("orchestrated task rejected by sanitizer", "task_id", task.TaskID, "sender", task.OriginalSender) - _ = a.matrix.SendMarkdown(ctx, roomID, "El mensaje fue rechazado por el filtro de seguridad.") + _ = a.sender.SendMarkdown(ctx, roomID, "El mensaje fue rechazado por el filtro de seguridad.") return } msgCtx.Content = sanitized @@ -294,7 +294,7 @@ func (a *Agent) handleTaskEvent(ctx context.Context, msg bus.AgentMessage) { } // Send reply to Matrix room - if sendErr := a.matrix.SendMarkdown(ctx, roomID, reply); sendErr != nil { + if sendErr := a.sender.SendMarkdown(ctx, roomID, reply); sendErr != nil { a.logger.Error("failed to send orchestrated reply to Matrix", "err", sendErr) } @@ -321,9 +321,9 @@ func (a *Agent) handleTaskEvent(ctx context.Context, msg bus.AgentMessage) { // If threadID is non-empty, the reply is sent as part of that thread. func (a *Agent) sendReply(ctx context.Context, roomID, eventID, threadID, markdown string) error { if threadID != "" { - return a.matrix.SendThreadMarkdown(ctx, roomID, threadID, eventID, markdown) + return a.sender.SendThreadMarkdown(ctx, roomID, threadID, eventID, markdown) } - return a.matrix.SendReplyMarkdown(ctx, roomID, eventID, markdown) + return a.sender.SendReplyMarkdown(ctx, roomID, eventID, markdown) } // parseSeverity converts a config string to sanitize.Severity. diff --git a/agents/runtime.go b/agents/runtime.go index 43786b7..5df8171 100644 --- a/agents/runtime.go +++ b/agents/runtime.go @@ -49,6 +49,7 @@ type Agent struct { rules []decision.Rule llm coretypes.CompleteFunc // nil when no LLM configured (simple_bot) matrix *matrix.Client + sender effects.MatrixSender // used by sendReply; same object as matrix in production runner *effects.Runner listener *matrix.Listener toolReg *tools.Registry @@ -157,6 +158,7 @@ func New(cfg *config.AgentConfig, rules []decision.Rule, agentACL acl.ACL, logge rules: rules, llm: llmFunc, matrix: matrixClient, + sender: matrixClient, runner: runner, toolReg: toolReg, logger: logger,