feat: respuestas como reply de Matrix + presencia online/offline
Añade soporte para que las respuestas de los bots sean replies nativos de Matrix (m.in_reply_to) en lugar de mensajes sueltos. Los clientes Matrix mostrarán el mensaje original citado. Cambios: - EventID en MessageContext para capturar el ID del evento entrante - InReplyTo en ReplyAction para indicar a qué evento responder - SendReplyMarkdown en el cliente Matrix (shell/matrix/client.go) - Runner usa SendReplyMarkdown cuando InReplyTo está presente - runtime.go pasa InReplyTo en todas las respuestas LLM y comandos - SetPresence online al arrancar, offline al apagar (graceful) No se tocan: herramientas, TUI, configuración de agentes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+18
-6
@@ -285,6 +285,18 @@ func (a *Agent) Run(ctx context.Context) error {
|
||||
"tools", a.toolReg.Names(),
|
||||
)
|
||||
|
||||
// Set presence to online
|
||||
if err := a.matrix.SetPresence(ctx, event.PresenceOnline); err != nil {
|
||||
a.logger.Warn("failed to set presence online", "err", err)
|
||||
}
|
||||
defer func() {
|
||||
// Use background context since ctx is already cancelled at shutdown
|
||||
offlineCtx := context.Background()
|
||||
if err := a.matrix.SetPresence(offlineCtx, event.PresenceOffline); err != nil {
|
||||
a.logger.Warn("failed to set presence offline", "err", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Start bus listener if connected to the orchestration bus
|
||||
if a.agentBus != nil {
|
||||
ch := a.agentBus.Subscribe(bus.AgentID(a.cfg.Agent.ID))
|
||||
@@ -453,14 +465,14 @@ func (a *Agent) handleEvent(ctx context.Context, msgCtx decision.MessageContext,
|
||||
if handler, ok := a.commands[cmdName]; ok {
|
||||
a.logger.Info("command_executed", "command", cmdName)
|
||||
reply := handler(ctx, msgCtx)
|
||||
_ = a.matrix.SendMarkdown(ctx, roomID, reply)
|
||||
_ = a.matrix.SendReplyMarkdown(ctx, roomID, msgCtx.EventID, reply)
|
||||
return
|
||||
}
|
||||
|
||||
// Unknown command — never falls through to rules or LLM
|
||||
a.logger.Info("command_unknown", "command", msgCtx.Command)
|
||||
_ = a.matrix.SendMarkdown(ctx, roomID,
|
||||
fmt.Sprintf("Comando desconocido: !%s. Usa !help para ver comandos disponibles.", msgCtx.Command))
|
||||
_ = a.matrix.SendReplyMarkdown(ctx, roomID, msgCtx.EventID,
|
||||
fmt.Sprintf("Comando desconocido: `!%s`. Usa `!help` para ver comandos disponibles.", msgCtx.Command))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -502,7 +514,7 @@ func (a *Agent) executeActions(ctx context.Context, roomID string, msgCtx decisi
|
||||
a.logger.Warn("LLM action requested but no LLM configured")
|
||||
expanded = append(expanded, decision.Action{
|
||||
Kind: decision.ActionKindReply,
|
||||
Reply: &decision.ReplyAction{Content: "Este bot no tiene LLM configurado."},
|
||||
Reply: &decision.ReplyAction{Content: "Este bot no tiene LLM configurado.", InReplyTo: msgCtx.EventID},
|
||||
})
|
||||
continue
|
||||
}
|
||||
@@ -518,12 +530,12 @@ func (a *Agent) executeActions(ctx context.Context, roomID string, msgCtx decisi
|
||||
a.logger.Error("llm error", "err", err)
|
||||
expanded = append(expanded, decision.Action{
|
||||
Kind: decision.ActionKindReply,
|
||||
Reply: &decision.ReplyAction{Content: "Sorry, I encountered an error."},
|
||||
Reply: &decision.ReplyAction{Content: "Sorry, I encountered an error.", InReplyTo: msgCtx.EventID},
|
||||
})
|
||||
} else {
|
||||
expanded = append(expanded, decision.Action{
|
||||
Kind: decision.ActionKindReply,
|
||||
Reply: &decision.ReplyAction{Content: reply},
|
||||
Reply: &decision.ReplyAction{Content: reply, InReplyTo: msgCtx.EventID},
|
||||
})
|
||||
|
||||
// Memory: append assistant reply after LLM call
|
||||
|
||||
Reference in New Issue
Block a user