refactor(protocol): add toolName to ToolResult, remove proto typealiases, rename id→toolCallId, drop Conversation.events()
Three protocol-level changes from Android-client review (items 1-3, 5-6):
1) toolName denormalization in ToolResult (3 layers):
- :outbox-api/Event.ToolResult: +toolName: String? = null
- :journal-api/MessageRecord.ToolResult: +toolName: String? = null
- :proto/Message.ToolResult: +toolName: String? = null
- :storage-ksqlite, :journal-ksqlite ResultPayload codec: +toolName
- :standalone/ToolDispatcher, ConversationLoop: thread toolName = call.name
Nullable + default = backward-compat for already-persisted histories
and existing clients.
2) Drop proto/Event.kt, AgentEvent.kt, CommonEvent.kt typealiases.
is proto.Event.End failed with 'Unresolved reference End' (alias
loses nested-class access). Use pw.binom.agentik.outbox.{Event,
AgentEvent, CommonEvent} directly everywhere — :proto already has
api(:outbox-api), the package is visible to consumers, no shim
needed. 21 files rewired, 3 files deleted.
3) Rename Event.ToolResult.id → toolCallId (option B per user).
In :outbox-api Event.ToolResult.id == Event.ToolCall.id (one value,
one name); the persistent journal keeps MessageRecord.ToolResult.id
as its own PK + toolCallId as FK to the call — different semantics,
left untouched. Fixed ToolDispatcher bug: emitted id = resultId
while KDoc claimed id == ToolCall.id; now emits toolCallId = callId.
4) Remove Conversation.events() from :proto; OutboxStore is sole event source.
Conversation is a pure per-conversation abstraction (send/getMessages/
rename/close). Live events only via agent.outbox.conversationEvents/
agentEvents/events. HTTP route /conversations/{id}/events stays for
wire-compat but routes through outbox internally (map { it.event }).
jvmTest green (95 tasks).
This commit is contained in:
@@ -14,9 +14,9 @@ import kotlin.time.Instant
|
||||
* идентична `OutboxStore.events`: поток **не реплеит** прошлое, для бэкфилла
|
||||
* используются `Agent.getConversations` / `getConversation`.
|
||||
*
|
||||
* **История**: раньше жил в `:proto` (как `pw.binom.agentik.proto.AgentEvent`).
|
||||
* После миграции в `:outbox-api` — `:proto.AgentEvent` стал typealias'ом,
|
||||
* backward-compat для существующих импортов сохранён.
|
||||
* **История**: до 2026-09-21 жил в `:proto` как `pw.binom.agentik.proto.AgentEvent`;
|
||||
* typealias удалён 2026-09-21 (стирал nested-типы в `is`/`when`) — потребители
|
||||
* импортируют напрямую из `pw.binom.agentik.outbox.AgentEvent`.
|
||||
*/
|
||||
@Serializable
|
||||
sealed interface AgentEvent {
|
||||
|
||||
@@ -9,17 +9,17 @@ import kotlinx.serialization.Serializable
|
||||
*
|
||||
* Useful for admin dashboards, debug tools, parent agents: one subscription
|
||||
* instead of N+1. For regular UI use two separate SSE feeds
|
||||
* ([AgentEvent] via `/events` и `Event` via `/conversations/{id}/events`);
|
||||
* ([AgentEvent] via `/events` и [Event] via `/conversations/{id}/events`);
|
||||
* [CommonEvent] — for those who need everything in one place.
|
||||
*
|
||||
* Server endpoint: `GET /events/all` (SSE), or replay via `OutboxStore.events(after)`.
|
||||
*
|
||||
* **История**: раньше жил в `:proto` (как `pw.binom.agentik.proto.CommonEvent`).
|
||||
* После миграции в `:outbox-api` — `:proto.CommonEvent` стал typealias'ом,
|
||||
* backward-compat для существующих импортов сохранён. `CommonEvent.Conversation`
|
||||
* ссылается на [Event] (тоже в `:outbox-api` теперь) — раньше был
|
||||
* `pw.binom.agentik.proto.Event`, теперь это `pw.binom.agentik.outbox.Event`
|
||||
* (он тоже typealias-нут в `:proto.Event`).
|
||||
* **История**: до 2026-09-21 жил в `:proto` как `pw.binom.agentik.proto.CommonEvent`;
|
||||
* при миграции в `:outbox-api` был оставлен typealias в `:proto` для backward-compat,
|
||||
* но он стирал nested-типы (`CommonEvent.Agent`, `CommonEvent.Conversation`),
|
||||
* что ломало `is CommonEvent.Agent` на стороне клиента. Typealias'ы
|
||||
* `Event`/`AgentEvent`/`CommonEvent` из `:proto` удалены — потребители
|
||||
* импортируют напрямую из `pw.binom.agentik.outbox.*`.
|
||||
*/
|
||||
@Serializable
|
||||
sealed interface CommonEvent {
|
||||
|
||||
@@ -15,9 +15,12 @@ import kotlin.time.Instant
|
||||
* `StartReasoning?` → `StartResponse(TEXT|IMAGE)` → ...контент... → `End` | `Interrupted` | `Error`.
|
||||
* `StartReasoning` может отсутствовать, если агент не показывал рассуждения.
|
||||
*
|
||||
* **История**: раньше жил в `:proto` (как `pw.binom.agentik.proto.Event`).
|
||||
* После миграции в `:outbox-api` — `:proto.Event` стал typealias'ом,
|
||||
* backward-compat для существующих импортов сохранён.
|
||||
* **История**: до 2026-09-21 жил в `:proto` как `pw.binom.agentik.proto.Event`;
|
||||
* при миграции в `:outbox-api` был оставлен typealias в `:proto` для
|
||||
* backward-compat, но он стирал nested-типы (`Event.End`, `Event.ToolCall`,
|
||||
* `Event.ToolResult`), что ломало `is Event.End` на стороне клиента.
|
||||
* Typealias удалён 2026-09-21 — потребители импортируют напрямую из
|
||||
* `pw.binom.agentik.outbox.Event`.
|
||||
*/
|
||||
@Serializable
|
||||
sealed interface Event {
|
||||
@@ -75,12 +78,26 @@ sealed interface Event {
|
||||
|
||||
/**
|
||||
* Результат вызова тула. Приходит целиком после завершения исполнения.
|
||||
* [id] совпадает с [ToolCall.id], к которому относится результат, и
|
||||
* с id `Message.ToolResult` в истории.
|
||||
*
|
||||
* [toolCallId] = id [ToolCall], к которому относится результат, и
|
||||
* `MessageRecord.ToolResult.toolCallId` в истории. Один Call → один Result,
|
||||
* пара `(date, toolCallId)` уникальна — отдельный `id` в live-событии
|
||||
* не нужен (PK живёт в персистентном журнале).
|
||||
*
|
||||
* [toolName] денормализован из соответствующего [ToolCall.toolName] —
|
||||
* UI рендерит имя тула без локальной `Map<toolCallId, name>` и без риска
|
||||
* «Result пришёл до Call». `null` допустим для backfill'а старых
|
||||
* записей, у которых поле отсутствует, или теоретического случая
|
||||
* Result без предшествующего Call (orphan).
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("tool_result")
|
||||
data class ToolResult(override val date: Instant, val id: String, val result: String?) : Event
|
||||
data class ToolResult(
|
||||
override val date: Instant,
|
||||
val toolCallId: String,
|
||||
val toolName: String? = null,
|
||||
val result: String?,
|
||||
) : Event
|
||||
|
||||
/**
|
||||
* Ошибка хода. После неё поток завершается; дальнейшие события могут
|
||||
|
||||
Reference in New Issue
Block a user