Skip to content

# 14 — Messenger Agent Module (MicroDAO)

Агентське переосмислення месенджера

Цей документ описує, як класичний "месенджер" (Telegram/WhatsApp-подібний інтерфейс) реалізований у MicroDAO як агент-модуль, а не просто список чатів.

# 1. Ідея

Замість "голої" стрічки чатів у MicroDAO є:

- Agent Messenger — підагент всередині microDAO, який:

- знає про всі чати, канали, DM;

- вміє показувати потрібні розмови за запитом користувача;

- вміє сам пропонувати релевантні чати;

- інтегрований з памʼяттю (13) і runtime (12);

- може працювати як "голосовий/текстовий UI" поверх звичайного месенджера.

Класичні фічі месенджера (чати, канали, DM, статуси, непрочитані, пошук) — описані як спроможності агента, а не просто як UI.

# 2. Ролі агентів у модулі месенджера

## 2.1. Messenger Agent (core)

Роль: `"messenger_core"` (може бути профіль Team Assistant або окремий агент).

Він:

- знає структуру:

- `teams` (microDAO),

- `channels` (публічні/приватні),

- `direct messages`,

- `threads` (якщо ввімкнено),

- має доступ до:

- списку чатів,

- їхнього стану (непрочитані, muted, pinned),

- історії повідомлень (через Messaging Service / Memory).

## 2.2. User-Facing Agent (асистент користувача)

Користувач взаємодіє не з "меню чатів", а з агентом:

- "Покажи мені всі непрочитані по проекту X"

- "Знайди переписку, де ми обговорювали токеноміку"

- "Підготуй резюме сьогоднішнього дня по всіх каналах"

User-facing агент делегує запити Messenger Agent'у.

# 3. Функціональні спроможності Messenger Agent

## 3.1. Базові (класичний месенджер)

Під капотом елевантні фічі:

- Список каналів і чатів:

- публічні канали,

- приватні канали,

- особисті чати (DM),

- системні / службові.

- Стани:

- `unread_count`,

- `muted`,

- `pinned`,

- `last_message` + `last_activity_at`.

- Повідомлення:

- текст,

- посилання,

- (пізніше) вкладення,

- реакції (on/off для MVP).

- Системні події:

- додавання/видалення учасників,

- зміна назви/іконки,

- інвайти.

Це реалізується Messaging Service (див. 02/03/04), але доступно агенту як "інструменти".

## 3.2. Розширені (агентські)

Messenger Agent вміє:

1. Фільтрувати чати:

2. за проектом,

3. за учасником,

4. за темою (через пошук + RAG).

5. Будувати "розумні папки":

6. "Сьогоднішні важливі розмови",

7. "Все, де тебе тегнули",

8. "Все, що стосується токеноміки/DAO".

9. Проводити огляди:

10. "Зроби щоденний дайджест по всіх каналах",

11. "Поясни, що змінилось з учора".

12. Автоматично створювати follow-ups / задачі:

13. над певними патернами (наприклад, "зробимо", "потрібно", "до пʼятниці").

# 4. Інтерфейс з точки зору користувача

### 4.1. Класичний UI (sidebar + список чатів)

Звичайний sidebar:

- Канали,

- DM,

- Папки/фільтри (Unread, Mentions, Starred).

Але поверх нього — агентське поле запиту:

> "Напиши, що ти хочеш побачити"
> (input зверху або окремий Agent Chat).

Приклади:

- "Покажи тільки непрочитані в робочих каналах"

- "Відфільтруй чати, де обговорюється MicroDAO MVP"

- "Покажи останні 10 повідомлень від Марії"

Агент відповідає:

- або у вигляді пояснювальної репліки;

- або оновлює UI (відкриває/фільтрує потрібні чати).

### 4.2. Повністю агентський режим

У майбутньому можливо:

- взагалі без списку чатів;

- користувач спілкується з агентом:

> "Що важливого в команді за сьогодні?"
> "Покажи діалог з Ігорем, де ми обговорювали бюджети."
> "Знайди канал, де ми домовлялись про токеноміку."

# 5. Інтеграція з Agent Runtime Core (12)

