- agent, err := openAgent(filepath.Join(dir, agentDirName))
- if err != nil {
- return err
- }
-
- client := newClient(address, auth, agent.CacheKey(), filepath.Join(agent.dir, "usage.jsonl"))
- memory, err := openMemory(ctx, agent.dir, time.Now, newCompactor(client, agent.Prompt, config.Compactor))
- if err != nil {
- return err
- }
-
- defer func() {
- err = errors.Join(err, memory.Close())
- }()
-
- listener, err := listenSocket(socket)
- if err != nil {
- return err
- }
-
- _, err = fmt.Fprintf(out, "onechat: %s on %s, %s at %s effort, in %s\n", agent.config.Name, listener.Addr(), agent.config.Model, agent.config.Effort, agent.config.Workdir)
- if err != nil {
- return errors.Join(err, listener.Close())
- }
-
- var telegram *TelegramBot
- if hasBot {
- telegram = newTelegramBot(newTelegramAPI(telegramAPIURL, botSettings.Token), botSettings.Owner, filepath.Join(agent.dir, telegramOffsetFileName), log.New(out, "telegram: ", log.LstdFlags))
- _, err = fmt.Fprintln(out, "onechat: the Telegram bot waits for messages of its owner")
- if err != nil {
- return errors.Join(err, listener.Close())
- }
- }
-
- return serveAgent(ctx, listener, telegram, func(notify func(Event)) (*loop, error) {
- return newLoop(agent, memory, client, time.Now, notify)
- })
-}
-
-// serveAgent runs the loop that start makes and serves the clients of
-// listener until ctx ends or the loop fails. It closes listener. When bot is
-// not nil, it runs the bot too, and a failure of the bot stops the agent.
-func serveAgent(ctx context.Context, listener net.Listener, bot *TelegramBot, start func(notify func(Event)) (*loop, error)) error {
- ctx, cancel := context.WithCancel(ctx)
- defer cancel()
-
- hub := &hub{
- clients: make(map[*hubClient]bool),
- }
-
- 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())
- }
-
- var workers sync.WaitGroup
- workers.Add(1)
- go func() {
- defer workers.Done()
-
- hub.Accept(ctx, listener, l)
- }()
-
- var botErr error
- if bot != nil {
- workers.Add(1)
- go func() {
- defer workers.Done()
-
- botErr = bot.Run(ctx, l)
- 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, botErr)
-}
-
-// hub holds the connected clients and sends each event to all of them.
-type hub struct {