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