Files
agentik/integrations-telegram/build.gradle.kts
T
subochev 24212a1003 feat(standalone): :integrations-telegram — мост Telegram-чат ↔ agent
Новый модуль :integrations-telegram, опциональный «плагин» для standalone:
  * TelegramBridgeComponent — Component-имплементация, устанавливается
    в agent через agent.install(...) только при заданном
    AGENTIK_TELEGRAM_TOKEN. Нет токена — нет polling'а, classpath не
    содержит pw.binom.telegram.* (factory возвращает AutoCloseable,
    а Component-объект создаётся внутри factory и утекает в
    standalone только через agent-api).
  * Long-polling getUpdates?timeout=N — не webhook, не нужен публичный URL.
  * chatId ↔ ConversationId маппинг в общей SQLite-БД standalone'а
    (таблица tg_chat_map); persistent=true переиспользует conv_id,
    persistent=false — каждый Telegram-message = свежий temp-диалог.
  * Group-чаты и /new стартуют временный диалог, не пишут в мапу.
  * Tool-call показывает «⚙️ обрабатываю…» через sendChatAction(typing)
    по onlineOutbox.onlineEvents.
  * Outbound streaming через editMessageText с guard'ом «message is not
    modified»; End с пустым телом → «(empty response)».
  * Ошибки conv.send — одной строкой в чат, polling не падает.
  * uninstall отменяет scope, polling и stream-джобы корректно
    останавливаются.

Конфиг — через env (AppConfig.fromEnv):
  * AGENTIK_TELEGRAM_TOKEN         (default пусто → модуль не активен)
  * AGENTIK_TELEGRAM_POLLING_TIMEOUT  (default 30s, ок 25–35)
  * AGENTIK_TELEGRAM_PERSISTENT      (default true)

Зависимость: наша in-house либа caffeine-mgn/telegramClient
(pw.binom.telegram:telegramClient:1.0.0-SNAPSHOT из mavenLocal).

standalone/Main.kt:
  * integrationsScope (SupervisorJob + Dispatchers.Default) создаётся
    до server'а; tgClient закрывается shutdown-hook'ом ДО agent.close()
    и integrationsScope.cancel() — порядок важен, иначе polling
    long-poll не прерывается и JVM висит на выходе.

Тесты (8/8 ✅):
  * первый входящий текст → persistent conv + conv.send
  * повтор из того же chat → тот же conv
  * non-persistent → каждый message = новый temp-conv
  * typing-индикатор на каждом сообщении
  * outbound streaming → 3 editMessage подряд
  * End с пустым телом → draft заменяется на «(empty response)»
  * ошибка conv.send → одна строка в чат, polling не падает
  * uninstall → polling остановлен, новые push'и не обрабатываются

standalone/README.md — добавлен раздел «Telegram-интеграция» с env-таблицей,
описанием поведения и инструкцией по включению.
2026-10-05 23:33:57 +03:00

64 lines
3.1 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Telegram-интеграция для :standalone: переносит входящие текстовые
// сообщения Telegram-бота в диалоги [pw.binom.agentik.proto.Agent] и
// стримит ответы агента обратно в чат.
//
// Переиспользуемый модуль (не зависит от :standalone): компонент
// `TelegramBridgeComponent` реализует [pw.binom.agentik.agent.Component]
// и подключается к любому `MutableAgent`. `:standalone` инициализирует
// его при наличии `AGENTIK_TELEGRAM_TOKEN` (см. `AppConfig.IntegrationSection`).
//
// Зависимости:
// - :agent-api — Component / MutableAgent
// - :proto — Agent / Conversation
// - :outbox-api — OnlineEvent / OnlineOutbox (стриминг ответа)
// - :content-api — Content.Text (что шлём в conv.send)
// - :journal-api — DurableEvent.AssistantMessage (для fallback, см.
// TelegramBridgeComponent — когда подписчик на
// onlineOutbox пропустил ход, добираем полный текст
// из durable-события)
// - pw.binom.telegram:telegramClient — KMP-обёртка Bot HTTP API
// (`telegramClient-jvm` уже опубликован в mavenLocal как 1.0.0-SNAPSHOT).
// - ktor-client-cio — HTTP-движок для TelegramClient (KMP).
// - ksqlite — таблица `tg_chat_map` (chat_id ↔ conversation_id).
// - kotlinx-coroutines — ASync-механика поллера и подписчиков.
plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.serialization)
}
kotlin {
jvmToolchain(21)
}
dependencies {
api(project(":agent-api"))
api(project(":proto"))
api(project(":outbox-api"))
implementation(project(":content-api"))
implementation(project(":journal-api"))
// Telegram Bot HTTP API (опубликован локально через publishToMavenLocal
// в /home/subochev/common-projects/WORK/telegramClient — caffeineRepo
// пока не имеет релизов, mavenLocal идёт первым в settings.gradle.kts).
// `implementation`, а не `api`: типы `pw.binom.telegram.*` НЕ должны
// утекать в classpath standalone'а — standalone видит только фабрику
// `createTelegramBridgeComponent` (см. TelegramBridgeComponent.kt).
implementation("pw.binom.telegram:telegramClient:1.0.0-SNAPSHOT")
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.cio)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.ksqlite)
}
dependencies {
testImplementation(libs.kotlin.test)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.kotlinx.coroutines.core)
testImplementation(libs.kotlinx.serialization.json)
}