# IRC-транспорт — открытые вопросы По мере закрытия отмечаем `- N. [x]`. Закрытый вопрос остаётся в файле с принятым решением. - 1. [x] **История.** Принято: новый абстрактный метод `suspend fun getLatestMessages(offset: Int, limit: Int): List` в `:proto.Conversation` (offset = пропустить С КОНЦА, 0 = самые свежие). IRC-сервер не держит своего буфера, на `CHATHISTORY` дёргает агента. CAP `draft/chathistory` объявляем. - 2. [x] **Tool/Error/Image события — раскладка по IRC.** Принято. Каждый `Event` мапится: - `StartReasoning` → дропаем с провода - `StartResponse(TEXT|IMAGE)` → CTCP `AGENTIK response-start {"type":"text"|"image"}` - `AppendText(body)` → `PRIVMSG #chan :body` - `AppendImage(body, mime)` → через `ImageStore` → CTCP `AGENTIK image {"url":..,"mime":..,"ttl":..}` - `ToolCall` → CTCP `AGENTIK tool-call {json}` - `ToolResult` → CTCP `AGENTIK tool-result {json}` - `Error` → CTCP `AGENTIK error {json}` - `End` → CTCP `AGENTIK end` - `Interrupted` → CTCP `AGENTIK interrupted` - 3. [x] **Interrupt.** **Упрощение:** команды `/stop` и `/interrupt` в `PRIVMSG` (т.е. `PRIVMSG #chan :/stop`) вызывают `Conversation.interrupt()`. Если `PRIVMSG` приходит во время активного размышления — сервер сначала зовёт `interrupt()`, затем `send(content)`. CTCP-вариант дропаем. - 4. [x] **`AgentEvent.Created/Deleted/Renamed` маппинг.** Принято: Created = IRC `JOIN`-бродкаст; Deleted = `KICK` самого себя; Renamed = `TOPIC #foo :new title`. - 5. [x] **NICK агента.** Принято: параметр в DSL, дефолт `"Agent"`. - 6. [x] **Multi-user в канале.** Принято: **в канале всегда только наш агент и наш пользователь. Других не будет никогда.** - 7. [x] **Маппинг канал ↔ Conversation.** Принято: имя IRC-канала = `Conversation.title`; `Conversation.id` = UUID, выдаётся через `CTCP AGENTIK id #foo`; при переименовании канала id стабилен. - 8. [x] **Создание канала.** Принято: `JOIN #foo` → создаём `Conversation(title="foo", id=)`. Если уже есть — заходим. - 9. [x] **Удаление канала.** Принято: `PART` закрывает сторону клиента; `CTCP AGENTIK delete #foo` — удаление Conversation-а. - 10. [x] **Модуль.** Принято: `:irc-server`, KMP через kotlinx-io. Также модуль содержит HTTP staging-эндпоинт для картинок (см. п.13). - 11. [x] **Аутентификация клиента.** Принято: без auth, любой может подключиться. - 12. [x] **Capabilities (ircv3).** Принято: в первом проходе объявляем `server-time`, `message-tags`, `batch`, `draft/chathistory`. SASL не объявляем (п.11). Остальные CAPs (echo-message, labeled-response, standard-replies, multi-user stuff) добавляем инкрементально. - 13. [x] **ImageStore.** Принято: `ImageStore` живёт в `:irc-server`, дефолтная in-memory реализация с **TTL 600 сек**, staging-порт **авто-pick** (0 → свободный). Клиент через IRC картинки **не шлёт** (для этого HTTP `:server`). Конкретную реализацию `ImageStore` пользователь сделает позже сам, в первом проходе — наша in-memory. ## Все вопросы закрыты Итого решений по `:irc-server`: - Модуль `:irc-server`, KMP через kotlinx-io. - Канал IRC = `Conversation` (имя = title, UUID через CTCP `AGENTIK id`). - В канале всегда только 1 пользователь + агент (ник `Agent` по умолчанию). - `Event` → IRC: `PRIVMSG` для текста, CTCP `AGENTIK <имя> {json}` для всего остального. `StartReasoning` дропается. - Interrupt через `/stop` / `/interrupt` в PRIVMSG; входящий PRIVMSG во время размышления = `interrupt()` + `send()`. - История через `CHATHISTORY` (LATEST/BEFORE/BETWEEN/AFTER), сервер не буферизует, дёргает новый `:proto` метод `getLatestMessages(offset, limit)`. - Картинки только agent → client через `ImageStore` + HTTP staging в том же модуле. - CAPs: `server-time`, `message-tags`, `batch`, `draft/chathistory`. Без auth. Можно кодить.