Skip to content

Commit 5de67f6

Browse files
committed
Include title in message events.
1 parent 9652338 commit 5de67f6

File tree

4 files changed

+41
-21
lines changed

4 files changed

+41
-21
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
<groupId>com.embabel.agent</groupId>
1414
<artifactId>embabel-chat-store</artifactId>
15-
<version>0.1.0-SNAPSHOT</version>
15+
<version>0.2.0-SNAPSHOT</version>
1616
<packaging>jar</packaging>
1717
<name>Embabel Chat Store</name>
1818
<description>Chat session storage library for Embabel Agent using Neo4j and Drivine</description>
@@ -194,4 +194,4 @@
194194
</snapshotRepository>
195195
</distributionManagement>
196196

197-
</project>
197+
</project>

src/main/kotlin/com/embabel/chat/event/ConversationEvents.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ enum class MessageStatus {
8585
* @param status the current status of the message
8686
* @param fromUserId the ID of the user who sent this message (author)
8787
* @param toUserId the ID of the user who should receive this message (for routing, e.g., WebSocket)
88+
* @param title the session/conversation title (for UI display)
8889
* @param message the message (always present for ADDED, present for PERSISTED)
8990
* @param content the message content (useful for PERSISTENCE_FAILED when message ref may be stale)
9091
* @param role the message role
@@ -96,6 +97,7 @@ data class MessageEvent(
9697
val status: MessageStatus,
9798
val fromUserId: String? = null,
9899
val toUserId: String? = null,
100+
val title: String? = null,
99101
val message: Message? = null,
100102
val content: String? = null,
101103
val role: Role? = null,
@@ -111,12 +113,14 @@ data class MessageEvent(
111113
conversationId: String,
112114
message: Message,
113115
fromUserId: String? = null,
114-
toUserId: String? = null
116+
toUserId: String? = null,
117+
title: String? = null
115118
) = MessageEvent(
116119
conversationId = conversationId,
117120
status = MessageStatus.ADDED,
118121
fromUserId = fromUserId,
119122
toUserId = toUserId,
123+
title = title,
120124
message = message,
121125
content = message.content,
122126
role = message.role
@@ -129,12 +133,14 @@ data class MessageEvent(
129133
conversationId: String,
130134
message: Message,
131135
fromUserId: String? = null,
132-
toUserId: String? = null
136+
toUserId: String? = null,
137+
title: String? = null
133138
) = MessageEvent(
134139
conversationId = conversationId,
135140
status = MessageStatus.PERSISTED,
136141
fromUserId = fromUserId,
137142
toUserId = toUserId,
143+
title = title,
138144
message = message,
139145
content = message.content,
140146
role = message.role
@@ -149,12 +155,14 @@ data class MessageEvent(
149155
role: Role,
150156
error: Throwable,
151157
fromUserId: String? = null,
152-
toUserId: String? = null
158+
toUserId: String? = null,
159+
title: String? = null
153160
) = MessageEvent(
154161
conversationId = conversationId,
155162
status = MessageStatus.PERSISTENCE_FAILED,
156163
fromUserId = fromUserId,
157164
toUserId = toUserId,
165+
title = title,
158166
content = content,
159167
role = role,
160168
error = error

src/main/kotlin/com/embabel/chat/store/adapter/StoredConversation.kt

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ import java.util.UUID
8383
* @param eventPublisher Spring's event publisher for broadcasting events
8484
* @param user the human user participant (author of USER messages, recipient of ASSISTANT messages)
8585
* @param agent the AI/system user participant (author of ASSISTANT messages, recipient of USER messages)
86+
* @param title the session title (included in events for UI display)
8687
* @param titleGenerator optional generator for auto-generating session title from first message
8788
* @param assetTracker tracker for conversation assets (defaults to in-memory)
8889
* @param scope coroutine scope for async operations (defaults to IO dispatcher with SupervisorJob)
@@ -93,6 +94,7 @@ class StoredConversation(
9394
private val eventPublisher: ApplicationEventPublisher? = null,
9495
private val user: SessionUser? = null,
9596
private val agent: SessionUser? = null,
97+
private var title: String? = null,
9698
private val titleGenerator: TitleGenerator? = null,
9799
override val assetTracker: AssetTracker = InMemoryAssetTracker(),
98100
private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob()),
@@ -190,7 +192,7 @@ class StoredConversation(
190192

191193
// Publish ADDED event synchronously before async persistence
192194
eventPublisher?.publishEvent(
193-
MessageEvent.added(id, message, from?.id, to?.id)
195+
MessageEvent.added(id, message, from?.id, to?.id, title)
194196
)
195197

196198
scope.launch {
@@ -199,21 +201,18 @@ class StoredConversation(
199201
val persistedMessage = updatedSession.messages.last().toMessage()
200202

201203
// Generate title from first message if no title exists
202-
if (isFirstMessage && titleGenerator != null) {
203-
val session = repository.findBySessionId(id).orElse(null)
204-
if (session?.session?.title.isNullOrBlank()) {
205-
try {
206-
val title = titleGenerator.generate(message)
207-
repository.updateSessionTitle(id, title)
208-
logger.debug("Generated title '{}' for session {}", title, id)
209-
} catch (e: Exception) {
210-
logger.warn("Failed to generate title for session {}: {}", id, e.message)
211-
}
204+
if (isFirstMessage && titleGenerator != null && title.isNullOrBlank()) {
205+
try {
206+
title = titleGenerator.generate(message)
207+
repository.updateSessionTitle(id, title!!)
208+
logger.debug("Generated title '{}' for session {}", title, id)
209+
} catch (e: Exception) {
210+
logger.warn("Failed to generate title for session {}: {}", id, e.message)
212211
}
213212
}
214213

215214
eventPublisher?.publishEvent(
216-
MessageEvent.persisted(id, persistedMessage, from?.id, to?.id)
215+
MessageEvent.persisted(id, persistedMessage, from?.id, to?.id, title)
217216
)
218217
logger.debug("Message {} persisted to session {}", messageData.messageId, id)
219218
} catch (e: Exception) {
@@ -225,7 +224,8 @@ class StoredConversation(
225224
role = message.role,
226225
error = e,
227226
fromUserId = from?.id,
228-
toUserId = to?.id
227+
toUserId = to?.id,
228+
title = title
229229
)
230230
)
231231
}

src/main/kotlin/com/embabel/chat/store/adapter/StoredConversationFactory.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,31 @@ class StoredConversationFactory @JvmOverloads constructor(
7777
* @param id the conversation/session ID
7878
* @param user the human user participant
7979
* @param agent the AI/system user participant (optional, can be set later)
80+
* @param title the session title (included in events for UI display)
8081
*/
8182
@JvmOverloads
82-
fun createForParticipants(id: String, user: SessionUser, agent: SessionUser? = null): Conversation {
83-
return createInternal(id, user, agent)
83+
fun createForParticipants(
84+
id: String,
85+
user: SessionUser,
86+
agent: SessionUser? = null,
87+
title: String? = null
88+
): Conversation {
89+
return createInternal(id, user, agent, title)
8490
}
8591

86-
private fun createInternal(id: String, user: SessionUser?, agent: SessionUser?): Conversation {
92+
private fun createInternal(
93+
id: String,
94+
user: SessionUser?,
95+
agent: SessionUser?,
96+
title: String? = null
97+
): Conversation {
8798
return StoredConversation(
8899
id = id,
89100
repository = repository,
90101
eventPublisher = eventPublisher,
91102
user = user,
92103
agent = agent,
104+
title = title,
93105
titleGenerator = titleGenerator,
94106
assetTracker = InMemoryAssetTracker(),
95107
scope = scope

0 commit comments

Comments
 (0)