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:
+13
-3
@@ -30,7 +30,7 @@ internal fun encodeRecord(record: MessageRecord): Pair<String, String> = when (r
|
||||
)
|
||||
is MessageRecord.ToolResult -> "tool_result" to Json.encodeToString(
|
||||
ResultPayload.serializer(),
|
||||
ResultPayload(toolCallId = record.toolCallId, result = record.result),
|
||||
ResultPayload(toolCallId = record.toolCallId, toolName = record.toolName, result = record.result),
|
||||
)
|
||||
is MessageRecord.Error -> "error" to Json.encodeToString(
|
||||
ErrorPayload.serializer(),
|
||||
@@ -59,7 +59,7 @@ internal fun SQLiteResultSet.toMessageRecord(json: Json): MessageRecord {
|
||||
}
|
||||
"tool_result" -> {
|
||||
val p = Json.decodeFromString(ResultPayload.serializer(), payload)
|
||||
MessageRecord.ToolResult(id = id, conversationId = convId, toolCallId = p.toolCallId, result = p.result, createdAt = createdAt)
|
||||
MessageRecord.ToolResult(id = id, conversationId = convId, toolCallId = p.toolCallId, toolName = p.toolName, result = p.result, createdAt = createdAt)
|
||||
}
|
||||
"error" -> {
|
||||
val p = Json.decodeFromString(ErrorPayload.serializer(), payload)
|
||||
@@ -72,8 +72,18 @@ internal fun SQLiteResultSet.toMessageRecord(json: Json): MessageRecord {
|
||||
@kotlinx.serialization.Serializable
|
||||
internal data class CallPayload(val name: String, val title: String?, val argsJson: String)
|
||||
|
||||
/**
|
||||
* Тулрезалт-сериализация для SQLite. [toolName] денормализован из
|
||||
* соответствующего `ToolCall.name` для упрощения UI (нет нужды в
|
||||
* локальной `Map<id, name>`). Nullable с дефолтом — старые записи
|
||||
* без поля десериализуются как `null`.
|
||||
*/
|
||||
@kotlinx.serialization.Serializable
|
||||
internal data class ResultPayload(val toolCallId: String, val result: String?)
|
||||
internal data class ResultPayload(
|
||||
val toolCallId: String,
|
||||
val toolName: String? = null,
|
||||
val result: String?,
|
||||
)
|
||||
|
||||
@kotlinx.serialization.Serializable
|
||||
internal data class ErrorPayload(val message: String, val code: String?)
|
||||
|
||||
Reference in New Issue
Block a user