Files
agentik/IRC-QUESTIONS.md
T
subochev a3581abf84 Bring up :proto protocol + :server (Ktor) + :client (HTTP) modules; wire :server into standalone with EchoProtoAgent
Major additions:

* :proto (KMP submodule) — in-house stateful protocol replacing AG-UI.
  Agent owns conversation transcript; Conversation.events(after) is a live,
  replay-free stream; backfill via Conversation.getMessages(after, offset, limit).
  Each Event carries an Instant date for client-side resume tracking.
  Sealed hierarchies (Content/Message/Event/AgentEvent) annotated @Serializable
  with snake_case @SerialName JSON discriminators so the wire format is
  decoupled from Kotlin class names.

* :server (JVM, Ktor 3.1.3) — REST+SSE facade for Agent.
  Public entry: Route.agentikAgent(agent, path = "/agentik").
  Endpoints: create/list/get/patch/delete conversations, POST messages (202),
  POST interrupt, GET messages, GET conversation events (SSE),
  GET agent events (SSE), GET /health. Custom Instant serializer for
  kotlin.time.Instant registered contextually on agentikJson (ISO-8601,
  ignoreUnknownKeys=true, explicitNulls=false).

* :client (JVM, Ktor HTTP Client + CIO) — mirror of :server returning
  a pw.binom.agentik.proto.Agent backed by HTTP calls. Custom SSE parser
  since ktor-client-sse is not on the 3.1.3 client classpath.

* standalone — EchoProtoAgent (in-memory Agent for :proto), EchoAgent
  (existing AG-UI echo), both mounted on the same Netty embedded server
  on port 8080 (/agui and /agentik); A2A stays on its own CIO engine on
  8081. EchoProtoAgent smoke-tested end-to-end against :server: all 11
  endpoints, including live SSE delivery of StartResponse/AppendText/End
  event triplets and Agent-level Created/Deleted events.

Design notes pinned in:
* agentik/IRC-QUESTIONS.md — closed 13-item checklist for the upcoming
  :irc-server transport (channel = conversation, CTCP for structural
  events, draft/chathistory for backfill, ImageStore side-channel, etc).
* docs/ARCHITECTURE.md — overall layout snapshot.
2026-09-12 01:10:27 +03:00

5.0 KiB
Raw Blame History

IRC-транспорт — открытые вопросы

По мере закрытия отмечаем - N. [x]. Закрытый вопрос остаётся в файле с принятым решением.

    1. История. Принято: новый абстрактный метод suspend fun getLatestMessages(offset: Int, limit: Int): List<Message> в :proto.Conversation (offset = пропустить С КОНЦА, 0 = самые свежие). IRC-сервер не держит своего буфера, на CHATHISTORY дёргает агента. CAP draft/chathistory объявляем.
    1. 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
    1. Interrupt. Упрощение: команды /stop и /interrupt в PRIVMSG (т.е. PRIVMSG #chan :/stop) вызывают Conversation.interrupt(). Если PRIVMSG приходит во время активного размышления — сервер сначала зовёт interrupt(), затем send(content). CTCP-вариант дропаем.
    1. AgentEvent.Created/Deleted/Renamed маппинг. Принято: Created = IRC JOIN-бродкаст; Deleted = KICK самого себя; Renamed = TOPIC #foo :new title.
    1. NICK агента. Принято: параметр в DSL, дефолт "Agent".
    1. Multi-user в канале. Принято: в канале всегда только наш агент и наш пользователь. Других не будет никогда.
    1. Маппинг канал ↔ Conversation. Принято: имя IRC-канала = Conversation.title; Conversation.id = UUID, выдаётся через CTCP AGENTIK id #foo; при переименовании канала id стабилен.
    1. Создание канала. Принято: JOIN #foo → создаём Conversation(title="foo", id=<uuid>). Если уже есть — заходим.
    1. Удаление канала. Принято: PART закрывает сторону клиента; CTCP AGENTIK delete #foo — удаление Conversation-а.
    1. Модуль. Принято: :irc-server, KMP через kotlinx-io. Также модуль содержит HTTP staging-эндпоинт для картинок (см. п.13).
    1. Аутентификация клиента. Принято: без auth, любой может подключиться.
    1. Capabilities (ircv3). Принято: в первом проходе объявляем server-time, message-tags, batch, draft/chathistory. SASL не объявляем (п.11). Остальные CAPs (echo-message, labeled-response, standard-replies, multi-user stuff) добавляем инкрементально.
    1. 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.

Можно кодить.