Skip to content

Commit 803e184

Browse files
committed
feat(chat): enhance chat handling with history and response tracking
#251 - Modify `MessageView` to expose `message` property. - Update `CustomAgentChatProcessor` to return LLM response and handle chat history. - Add `getHistoryMessages` to `ChatCodingPanel` for retrieving chat history. - Enhance `ChatCodingService` to manage chat history and agent state transitions.
1 parent 9cc5268 commit 803e184

File tree

4 files changed

+76
-22
lines changed

4 files changed

+76
-22
lines changed

core/src/main/kotlin/cc/unitmesh/devti/agent/CustomAgentChatProcessor.kt

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,29 @@ package cc.unitmesh.devti.agent
22

33
import cc.unitmesh.devti.AutoDevBundle
44
import cc.unitmesh.devti.agent.model.CustomAgentConfig
5-
import cc.unitmesh.devti.agent.model.CustomAgentState
65
import cc.unitmesh.devti.agent.model.CustomAgentResponseAction
6+
import cc.unitmesh.devti.agent.model.CustomAgentState
77
import cc.unitmesh.devti.gui.chat.ChatCodingPanel
88
import cc.unitmesh.devti.gui.chat.ChatRole
99
import cc.unitmesh.devti.llms.LLMProvider
1010
import cc.unitmesh.devti.provider.ContextPrompter
11-
import cc.unitmesh.devti.provider.devins.LanguagePromptProcessor
1211
import cc.unitmesh.devti.provider.devins.CustomAgentContext
13-
import cc.unitmesh.devti.util.LLMCoroutineScope
12+
import cc.unitmesh.devti.provider.devins.LanguagePromptProcessor
1413
import cc.unitmesh.devti.util.parser.CodeFence
1514
import com.intellij.openapi.components.Service
1615
import com.intellij.openapi.components.service
1716
import com.intellij.openapi.diagnostic.logger
1817
import com.intellij.openapi.project.Project
19-
import kotlinx.coroutines.flow.*
20-
import kotlinx.coroutines.launch
18+
import kotlinx.coroutines.flow.Flow
2119
import kotlinx.coroutines.runBlocking
20+
import java.util.concurrent.CompletableFuture
2221

