Skip to content

Commit 4600602

Browse files
committed
Use Drivine DSL for user mgmt features.
1 parent d2d4a93 commit 4600602

18 files changed

Lines changed: 198 additions & 92 deletions

pom.xml

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

1919
<properties>
2020
<java.version>21</java.version>
21-
<embabel-agent.version>0.3.1</embabel-agent.version>
21+
<embabel-agent.version>0.3.2-SNAPSHOT</embabel-agent.version>
2222
<kotlin.version>2.2.0</kotlin.version>
2323
</properties>
2424

@@ -46,7 +46,7 @@
4646
<dependency>
4747
<groupId>org.drivine</groupId>
4848
<artifactId>drivine4j-spring-boot-starter</artifactId>
49-
<version>0.0.12</version>
49+
<version>0.0.14</version>
5050
</dependency>
5151

5252

src/main/java/com/embabel/guide/ChatActions.java

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
import com.embabel.agent.rag.tools.TryHyDE;
1111
import com.embabel.chat.Conversation;
1212
import com.embabel.chat.UserMessage;
13-
import com.embabel.guide.domain.DrivineGuideUserRepository;
14-
import com.embabel.guide.domain.GuideUserWithDiscordUserInfo;
15-
import com.embabel.guide.domain.GuideUserWithWebUser;
16-
import com.embabel.guide.domain.HasGuideUserData;
13+
import com.embabel.guide.domain.DiscordUserInfoData;
14+
import com.embabel.guide.domain.GuideUser;
15+
import com.embabel.guide.domain.GuideUserData;
16+
import com.embabel.guide.domain.GuideUserRepository;
1717
import com.embabel.guide.rag.DataManager;
1818
import org.slf4j.Logger;
1919
import org.slf4j.LoggerFactory;
@@ -28,15 +28,15 @@
2828
public class ChatActions {
2929

3030
private final DataManager dataManager;
31-
private final DrivineGuideUserRepository guideUserRepository;
31+
private final GuideUserRepository guideUserRepository;
3232

3333
private final Logger logger = LoggerFactory.getLogger(ChatActions.class);
3434
private final GuideProperties guideProperties;
3535
private final DrivineStore drivineStore;
3636

3737
public ChatActions(
3838
DataManager dataManager,
39-
DrivineGuideUserRepository guideUserRepository,
39+
GuideUserRepository guideUserRepository,
4040
DrivineStore drivineStore,
4141
GuideProperties guideProperties) {
4242
this.dataManager = dataManager;
@@ -45,7 +45,7 @@ public ChatActions(
4545
this.drivineStore = drivineStore;
4646
}
4747

48-
private HasGuideUserData getGuideUser(@Nullable User user) {
48+
private GuideUser getGuideUser(@Nullable User user) {
4949
switch (user) {
5050
case null -> {
5151
logger.warn("user is null: Cannot create or fetch GuideUser");
@@ -54,21 +54,36 @@ private HasGuideUserData getGuideUser(@Nullable User user) {
5454
case DiscordUser du -> {
5555
return guideUserRepository.findByDiscordUserId(du.getId())
5656
.orElseGet(() -> {
57-
var composed = GuideUserWithDiscordUserInfo.fromDiscordUser(du);
58-
var created = guideUserRepository.createWithDiscord(
59-
composed.getGuideUserData(),
60-
composed.getDiscordUserInfo()
57+
var guideUserData = new GuideUserData(
58+
java.util.UUID.randomUUID().toString(),
59+
null,
60+
null
6161
);
62+
var discordInfo = du.getDiscordUser();
63+
var discordUserInfo = new DiscordUserInfoData(
64+
discordInfo.getId(),
65+
discordInfo.getUsername(),
66+
discordInfo.getDiscriminator(),
67+
discordInfo.getDisplayName(),
68+
discordInfo.isBot(),
69+
discordInfo.getAvatarUrl()
70+
);
71+
var created = guideUserRepository.createWithDiscord(guideUserData, discordUserInfo);
6272
logger.info("Created new Discord user: {}", created);
6373
return created;
6474
});
6575
}
66-
case GuideUserWithWebUser wu -> {
67-
return guideUserRepository.findByWebUserId(wu.getWebUser().getId())
68-
.orElseThrow(() -> new RuntimeException("Missing user with id: " + wu.getWebUser().getId()));
69-
}
70-
case HasGuideUserData gu -> {
71-
return gu;
76+
case GuideUser gu -> {
77+
// Already a GuideUser, look it up by ID to ensure we have latest data
78+
if (gu.getWebUser() != null) {
79+
return guideUserRepository.findByWebUserId(gu.getWebUser().getId())
80+
.orElseThrow(() -> new RuntimeException("Missing user with id: " + gu.getWebUser().getId()));
81+
} else if (gu.getDiscordUserInfo() != null) {
82+
return guideUserRepository.findByDiscordUserId(gu.getDiscordUserInfo().getId())
83+
.orElseThrow(() -> new RuntimeException("Missing user with id: " + gu.getDiscordUserInfo().getId()));
84+
} else {
85+
return gu;
86+
}
7287
}
7388
default -> {
7489
throw new RuntimeException("Unknown user type: " + user);
@@ -82,12 +97,22 @@ void respond(
8297
ActionContext context) {
8398
logger.info("Incoming request from user {}", context.user());
8499
// TODO null safety is a problem here
85-
var guideUser = getGuideUser(context.user()).guideUserData();
100+
var guideUser = getGuideUser(context.user());
86101

87-
var persona = guideUser.getPersona() != null ? guideUser.getPersona() : guideProperties.defaultPersona();
102+
var persona = guideUser.getCore().getPersona() != null ? guideUser.getCore().getPersona() : guideProperties.defaultPersona();
88103
var templateModel = new HashMap<String, Object>();
89104

90105
templateModel.put("persona", persona);
106+
107+
// Pass user info to the template for personalization
108+
var userMap = new HashMap<String, Object>();
109+
var displayName = guideUser.getDisplayName();
110+
// Only include display name if it's a real name (not the "Unknown" fallback)
111+
if (!"Unknown".equals(displayName)) {
112+
userMap.put("displayName", displayName);
113+
}
114+
userMap.put("customPersona", guideUser.getCore().getCustomPrompt());
115+
templateModel.put("user", userMap);
91116
var assistantMessage = context
92117
.ai()
93118
.withLlm(guideProperties.chatLlm())

src/main/java/com/embabel/guide/GuideProperties.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public record GuideProperties(
3636
@NotNull
3737
@NotBlank(message = "projectsPath must not be blank")
3838
String projectsPath,
39-
@NestedConfigurationProperty ContentChunker.DefaultConfig chunkerConfig,
39+
@NestedConfigurationProperty ContentChunker.Config chunkerConfig,
4040
@DefaultValue("references.yml")
4141
@NotBlank(message = "referencesFile must not be blank")
4242
String referencesFile,

src/main/java/com/embabel/guide/rag/DataManager.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.embabel.agent.api.common.reference.LlmReferenceProviders;
55
import com.embabel.agent.api.identity.User;
66
import com.embabel.agent.rag.ingestion.*;
7+
import com.embabel.agent.rag.ingestion.policy.UrlSpecificContentRefreshPolicy;
78
import com.embabel.agent.rag.neo.drivine.DrivineStore;
89
import com.embabel.agent.tools.file.FileTools;
910
import com.embabel.guide.GuideProperties;
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2024-2025 Embabel Software, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.embabel.guide.rag;
17+
18+
import com.embabel.agent.rag.ingestion.ChunkTransformer;
19+
import com.embabel.agent.rag.ingestion.ContentChunker;
20+
import com.embabel.agent.rag.neo.drivine.DrivineCypherSearch;
21+
import com.embabel.agent.rag.neo.drivine.DrivineStore;
22+
import com.embabel.agent.rag.neo.drivine.NeoRagServiceProperties;
23+
import com.embabel.common.ai.model.EmbeddingService;
24+
import com.embabel.common.ai.model.ModelProvider;
25+
import com.embabel.common.ai.model.ModelSelectionCriteria;
26+
import com.embabel.guide.GuideProperties;
27+
import org.drivine.manager.PersistenceManager;
28+
import org.springframework.beans.factory.annotation.Qualifier;
29+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
30+
import org.springframework.context.annotation.Bean;
31+
import org.springframework.context.annotation.Configuration;
32+
import org.springframework.context.annotation.Primary;
33+
import org.springframework.transaction.PlatformTransactionManager;
34+
35+
/**
36+
* Configuration for RAG (Retrieval Augmented Generation) components.
37+
* Creates the DrivineStore and related beans for Neo4j-based RAG operations.
38+
*/
39+
@Configuration
40+
@EnableConfigurationProperties(NeoRagServiceProperties.class)
41+
class RagConfiguration {
42+
43+
@Bean
44+
@Primary
45+
EmbeddingService embeddingService(ModelProvider modelProvider) {
46+
return modelProvider.getEmbeddingService(ModelSelectionCriteria.getPlatformDefault());
47+
}
48+
49+
@Bean
50+
ChunkTransformer chunkTransformer() {
51+
return ChunkTransformer.NO_OP;
52+
}
53+
54+
@Bean
55+
@Primary
56+
DrivineStore drivineStore(
57+
@Qualifier("neo") PersistenceManager persistenceManager,
58+
PlatformTransactionManager platformTransactionManager,
59+
EmbeddingService embeddingService,
60+
ChunkTransformer chunkTransformer,
61+
NeoRagServiceProperties neoRagProperties,
62+
GuideProperties guideProperties) {
63+
var chunkerConfig = guideProperties.chunkerConfig() != null
64+
? guideProperties.chunkerConfig()
65+
: new ContentChunker.Config();
66+
return new DrivineStore(
67+
persistenceManager,
68+
neoRagProperties,
69+
chunkerConfig,
70+
chunkTransformer,
71+
embeddingService,
72+
platformTransactionManager,
73+
new DrivineCypherSearch(persistenceManager)
74+
);
75+
}
76+
}

src/main/kotlin/com/embabel/guide/chat/listener/WebSocketConnectionListener.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.embabel.guide.chat.listener
22

33
import com.embabel.guide.chat.service.JesseService
4-
import com.embabel.guide.domain.DrivineGuideUserRepository
4+
import com.embabel.guide.domain.GuideUserRepository
55
import org.slf4j.LoggerFactory
66
import org.springframework.context.event.EventListener
77
import org.springframework.messaging.simp.stomp.StompHeaderAccessor
@@ -14,7 +14,7 @@ import org.springframework.web.socket.messaging.SessionConnectedEvent
1414
@Component
1515
class WebSocketConnectionListener(
1616
private val jesseService: JesseService,
17-
private val guideUserRepository: DrivineGuideUserRepository
17+
private val guideUserRepository: GuideUserRepository
1818
) {
1919

2020
private val logger = LoggerFactory.getLogger(WebSocketConnectionListener::class.java)

src/main/kotlin/com/embabel/guide/chat/security/AnonymousPrincipalHandshakeHandler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class AnonymousPrincipalHandshakeHandler(
5050
return object : Principal {
5151
private val user = guideUserService.findOrCreateAnonymousWebUser()
5252

53-
override fun getName(): String = user.webUser.id
53+
override fun getName(): String = user.webUser?.id ?: user.id
5454
}
5555
}
5656

src/main/kotlin/com/embabel/guide/chat/service/GuideRagServiceAdapter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import com.embabel.chat.AssistantMessage
55
import com.embabel.chat.ChatSession
66
import com.embabel.chat.Chatbot
77
import com.embabel.chat.UserMessage
8-
import com.embabel.guide.domain.DrivineGuideUserRepository
8+
import com.embabel.guide.domain.GuideUserRepository
99
import kotlinx.coroutines.Dispatchers
1010
import kotlinx.coroutines.delay
1111
import kotlinx.coroutines.withContext
@@ -28,7 +28,7 @@ import java.util.concurrent.ConcurrentHashMap
2828
)
2929
class GuideRagServiceAdapter(
3030
private val chatbot: Chatbot,
31-
private val guideUserRepository: DrivineGuideUserRepository
31+
private val guideUserRepository: GuideUserRepository
3232
) : RagServiceAdapter {
3333

3434
private val logger = LoggerFactory.getLogger(GuideRagServiceAdapter::class.java)

src/main/kotlin/com/embabel/guide/domain/AnonymousGuideUser.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ data class AnonymousGuideUser(
2525
core = core,
2626
webUser = webUser
2727
)
28-
}
28+
}

src/main/kotlin/com/embabel/guide/domain/GraphObjectGuideUserRepository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import java.util.Optional
1313
*/
1414
@Repository
1515
class GraphObjectGuideUserRepository(
16-
@Qualifier("neoGraphObjectManager") private val graphObjectManager: GraphObjectManager
16+
@param:Qualifier("neoGraphObjectManager") private val graphObjectManager: GraphObjectManager
1717
) : GuideUserRepository {
1818

1919
@Transactional(readOnly = true)

0 commit comments

Comments
 (0)