Изменения вводят live-канал OnlineOutbox и фоновую синхронизацию диалогов.
This commit is contained in:
@@ -2,6 +2,8 @@ package pw.binom.agentik.proto
|
||||
|
||||
import pw.binom.agentik.journal.ConversationStore
|
||||
import pw.binom.agentik.journal.JournalStore
|
||||
import pw.binom.agentik.outbox.OnlineEvent
|
||||
import pw.binom.agentik.outbox.OnlineOutbox
|
||||
import pw.binom.agentik.outbox.OutboxStore
|
||||
import kotlin.time.Instant
|
||||
|
||||
@@ -12,9 +14,10 @@ import kotlin.time.Instant
|
||||
* [createConversation] возвращает [Conversation], который сам хранит историю
|
||||
* и которому отправляют ходы через [Conversation.send].
|
||||
*
|
||||
* **Хранилища вынесены в [Agent.journal], [Agent.outbox] и
|
||||
* [Agent.conversationStore]**: все три read-only views. События живут
|
||||
* в [outbox] как `OutboxStore.events(after)` / `outbox.agentEvents(after)`.
|
||||
* **Хранилища вынесены в [Agent.journal], [Agent.outbox],
|
||||
* [Agent.onlineOutbox] и [Agent.conversationStore]**: read-only views.
|
||||
* Durable-события живут в [outbox] как `OutboxStore.events(after)` /
|
||||
* `outbox.agentEvents(after)`; live-стриминг ответа — в [onlineOutbox].
|
||||
* Это даёт единый путь для всех read-операций по хранилищу и убирает
|
||||
* дублирование между протоколом и хранилищем.
|
||||
*
|
||||
@@ -83,6 +86,24 @@ interface Agent : AutoCloseable {
|
||||
*/
|
||||
val outbox: OutboxStore
|
||||
|
||||
/**
|
||||
* Live-канал **онлайн-событий** ([OnlineEvent] — стриминг ответа агента).
|
||||
*
|
||||
* Отделён от [outbox] принципиально:
|
||||
* - [outbox] — durable: «целые» события, перезапрашиваемые по курсору
|
||||
* (`after`), с catchup + live;
|
||||
* - [onlineOutbox] — live-only: дельты токенов, **никогда не сохраняются**,
|
||||
* без catchup/курсора, подписка работает только «онлайн».
|
||||
*
|
||||
* Используется HTTP-фасадом `:server` для endpoint'а
|
||||
* `GET /{path}/conversations/{id}/online` (SSE). Клиент рендерит ответ
|
||||
* из этого потока в реальном времени, а durable-историю берёт из [journal].
|
||||
*
|
||||
* **Read-only**: write-доступ только через `MutableOnlineOutbox` внутри
|
||||
* ChatAgent / ConversationLoop, не через [Agent] interface.
|
||||
*/
|
||||
val onlineOutbox: OnlineOutbox
|
||||
|
||||
/**
|
||||
* Read-only view на `conversation` table (id + title + timestamps).
|
||||
*
|
||||
|
||||
@@ -9,15 +9,21 @@ import kotlin.time.Instant
|
||||
* [send] агенту не нужно пересылать транскрипт — он уже живёт внутри
|
||||
* [Conversation].
|
||||
*
|
||||
* **Live-события** диалога (turn stream: StartReasoning / AppendText / End /
|
||||
* ToolCall / ToolResult / ...) НЕ часть этого интерфейса — единственный
|
||||
* источник live-событий это [pw.binom.agentik.outbox.OutboxStore].
|
||||
* Подписаться на события конкретного диалога:
|
||||
* ```
|
||||
* agent.outbox.conversationEvents(after = lastSeen, conversationId = id)
|
||||
* .map { it.event }
|
||||
* .collect { e -> ... }
|
||||
* ```
|
||||
* **Live-события** диалога НЕ часть этого интерфейса. Их два независимых
|
||||
* потока:
|
||||
* - **durable** ([pw.binom.agentik.outbox.Event]: Working / End / Interrupted /
|
||||
* Error / ToolCall / ToolResult / ToolFailed) — из
|
||||
* [pw.binom.agentik.outbox.OutboxStore], перезапрашивается по курсору:
|
||||
* ```
|
||||
* agent.outbox.conversationEvents(after = lastSeen, conversationId = id)
|
||||
* .map { it.event }
|
||||
* .collect { e -> ... }
|
||||
* ```
|
||||
* - **online** ([pw.binom.agentik.outbox.OnlineEvent]: StartReasoning /
|
||||
* StartResponse / AppendText / AppendImage) — live-only стриминг ответа
|
||||
* из [pw.binom.agentik.outbox.OnlineOutbox], без catchup/курсора:
|
||||
* `agent.onlineOutbox.onlineEvents(id)`.
|
||||
*
|
||||
* Для cross-conversation view (admin / parent-agent / debug):
|
||||
* `agent.outbox.events(after)`. Для lifecycle агента (created/deleted/renamed):
|
||||
* `agent.outbox.agentEvents(after)`.
|
||||
|
||||
Reference in New Issue
Block a user