2322
@Service(Service.Level.PROJECT)
2423
class CustomAgentChatProcessor(val project: Project) {
2524
private val customAgentExecutor = project.service<CustomAgentExecutor>()
2625
private val logger = logger<CustomAgentChatProcessor>()
2726

28-
fun handleChat(prompter: ContextPrompter, ui: ChatCodingPanel, llmProvider: LLMProvider) {
27+
fun handleChat(prompter: ContextPrompter, ui: ChatCodingPanel, llmProvider: LLMProvider): String? {
2928
val originPrompt = prompter.requestPrompt()
3029
ui.addMessage(originPrompt, true, originPrompt)
3130

@@ -37,9 +36,10 @@ class CustomAgentChatProcessor(val project: Project) {
3736
val response: Flow<String>? = customAgentExecutor.execute(request, selectedAgent)
3837
if (response == null) {
3938
logger.error("error for custom agent: $selectedAgent with request: $request")
40-
return
39+
return null
4140
}
4241

42+
var llmResponse = ""
4343
selectedAgent.state = CustomAgentState.FINISHED
4444

4545
var devInCode: String? = ""
@@ -63,24 +63,32 @@ class CustomAgentChatProcessor(val project: Project) {
6363

6464
ui.hiddenProgressBar()
6565
ui.updateUI()
66+
67+
llmResponse = content
6668
}
6769

6870
CustomAgentResponseAction.Stream -> {
6971
ui.addMessage(AutoDevBundle.message("autodev.loading"))
70-
var msg = ""
71-
LLMCoroutineScope.scope(project).launch {
72-
msg = ui.updateMessage(response)
72+
val future: CompletableFuture<String> = CompletableFuture()
73+
val sb = StringBuilder()
74+
runBlocking {
75+
val result = ui.updateMessage(response)
76+
sb.append(result)
7377
}
7478

75-
llmProvider.appendLocalMessage(msg, ChatRole.Assistant)
79+
val content = sb.toString()
80+
llmProvider.appendLocalMessage(content, ChatRole.Assistant)
7681
ui.hiddenProgressBar()
7782
ui.updateUI()
7883
ui.moveCursorToStart()
7984

80-
val code = CodeFence.parse(msg)
85+
val code = CodeFence.parse(content)
8186
if (code.language.displayName == "DevIn") {
8287
devInCode = code.text
8388
}
89+
90+
future.complete(content)
91+
llmResponse = future.get()
8492
}
8593

8694
CustomAgentResponseAction.TextChunk -> {
@@ -97,6 +105,8 @@ class CustomAgentChatProcessor(val project: Project) {
97105
ui.moveCursorToStart()
98106
ui.setInput(content)
99107
ui.hiddenProgressBar()
108+
109+
llmResponse = content
100110
}
101111

102112
CustomAgentResponseAction.Flow -> {
@@ -116,6 +126,8 @@ class CustomAgentChatProcessor(val project: Project) {
116126

117127
ui.appendWebView(content, project)
118128
ui.hiddenProgressBar()
129+
130+
llmResponse = content
119131
}
120132

121133
CustomAgentResponseAction.DevIns -> {
@@ -129,13 +141,17 @@ class CustomAgentChatProcessor(val project: Project) {
129141
ui.updateUI()
130142

131143
devInCode = msg
144+
145+
llmResponse = msg
132146
}
133147
}
134148

135149
if (!devInCode.isNullOrEmpty()) {
136150
LanguagePromptProcessor.instance("DevIn").forEach {
137-
it.execute(project, CustomAgentContext(selectedAgent, devInCode))
151+
it.execute(project, CustomAgentContext(selectedAgent, devInCode!!))
138152
}
139153
}
154+
155+
return llmResponse
140156
}
141157
}

core/src/main/kotlin/cc/unitmesh/devti/gui/chat/ChatCodingPanel.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package cc.unitmesh.devti.gui.chat
22

3+
import cc.unitmesh.cf.core.llms.LlmMsg
34
import cc.unitmesh.devti.*
45
import cc.unitmesh.devti.agent.model.CustomAgentConfig
56
import cc.unitmesh.devti.agent.view.WebBlock
@@ -11,7 +12,6 @@ import cc.unitmesh.devti.settings.AutoDevSettingsState
1112
import cc.unitmesh.devti.settings.LanguageChangedCallback.componentStateChanged
1213
import com.intellij.lang.html.HTMLLanguage
1314
import com.intellij.openapi.Disposable
14-
import com.intellij.openapi.diagnostic.logger
1515
import com.intellij.openapi.project.Project
1616
import com.intellij.openapi.ui.DialogPanel
1717
import com.intellij.openapi.ui.NullableComponent
@@ -169,6 +169,18 @@ class ChatCodingPanel(private val chatCodingService: ChatCodingService, val disp
169169
}
170170
}
171171

172+
fun getHistoryMessages(): List<LlmMsg.ChatMessage> {
173+
val messages = mutableListOf<LlmMsg.ChatMessage>()
174+
for (i in 0 until myList.componentCount) {
175+
val component = myList.getComponent(i)
176+
if (component is MessageView) {
177+
val role = LlmMsg.ChatRole.valueOf(component.role.name)
178+
messages.add(LlmMsg.ChatMessage(role, component.message, null))
179+
}
180+
}
181+
return messages
182+
}
183+
172184
suspend fun updateMessage(content: Flow<String>): String {
173185
if (myList.componentCount > 0) {
174186
myList.remove(myList.componentCount - 1)
@@ -215,7 +227,7 @@ class ChatCodingPanel(private val chatCodingService: ChatCodingService, val disp
215227
postAction(text)
216228
}
217229

218-
private suspend fun updateMessageInUi(content: Flow<String>): String {
230+
suspend fun updateMessageInUi(content: Flow<String>): String {
219231
val messageView = MessageView("", ChatRole.Assistant, "")
220232
myList.add(messageView)
221233
val startTime = System.currentTimeMillis()

core/src/main/kotlin/cc/unitmesh/devti/gui/chat/ChatCodingService.kt

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import cc.unitmesh.devti.custom.compile.CustomVariable
1010
import cc.unitmesh.devti.llms.LlmFactory
1111
import cc.unitmesh.devti.provider.ContextPrompter
1212
import com.intellij.openapi.application.ApplicationManager
13+
import com.intellij.openapi.application.runInEdt
1314
import com.intellij.openapi.components.service
1415
import com.intellij.openapi.project.Project
1516
import kotlinx.coroutines.Job
@@ -27,12 +28,15 @@ class ChatCodingService(var actionType: ChatActionType, val project: Project) {
2728
currentJob?.cancel()
2829
}
2930

31+
private var isLastAgent: Boolean = false
32+
3033
fun handlePromptAndResponse(
3134
ui: ChatCodingPanel,
3235
prompter: ContextPrompter,
3336
context: ChatContext? = null,
3437
keepHistory: Boolean
3538
) {
39+
var chatHistory: List<LlmMsg.ChatMessage> = emptyList()
3640
currentJob?.cancel()
3741
var requestPrompt = prompter.requestPrompt()
3842
var displayPrompt = prompter.displayPrompt()
@@ -41,9 +45,18 @@ class ChatCodingService(var actionType: ChatActionType, val project: Project) {
4145
val selectedCustomAgent = ui.getSelectedCustomAgent()
4246
when {
4347
selectedCustomAgent.state === CustomAgentState.START -> {
44-
counitProcessor.handleChat(prompter, ui, llmProvider)
45-
ui.resetAgent()
46-
ui.moveCursorToStart()
48+
isLastAgent = true
49+
val response = ApplicationManager.getApplication().executeOnPooledThread<String?> {
50+
val output = counitProcessor.handleChat(prompter, ui, llmProvider)
51+
52+
runInEdt {
53+
ui.resetAgent()
54+
ui.moveCursorToStart()
55+
}
56+
57+
output
58+
}
59+
4760
return
4861
}
4962

@@ -59,13 +72,16 @@ class ChatCodingService(var actionType: ChatActionType, val project: Project) {
5972
}
6073
}
6174

75+
if (isLastAgent) {
76+
isLastAgent = false
77+
chatHistory = ui.getHistoryMessages()
78+
}
6279

6380
ui.addMessage(requestPrompt, true, displayPrompt)
6481
ui.addMessage(AutoDevBundle.message("autodev.loading"))
6582

66-
6783
ApplicationManager.getApplication().executeOnPooledThread {
68-
val response = this.makeChatBotRequest(requestPrompt, keepHistory)
84+
val response = this.makeChatBotRequest(requestPrompt, keepHistory, chatHistory)
6985
currentJob = LLMCoroutineScope.scope(project).launch {
7086
when {
7187
actionType === ChatActionType.REFACTOR -> ui.updateReplaceableContent(response) {
@@ -97,7 +113,17 @@ class ChatCodingService(var actionType: ChatActionType, val project: Project) {
97113
}
98114
}
99115

100-
private fun makeChatBotRequest(requestPrompt: String, newChatContext: Boolean): Flow<String> {
116+
private fun makeChatBotRequest(
117+
requestPrompt: String,
118+
newChatContext: Boolean,
119+
chatHistory: List<LlmMsg.ChatMessage>
120+
): Flow<String> {
121+
if (chatHistory.isNotEmpty()) {
122+
chatHistory.forEach {
123+
llmProvider.appendLocalMessage(it.content, ChatRole.valueOf(it.role.name))
124+
}
125+
}
126+
101127
return llmProvider.stream(requestPrompt, "", keepHistory = !newChatContext)
102128
}
103129

core/src/main/kotlin/cc/unitmesh/devti/gui/chat/MessageView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import java.awt.*
2020
import javax.swing.*
2121
import kotlin.jvm.internal.Ref
2222

23-
class MessageView(private val message: String, val role: ChatRole, private val displayText: String) :
23+
class MessageView(val message: String, val role: ChatRole, private val displayText: String) :
2424
JBPanel<MessageView>(), DataProvider {
2525
private val myNameLabel: Component
2626
private val component: DisplayComponent = DisplayComponent(message)

0 commit comments

Comments
 (0)