From da1aca411ac87fa70e6b5793f9534d341ed9352e Mon Sep 17 00:00:00 2001 From: kami Date: Wed, 3 Jun 2026 18:55:57 +0400 Subject: [PATCH] =?UTF-8?q?feat(server):=20Task=203.4=20=E2=80=94=20Server?= =?UTF-8?q?Message.Narration=20+=20DomainEventMapper=20arm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apps/server/bridge/DomainEventMapper.kt | 10 ++++++++++ .../apps/server/protocol/ServerMessage.kt | 12 ++++++++++++ .../protocol/ServerMessageSerializationTest.kt | 18 ++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/apps/server/src/main/kotlin/com/correx/apps/server/bridge/DomainEventMapper.kt b/apps/server/src/main/kotlin/com/correx/apps/server/bridge/DomainEventMapper.kt index 21330750..857b9ac8 100644 --- a/apps/server/src/main/kotlin/com/correx/apps/server/bridge/DomainEventMapper.kt +++ b/apps/server/src/main/kotlin/com/correx/apps/server/bridge/DomainEventMapper.kt @@ -30,6 +30,7 @@ import com.correx.core.events.events.ToolCallAssessedEvent import com.correx.core.events.events.ToolInvocationRequestedEvent import com.correx.core.events.events.TransitionExecutedEvent import com.correx.core.events.events.WorkflowCompletedEvent +import com.correx.core.events.events.RouterNarrationEvent import com.correx.core.events.events.WorkflowFailedEvent import com.correx.core.events.risk.RiskAction import com.correx.core.events.types.ArtifactId @@ -205,6 +206,15 @@ suspend fun domainEventToServerMessage( sequence = seq, sessionSequence = sessionSequence, ) + is RouterNarrationEvent -> ServerMessage.Narration( + sessionId = p.sessionId, + content = p.content, + stageId = p.stageId, + latencyMs = p.latencyMs, + totalTokens = p.tokensUsed?.totalTokens, + sequence = seq, + sessionSequence = sessionSequence, + ) is ArtifactCreatedEvent -> ServerMessage.ArtifactCreated( sessionId = p.sessionId, stageId = p.stageId, diff --git a/apps/server/src/main/kotlin/com/correx/apps/server/protocol/ServerMessage.kt b/apps/server/src/main/kotlin/com/correx/apps/server/protocol/ServerMessage.kt index 9c249ebf..d72241a7 100644 --- a/apps/server/src/main/kotlin/com/correx/apps/server/protocol/ServerMessage.kt +++ b/apps/server/src/main/kotlin/com/correx/apps/server/protocol/ServerMessage.kt @@ -362,6 +362,18 @@ sealed interface ServerMessage { // -- Router -- + @Serializable + @SerialName("router.narration") + data class Narration( + val sessionId: SessionId, + val content: String, + val stageId: String? = null, + val latencyMs: Long? = null, + val totalTokens: Int? = null, + override val sequence: Long, + override val sessionSequence: Long, + ) : ServerMessage, SessionMessage + @Serializable @SerialName("router.response") data class RouterResponseMessage( diff --git a/apps/server/src/test/kotlin/com/correx/apps/server/protocol/ServerMessageSerializationTest.kt b/apps/server/src/test/kotlin/com/correx/apps/server/protocol/ServerMessageSerializationTest.kt index 3fe6336e..b1b66c26 100644 --- a/apps/server/src/test/kotlin/com/correx/apps/server/protocol/ServerMessageSerializationTest.kt +++ b/apps/server/src/test/kotlin/com/correx/apps/server/protocol/ServerMessageSerializationTest.kt @@ -107,6 +107,24 @@ class ServerMessageSerializationTest { assert(jsonStr.contains("\"lastSessionSequence\":15")) { "expected lastSessionSequence=15" } } + @Test + fun `Narration encodes type content stageId latencyMs and totalTokens`() { + val msg = ServerMessage.Narration( + sessionId = SessionId("sess-1"), + content = "moving on", + stageId = "validate", + latencyMs = 2000, + totalTokens = 120, + sequence = 10, + sessionSequence = 5, + ) + val jsonStr = ProtocolSerializer.encodeServerMessage(msg) + assert(jsonStr.contains("\"type\":\"router.narration\"")) { "expected type=router.narration" } + assert(jsonStr.contains("\"content\":\"moving on\"")) { "expected content" } + assert(jsonStr.contains("\"latencyMs\":2000")) { "expected latencyMs=2000" } + assert(jsonStr.contains("\"totalTokens\":120")) { "expected totalTokens=120" } + } + @Test fun `SessionAnnounced round-trips through JSON`() { val original = ServerMessage.SessionAnnounced(