Skip to content

Commit 6cd1e2c

Browse files
committed
feat(custom-agent): add support for custom web views in chat responses #51
The commit introduces the ability to display custom web views within chat responses, enhancing the user experience by providing a more interactive and dynamic way to display information.
1 parent 214eb79 commit 6cd1e2c

File tree

8 files changed

+59
-9
lines changed

8 files changed

+59
-9
lines changed

src/main/kotlin/cc/unitmesh/devti/counit/CustomAgentChatProcessor.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ import cc.unitmesh.devti.AutoDevBundle
44
import cc.unitmesh.devti.counit.model.CustomAgentConfig
55
import cc.unitmesh.devti.counit.model.CustomAgentState
66
import cc.unitmesh.devti.counit.model.ResponseAction
7+
import cc.unitmesh.devti.counit.view.WebBlock
8+
import cc.unitmesh.devti.counit.view.WebBlockView
79
import cc.unitmesh.devti.gui.chat.ChatCodingPanel
810
import cc.unitmesh.devti.gui.chat.ChatContext
11+
import cc.unitmesh.devti.gui.chat.ChatRole
912
import cc.unitmesh.devti.provider.ContextPrompter
1013
import cc.unitmesh.devti.util.LLMCoroutineScope
1114
import com.intellij.openapi.components.Service
1215
import com.intellij.openapi.diagnostic.logger
1316
import com.intellij.openapi.project.Project
17+
import com.intellij.temporary.gui.block.SimpleMessage
1418
import kotlinx.coroutines.launch
1519
import kotlinx.coroutines.runBlocking
1620

@@ -69,7 +73,18 @@ class CustomAgentChatProcessor(val project: Project) {
6973
}
7074

7175
ResponseAction.WebView -> {
72-
TODO()
76+
val sb = StringBuilder()
77+
runBlocking {
78+
response.collect {
79+
sb.append(it)
80+
}
81+
}
82+
val content = sb.toString()
83+
84+
val webBlock = WebBlock(SimpleMessage(content, content, ChatRole.User))
85+
val blockView = WebBlockView(webBlock, project, {})
86+
ui.appendWebView(blockView)
87+
ui.hiddenProgressBar()
7388
}
7489
}
7590
}

src/main/kotlin/cc/unitmesh/devti/counit/view/WebBlockView.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@ class WebBlockView(
1515
private val project: Project,
1616
private val disposable: Disposable,
1717
) : MessageBlockView {
18+
private val webViewWindow = WebViewWindow()
19+
20+
override fun initialize() {
21+
this.webViewWindow.loadHtml(block.msg.text)
22+
}
23+
1824
override fun getBlock(): MessageBlock {
1925
return block
2026
}
2127

2228
override fun getComponent(): Component {
23-
return WebViewWindow().component
29+
return webViewWindow.component
2430
}
2531
}

src/main/kotlin/cc/unitmesh/devti/counit/view/WebViewWindow.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ import java.awt.Component
1313
* for custom webview can refs: https://github.com/mucharafal/jcef_example
1414
*/
1515
class WebViewWindow {
16-
private val browser: JBCefBrowser = JBCefBrowser().also {
17-
// it.loadURL("http://myapp/index.html")
18-
}
16+
private val browser: JBCefBrowser = JBCefBrowser().also {}
1917

2018
val component: Component = browser.component
2119

src/main/kotlin/cc/unitmesh/devti/gui/chat/AutoDevInputSection.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ class AutoDevInputSection(private val project: Project, val disposable: Disposab
147147
}
148148
})
149149

150-
tokenizer = TokenizerImpl.INSTANCE
150+
tokenizer = TokenizerImpl.INSTANCESupplier.get()
151151
}
152152