Messenger Agent описується як звичайний агент:

    const messengerAgentConfig: AgentConfig = {
      id: "ag_messenger_core",
      teamId: "t_...",
      name: "Messenger Core",
      role: "team_assistant",
      systemPrompt: systemMessengerPrompt,
      memoryScope: "team",
      tools: [
        "list_channels",
        "list_unread",
        "search_messages",
        "open_channel",
        "get_daily_digest",
        "create_followup_from_message"
      ],
    };

Tools реалізуються через Messaging Service:

    const tools: ToolRegistry = {
      async list_channels(ctx, args) { ... },
      async list_unread(ctx, args) { ... },
      async search_messages(ctx, args) { ... },
      async open_channel(ctx, args) { ... }, // повертає метаданні каналу
      async get_daily_digest(ctx, args) { ... },
    };

Агент runtime (`runAgentTurn`) вирішує:

- чи просто відповісти текстом,

- чи викликати tools,

- чи комбінувати.

# 6. Інтеграція з памʼяттю (13)

Messenger Agent:

- Short-term — поточний контекст каналу/діалогу.

- Long-term — факти:

- які канали важливі для яких людей,

- які теми зʼявляються часто,

- які теги/поняття повʼязані з якими чатами.

Приклад фактів:

- "Канал #governance використовується для голосувань DAO."

- "Канал #dev-mvp обговорює реалізацію MVP MicroDAO."

Це дозволяє агенту:

- відповідати на питання типу:

- "Де обговорювати зміни в governance?"

- пропонувати:

- "Здається, обговорення токеноміки краще перенести в #tokenomics."

# 7. Типові сценарії використання

### Сценарій 1 — Новий учасник

Новачок пише агенту:

> "Я щойно приєднався. Де мені почитати, що тут відбувається?"

Messenger Agent:

- знаходить 2–3 ключові канали,

- дає короткі описи,

- пропонує їх відкрити.

### Сценарій 2 — Щоденний огляд

> "Сформуй підсумок за день."

Messenger Agent:

- використовує `get_daily_digest` tool,

- збирає важливі повідомлення/канали,

- створює summary (через LLM),

- відправляє повідомлення у спеціальний канал або в DM.

### Сценарій 3 — Пошук контексту

> "Знайди, де ми домовлялись про дедлайн запуску DAGI."

Messenger Agent:

- шукає в повідомленнях (Meilisearch + RAG),

- показує релевантні уривки,

- пропонує створити follow-up або задачу.

# 8. Взаємодія з іншими агентами

- Team Assistant може делегувати складні запити Messenger Agent'у.

- Evolution Meta-Agent аналізує:

- які канали важливі;

- які патерни запитів до Messenger Agent'а повторюються;

- які нові "розумні фільтри" варто запропонувати.

# 9. Реалізація Tools

## 9.1. list_channels

    async function list_channels(
      ctx: AgentContext,
      args: { filter?: "public" | "private" | "all"; projectId?: string }
    ): Promise<Channel[]> {
      const channels = await db.channels.findMany({
        where: {
          teamId: ctx.teamId,
          ...(args.filter === "public" && { type: "public" }),
          ...(args.filter === "private" && { type: "group" }),
          ...(args.projectId && { projectId: args.projectId }),
        },
        include: {
          _count: {
            select: { messages: true },
          },
        },
      });

      return channels.map(ch => ({
        id: ch.id,
        name: ch.name,
        type: ch.type,
        description: ch.description,
        messageCount: ch._count.messages,
      }));
    }

## 9.2. list_unread

    async function list_unread(
      ctx: AgentContext,
      args: { userId?: string }
    ): Promise<Array<{ channelId: string; unreadCount: number }>> {
      const userId = args.userId || ctx.userId;

      const unread = await db.userChannelStates.findMany({
        where: {
          userId,
          teamId: ctx.teamId,
          unreadCount: { gt: 0 },
        },
        include: {
          channel: true,
        },
      });

      return unread.map(u => ({
        channelId: u.channelId,
        channelName: u.channel.name,
        unreadCount: u.unreadCount,
        lastMessageAt: u.lastReadAt,
      }));
    }

