feat: implement multi-bot orchestration system with LLM routing
Implementa el sistema de orquestación para salas Matrix con múltiples bots. El orquestador es un "special agent" sin identidad Matrix que coordina qué bot responde y cuándo, usando LLM (Claude) para routing y evaluación de calidad. Cambios principales: - pkg/orchestration/task.go: tipos puros (TaskEvent, BotResponse, QualityScore, RoutingDecision) - shell/orchestration/: runtime del orquestador (orchestrator.go, router.go, evaluator.go) - agents/specials/orchestrator/: config + prompts (routing, quality, refinement) - internal/config/: SpecialConfig, OrchestrationCfg, LoadSpecial() - shell/bus/bus.go: protocolo request-reply (SendAndWait, Reply) para delegación - shell/matrix/listener.go: InterceptFunc para interceptar eventos en salas orquestadas - agents/runtime.go: SetBus, listenBus, handleTaskEvent para recibir tareas del orquestador - cmd/launcher/main.go: creación de bus compartido, arranque del orquestador antes de bots Incluye deduplicación para evitar que múltiples listeners en la misma sala disparen el orquestador más de una vez por mensaje. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,14 +18,20 @@ import (
|
||||
// EventHandler is called for each incoming Matrix message that passes filters.
|
||||
type EventHandler func(ctx context.Context, msgCtx decision.MessageContext, evt *event.Event)
|
||||
|
||||
// InterceptFunc is called for events in orchestrated rooms.
|
||||
// It receives the parsed MessageContext. If it returns true, the event is not
|
||||
// delivered to the bot's normal handler (the orchestrator handles it instead).
|
||||
type InterceptFunc func(ctx context.Context, msgCtx decision.MessageContext) bool
|
||||
|
||||
// Listener attaches to a mautrix syncer and dispatches events to an EventHandler.
|
||||
type Listener struct {
|
||||
client *Client
|
||||
cfg config.MatrixCfg
|
||||
handler EventHandler
|
||||
logger *slog.Logger
|
||||
dmCache map[id.RoomID]bool
|
||||
mu sync.RWMutex
|
||||
client *Client
|
||||
cfg config.MatrixCfg
|
||||
handler EventHandler
|
||||
logger *slog.Logger
|
||||
dmCache map[id.RoomID]bool
|
||||
mu sync.RWMutex
|
||||
interceptor InterceptFunc // if set and returns true, event is forwarded to orchestrator
|
||||
}
|
||||
|
||||
// NewListener creates a Listener for the given client.
|
||||
@@ -39,6 +45,13 @@ func NewListener(client *Client, cfg config.MatrixCfg, handler EventHandler, log
|
||||
}
|
||||
}
|
||||
|
||||
// SetInterceptor registers a function that can intercept event delivery.
|
||||
// If the function returns true, the event is handled by the orchestrator
|
||||
// and not delivered to the bot's normal handler.
|
||||
func (l *Listener) SetInterceptor(fn InterceptFunc) {
|
||||
l.interceptor = fn
|
||||
}
|
||||
|
||||
// Run starts the Matrix sync loop. Blocks until ctx is cancelled.
|
||||
func (l *Listener) Run(ctx context.Context) error {
|
||||
syncer := l.client.raw.Syncer.(*mautrix.DefaultSyncer)
|
||||
@@ -112,6 +125,13 @@ func (l *Listener) Run(ctx context.Context) error {
|
||||
"content_preview", truncate(msgCtx.Content, 80),
|
||||
)
|
||||
|
||||
// Orchestrator intercept: if this room is managed, the orchestrator
|
||||
// handles routing instead of the bot's normal handler.
|
||||
if l.interceptor != nil && l.interceptor(ctx, msgCtx) {
|
||||
l.logger.Debug("event intercepted by orchestrator", "room", evt.RoomID)
|
||||
return
|
||||
}
|
||||
|
||||
go l.handler(ctx, msgCtx, evt)
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user