25771a0c33
ci / JVM build + tests (push) Failing after 1m57s
PlantUML diagrams for future agent architecture (Android, multi-user chat, sub-agents, A2A): - 01-module-layers.md — целевая модульная структура - 02-agent-composition.md — AgentBuilder DSL + MemoryBackend.exposesTools() - 03-multi-user-chat.md — mention-detection sequence - 04-sub-agents.md — spawnChild + Flow<SubAgentEvent> + A2A - 05-android-stack.md — что меняется на Android vs Standalone Каждый .md включает пред-рендеренный SVG (показывается во всех markdown viewers без PlantUML plugin) + PlantUML source в code block (для редактирования). SVG нужен потому что PlantUML требует Graphviz dot для рендеринга — без него IntelliJ/VSCode выдают ошибку. Регенерация SVG после правки PlantUML-source: docker run --rm -v "$PWD:/work" plantuml/plantuml -tsvg /work/docs/diagrams/*.md
130 lines
4.8 KiB
Markdown
130 lines
4.8 KiB
Markdown
# 03 — Multi-user chat с mention-detection
|
||
|
||
Точка 1 из планов. Один `BaseAgent` обслуживает N пользователей. Отвечает только когда addressed (mention или admin-команда).
|
||
|
||

|
||
|
||
PlantUML source (для редактирования; требует Graphviz `dot` для рендеринга):
|
||
|
||
```plantuml
|
||
@startuml multi-user-chat
|
||
skinparam componentStyle rectangle
|
||
skinparam participantPadding 15
|
||
skinparam boxPadding 10
|
||
|
||
title Multi-user chat с mention-detection (точка 1 из планов)
|
||
|
||
' --- Участники ---
|
||
actor "User A" as UA
|
||
actor "User B" as UB
|
||
actor "User C\n(админ)" as UC
|
||
participant "Telegram /\nSlack /\nMatrix" as Channel
|
||
participant "AgentRuntime\n(BaseAgent)" as Runtime
|
||
participant "MentionDetector" as Detector
|
||
participant "SoulProvider" as Soul
|
||
participant "MemorySystem\n(MdMemory)" as Memory
|
||
participant "LlmBackend\n(LiteLlm)" as Llm
|
||
|
||
' --- Сценарий ---
|
||
UA -> Channel : "@bot, что нового?"
|
||
UB -> Channel : "люблю котов"
|
||
UC -> Channel : "/bot status"
|
||
Channel -> Runtime : событие чата
|
||
|
||
' --- Внутри Runtime ---
|
||
Runtime -> Detector : isMentioned(message, botName)
|
||
|
||
note right of Detector
|
||
variants:
|
||
- SimpleMentionDetector (regex: @bot)
|
||
- LlmMentionDetector (mini-classifier)
|
||
- AdminCommandDetector (/command)
|
||
end note
|
||
|
||
Detector --> Runtime : MatchResult{isMentioned, isCommand}
|
||
|
||
alt isMentioned или isCommand
|
||
Runtime -> Soul : read()
|
||
Runtime -> Memory : prefetch(query, topK)
|
||
Runtime -> Llm : send(system + history + memory + user)
|
||
Llm --> Runtime : response + tool_calls
|
||
Runtime -> Memory : save(decision)
|
||
Runtime --> Channel : ответ в нужный канал/thread
|
||
else NOT mentioned и NOT command
|
||
Runtime -> Runtime : drop (если не админ)
|
||
note right
|
||
Не отвечаем, но возможно:
|
||
- запоминаем факт (memory-only update)
|
||
- summary на long conversation
|
||
end note
|
||
end
|
||
|
||
@enduml
|
||
```
|
||
|
||
## Ключевые модули (что нужно будет добавить)
|
||
|
||
### `MentionDetector` interface
|
||
|
||
```kotlin
|
||
interface MentionDetector {
|
||
data class Result(
|
||
val isMentioned: Boolean,
|
||
val isAdminCommand: Boolean,
|
||
val isPrivateMessage: Boolean, // DM — всегда отвечаем
|
||
)
|
||
|
||
fun detect(message: ChatMessage, botName: String): Result
|
||
}
|
||
```
|
||
|
||
Имплементации:
|
||
- `SimpleMentionDetector` — regex `@bot`, `/command` (дешёво, latency ~0)
|
||
- `LlmMentionDetector` — маленькая классификация через тот же LLM (точнее, но +1 LLM-вызов на каждое сообщение)
|
||
- `HybridMentionDetector` — fast regex → fallback на LLM только если ambiguous
|
||
|
||
### `ChatAdapter` interface
|
||
|
||
```kotlin
|
||
interface ChatAdapter {
|
||
val channel: String // "telegram" / "slack" / "matrix"
|
||
suspend fun listen(onMessage: (ChatMessage) -> Unit): Job
|
||
suspend fun reply(messageId: String, text: String, threadId: String? = null)
|
||
suspend fun isAdmin(userId: String): Boolean
|
||
}
|
||
```
|
||
|
||
Имплементации per platform. Каждая адаптирует формат platform → `ChatMessage`.
|
||
|
||
### Конфигурация builder'а
|
||
|
||
```kotlin
|
||
agentBuilder {
|
||
llm(...)
|
||
storage(...)
|
||
memory(...)
|
||
soul(...)
|
||
background { ... }
|
||
chat {
|
||
mentionDetector = HybridMentionDetector(regex = "@bot|@Agent", llmClassifier = false)
|
||
chatAdapter = TelegramChatAdapter(token = "...")
|
||
// На каждое сообщение:
|
||
// 1. mentionDetector.detect()
|
||
// 2. если isMentioned || isAdminCommand || isPrivate → process
|
||
// 3. иначе — опционально memory-only save (тихий режим)
|
||
}
|
||
}
|
||
```
|
||
|
||
## Что это даёт
|
||
|
||
- Один `BaseAgent` обслуживает чат целиком (один LLM, одна память — общий контекст команды)
|
||
- `@bot` — explicit invocation, не «agent отвечает на всё подряд»
|
||
- `/bot status` / `/bot clear-memory` — admin-команды (отдельный канал, без LLM)
|
||
- DM — всегда отвечает (это личное обращение)
|
||
- В групповом чате без mention — agent может **молча учить** (memory update без ответа). Полезно для «запомнил что Вася любит котов».
|
||
|
||
## Текущее состояние vs целевое
|
||
|
||
⏳ Ничего из этого нет. Сейчас `:standalone` — это HTTP API, к которому подключаются clients. Для multi-user chat нужен новый `:chat-adapter-telegram` (или -slack / -matrix) модуль + `MentionDetector` interface.
|