## 9.3. search_messages

    async function search_messages(
      ctx: AgentContext,
      args: { query: string; channelId?: string; limit?: number }
    ): Promise<Message[]> {
      // Використовуємо Meilisearch для пошуку
      const results = await meilisearchClient
        .index("messages")
        .search(args.query, {
          filter: [
            `teamId = ${ctx.teamId}`,
            ...(args.channelId ? [`channelId = ${args.channelId}`] : []),
          ],
          limit: args.limit || 10,
        });

      return results.hits.map(hit => ({
        id: hit.id,
        channelId: hit.channelId,
        content: hit.content,
        authorId: hit.authorId,
        createdAt: hit.createdAt,
      }));
    }

## 9.4. get_daily_digest

    async function get_daily_digest(
      ctx: AgentContext,
      args: { date?: string; channels?: string[] }
    ): Promise<string> {
      const date = args.date || new Date().toISOString().split("T")[0];
      const startOfDay = new Date(date + "T00:00:00Z");
      const endOfDay = new Date(date + "T23:59:59Z");

      // Збираємо важливі повідомлення за день
      const messages = await db.messages.findMany({
        where: {
          teamId: ctx.teamId,
          createdAt: {
            gte: startOfDay,
            lte: endOfDay,
          },
          ...(args.channels && { channelId: { in: args.channels } }),
        },
        include: {
          author: true,
          channel: true,
        },
        orderBy: { createdAt: "desc" },
        take: 100,
      });

      // Формуємо контекст для LLM
      const context = messages.map(m => ({
        channel: m.channel.name,
        author: m.author.name,
        content: m.content,
        time: m.createdAt,
      }));

      // Викликаємо LLM для створення дайджесту
      const digest = await ctx.llm.complete(ctx, [
        {
          role: "system",
          content: "You are a summarizer. Create a concise daily digest of team communications.",
        },
        {
          role: "user",
          content: JSON.stringify(context),
        },
      ]);

      return digest;
    }

# 10. System Prompt для Messenger Agent

    You are the Messenger Agent for MicroDAO.

    Your role is to help users navigate and interact with channels, messages, and conversations.

    You can:
    - List and filter channels
    - Search for messages and conversations
    - Show unread messages
    - Create daily digests
    - Suggest relevant channels based on topics

    Always be concise and helpful. When a user asks to see something, use the appropriate tools to fetch the data and present it clearly.

    If you don't understand a request, ask for clarification.

# 11. UI Integration

## 11.1. Agent Query Input

Додати поле вводу над списком каналів:

    <AgentQueryInput
      placeholder="Питання до Messenger Agent..."
      onQuery={async (query) => {
        const response = await agentChat(messengerAgentId, [
          { role: "user", content: query },
        ]);

        // Відобразити відповідь або оновити UI
        if (response.action === "filter_channels") {
          setFilteredChannels(response.channels);
        } else {
          showAgentResponse(response.reply);
        }
      }}
    />

## 11.2. Smart Filters

Агент може створювати динамічні фільтри:

    <SmartFilter
      name="Важливі сьогодні"
      query="Покажи канали з непрочитаними повідомленнями за сьогодні"
      onApply={async () => {
        const result = await agentChat(messengerAgentId, [
          { role: "user", content: "Покажи канали з непрочитаними повідомленнями за сьогодні" },
        ]);
        applyFilter(result.channels);
      }}
    />

# 12. Завдання для Cursor

Приклад промта:

    You are a senior full-stack engineer.

    Implement the Messenger Agent module using:

    - 14_messenger_agent_module.md
    - 12_agent_runtime_core.md
    - 13_agent_memory_system.md
    - 03_api_core_snapshot.md
    - 05_coding_standards.md

    Tasks:

    1) Define messengerAgentConfig and register it in the Agents system.

    2) Implement tools:
       - list_channels
       - list_unread
       - search_messages
       - get_daily_digest (stub)

    3) Add Messenger Agent entrypoint in the UI (e.g. "Ask Messenger" input above channel list).

    4) Wire user queries from this input to /agents/{id}/chat using messengerAgentConfig.

    Output:

    - list of modified files
    - diff
    - summary

# 13. Результат

Після впровадження Messenger Agent:

- MicroDAO перестає бути "ще одним месенджером";

- користувач взаємодіє з агентом, а не просто з переліком чатів;

- всі класичні можливості месенджера залишаються, але стають інструментами всередині агентської ОС.

Готово.
Це повна специфікація Messenger Agent модуля, готова до використання в Cursor.