153153

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ import com.intellij.openapi.ui.DialogPanel
1414
import com.intellij.openapi.ui.NullableComponent
1515
import com.intellij.openapi.ui.SimpleToolWindowPanel
1616
import com.intellij.openapi.wm.IdeFocusManager
17+
import com.intellij.temporary.gui.block.MessageBlockView
1718
import com.intellij.temporary.gui.block.whenDisposed
1819
import com.intellij.ui.Gray
1920
import com.intellij.ui.JBColor
2021
import com.intellij.ui.components.ActionLink
2122
import com.intellij.ui.components.JBLabel
23+
import com.intellij.ui.components.JBPanel
2224
import com.intellij.ui.components.JBScrollPane
2325
import com.intellij.ui.components.panels.VerticalLayout
2426
import com.intellij.ui.dsl.builder.panel
@@ -29,6 +31,7 @@ import kotlinx.coroutines.Dispatchers
2931
import kotlinx.coroutines.delay
3032
import kotlinx.coroutines.flow.*
3133
import kotlinx.coroutines.withContext
34+
import java.awt.BorderLayout
3235
import java.awt.event.ActionListener
3336
import java.awt.event.MouseAdapter
3437
import java.awt.event.MouseEvent
@@ -262,4 +265,28 @@ class ChatCodingPanel(private val chatCodingService: ChatCodingService, val disp
262265

263266
updateUI()
264267
}
268+
269+
fun appendWebView(blockView: MessageBlockView) {
270+
myList.add(SimpleView(blockView))
271+
updateUI()
272+
}
273+
}
274+
275+
class SimpleView(val view: MessageBlockView) : JBPanel<MessageView>() {
276+
init {
277+
isDoubleBuffered = true
278+
isOpaque = true
279+
background = JBColor(0x6F59FF, 0x2d2f30)
280+
281+
layout = BorderLayout(JBUI.scale(8), 0)
282+
val centerPanel = JPanel(VerticalLayout(JBUI.scale(8)))
283+
284+
centerPanel.isOpaque = false
285+
centerPanel.border = JBUI.Borders.emptyRight(8)
286+
287+
add(centerPanel, BorderLayout.WEST)
288+
289+
view.initialize()
290+
centerPanel.add(view.getComponent())
291+
}
265292
}

src/main/kotlin/cc/unitmesh/devti/llms/tokenizer/TokenizerImpl.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package cc.unitmesh.devti.llms.tokenizer
22

33
import com.intellij.openapi.application.ApplicationManager
4+
import com.intellij.openapi.application.CachedSingletonsRegistry
45
import com.intellij.openapi.components.Service
56
import com.knuddels.jtokkit.Encodings
67
import com.knuddels.jtokkit.api.Encoding
78
import com.knuddels.jtokkit.api.EncodingRegistry
89
import com.knuddels.jtokkit.api.EncodingType
10+
import java.util.function.Supplier
911

1012
@Service(Service.Level.APP)
1113
class TokenizerImpl(private val maxTokenLength: Int = 8192) : Tokenizer {
@@ -20,6 +22,7 @@ class TokenizerImpl(private val maxTokenLength: Int = 8192) : Tokenizer {
2022
}
2123

2224
companion object {
23-
val INSTANCE = ApplicationManager.getApplication().getService(TokenizerImpl::class.java)
25+
val INSTANCESupplier: Supplier<TokenizerImpl> =
26+
CachedSingletonsRegistry.lazy { ApplicationManager.getApplication().getService(TokenizerImpl::class.java) }
2427
}
2528
}

src/main/kotlin/cc/unitmesh/devti/provider/PromptStrategy.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ abstract class PromptStrategy : LazyExtensionInstance<PromptStrategy>() {
2626
@Attribute("implementationClass")
2727
var implementationClass: String? = null
2828

29-
private val tokenizer: Tokenizer = TokenizerImpl.INSTANCE
29+
private val tokenizer: Tokenizer = TokenizerImpl.INSTANCESupplier.get()
3030

3131
override fun getImplementationClassName(): String? = implementationClass
3232

src/main/kotlin/com/intellij/temporary/error/ErrorMessageProcessor.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ object ErrorMessageProcessor {
7070
val extractedErrorPlaces: List<ErrorPlace> =
7171
extractErrorPlaces(project, description.consoleLineFrom, description.consoleLineTo, description.editor)
7272

73-
val errorPromptBuilder = ErrorPromptBuilder(AutoDevSettingsState.maxTokenLength, TokenizerImpl.INSTANCE)
73+
val errorPromptBuilder =
74+
ErrorPromptBuilder(AutoDevSettingsState.maxTokenLength, TokenizerImpl.INSTANCESupplier.get())
7475
return errorPromptBuilder.buildPrompt(extractedText, extractedErrorPlaces)
7576
}
7677

0 commit comments

Comments
 (0)