+ notify := hub.Broadcast
+ if bot != nil {
+ notify = func(event Event) {
+ hub.Broadcast(event)
+ bot.Notify(event)
+ }
+ }
+
+ l, err := start(notify)
+ if err != nil {
+ return errors.Join(err, listener.Close())
+ }
+
+ loops := []*TurnLoop{l}
+ for _, child := range children {
+ loop, err := child.Loop(nil, func(Event) {
+ })
+ if err != nil {
+ return errors.Join(fmt.Errorf("start child %q: %w", child.agent.config.Name, err), listener.Close())
+ }
+
+ loops = append(loops, loop)
+ }
+
+ hub.snapshot = func(ctx context.Context, snapshot func() error) error {
+ return daemonSnapshot(ctx, loops, snapshot)
+ }
+
+ var workers sync.WaitGroup
+
+ childErrors := make([]error, len(children))
+ for i, child := range children {
+ workers.Add(1)
+
+ go func() {
+ defer workers.Done()
+
+ childErrors[i] = daemonRunChild(ctx, loops[i+1], child.schedules)
+ if childErrors[i] != nil {
+ child.logger.Error("child stopped", "err", childErrors[i])
+ }
+
+ cancel()
+ }()
+ }
+
+ workers.Add(2)
+
+ go func() {
+ defer workers.Done()
+
+ hub.Accept(ctx, listener, l)
+ }()
+
+ var whatsappErr error
+
+ go func() {
+ defer workers.Done()
+
+ whatsappErr = whatsapp.Run(ctx, l, notify)
+
+ cancel()
+ }()
+
+ var schedulesErr error
+
+ workers.Add(1)
+
+ go func() {
+ defer workers.Done()
+
+ schedulesErr = schedules.Run(ctx, l)
+
+ cancel()
+ }()
+
+ var botErr error
+
+ if bot != nil {
+ workers.Add(1)
+
+ go func() {
+ defer workers.Done()
+
+ botErr = bot.Run(ctx, l, whatsapp)
+
+ cancel()
+ }()
+ }
+
+ err = l.Run(ctx)
+ if errors.Is(err, context.Canceled) {
+ err = nil
+ }
+
+ cancel()
+
+ err = errors.Join(err, listener.Close())
+
+ hub.CloseAll()
+ workers.Wait()
+
+ return errors.Join(err, whatsappErr, schedulesErr, botErr, errors.Join(childErrors...))