Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Shared chat lib #122

Merged
merged 80 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
62a5817
wip(chat): load and render chat library in jbcef... found some style …
MarcMcIntosh Mar 27, 2024
c9706bd
wip(chat): log events sent from chat
MarcMcIntosh Mar 27, 2024
3e51382
wip(chat): add definitions for event from and to chat
MarcMcIntosh Mar 28, 2024
77a02a5
feat(chat): parse message payload
MarcMcIntosh Mar 29, 2024
09f2b26
chore(chat): remove comments
MarcMcIntosh Mar 29, 2024
473c674
feat(chat caps): request and receive caps
MarcMcIntosh Apr 1, 2024
0e772bb
feat(chat prompts): add handler for getting system prompts
MarcMcIntosh Apr 1, 2024
1d0d25b
wip(chat): handle response. from lsp
MarcMcIntosh Apr 2, 2024
a2e2cb6
wip: handle user messages from lsp and open new file button
MarcMcIntosh Apr 10, 2024
eb986fa
feat(chat): send active file info
MarcMcIntosh Apr 11, 2024
b7ca2dd
feat(chat): send selected snippet
MarcMcIntosh Apr 11, 2024
52334e1
fix(chat): use caps cache
MarcMcIntosh Apr 15, 2024
0b93ae6
feat(chat): paste code into seleciton
MarcMcIntosh Apr 15, 2024
4cf0021
feat(chat): add debugging tools
MarcMcIntosh Apr 15, 2024
3e1d5d6
fix(chat): jbcef is an old version of chrome that doesn't support dvh…
MarcMcIntosh Apr 15, 2024
4562e73
wip(chat): support light/dark mode
MarcMcIntosh Apr 15, 2024
9938a58
feat(chat): add tabs
MarcMcIntosh Apr 16, 2024
624d4a7
wip(chat-history): set up chat history
MarcMcIntosh Apr 17, 2024
feeddc4
wip(chat): restore chat from history
MarcMcIntosh Apr 18, 2024
65f53e0
wip(restore chat): forgot to commit local variable
MarcMcIntosh Apr 18, 2024
101e305
chore(chat): clean up comments and set caps after requesting
MarcMcIntosh Apr 18, 2024
c96b1d9
fix(chat): add missing import
MarcMcIntosh Apr 18, 2024
729a698
wip(chat): handle stop streaming and project changes
MarcMcIntosh Apr 22, 2024
e2c3739
feat(chat): change theme with the IDE
MarcMcIntosh Apr 25, 2024
eee4041
refactor(events): move file up one directory
MarcMcIntosh Apr 25, 2024
7dd4b21
wip: setup tests for chat event parser
MarcMcIntosh Apr 25, 2024
6ce93b3
fix(json): issue with parsing context file response
MarcMcIntosh Apr 26, 2024
7113da1
chore(chat-js): update to alpha version
MarcMcIntosh Apr 26, 2024
18c62cf
wip: refactoring chat response payload json creation
MarcMcIntosh Apr 26, 2024
ae2348c
refactor(chat response choices): improve json serialisation.
MarcMcIntosh Apr 26, 2024
9010b43
fix(import): fix old import
MarcMcIntosh Apr 26, 2024
b470684
refactor(chat response messages): use the type system to correctly fo…
MarcMcIntosh Apr 29, 2024
455898d
refactor(chat snippet): use the type system to format the event to se…
MarcMcIntosh Apr 29, 2024
12ccdb8
refactor(chat, active file info): use the type system to format the m…
MarcMcIntosh Apr 29, 2024
55a84b0
refactor(chat restore): use the type system to formate the restore ch…
MarcMcIntosh Apr 29, 2024
05ee9fe
refactor(chat at commands): fix json messages and correct the command…
MarcMcIntosh Apr 30, 2024
d4a3ea8
fix(chat): fix system prompts message to chat
MarcMcIntosh Apr 30, 2024
ce8a743
refactor(chat caps): format caps response to json
MarcMcIntosh May 1, 2024
e5d5f60
fix(chat context file): lsp message content should be a string
MarcMcIntosh May 1, 2024
cb790dc
refactor: rename chat serialiser to chat history serialiser.
MarcMcIntosh May 1, 2024
59d3a67
fix(chat): handle detail messages from the lsp
MarcMcIntosh May 1, 2024
6666069
refactor(chat events): use Event.parse and Event.stringify
MarcMcIntosh May 1, 2024
3479ae4
test(chat error): update assertion
MarcMcIntosh May 2, 2024
4635ad7
add ast and vecdb params
reymondzzzz Apr 24, 2024
606b861
feat(ast and vecdb): send ast and vecdb options to chat
MarcMcIntosh May 2, 2024
fd2cce5
feat(chat preview files): add dedicated method for handling preview f…
MarcMcIntosh May 7, 2024
11f4afa
ci(lsp): use main version
MarcMcIntosh May 7, 2024
796777b
fix: duplicated definitions and adjust some ui settings
MarcMcIntosh May 8, 2024
400ad3a
chat-ui: add background colour from ide
MarcMcIntosh May 8, 2024
6a11dbc
debug: try and debug why a white flash happens when opening JCEF
MarcMcIntosh May 8, 2024
8242548
fix(completion): handle command completion and preview files separately
MarcMcIntosh May 14, 2024
9fb772f
debug: cached caps causing app to crash
MarcMcIntosh May 17, 2024
a8323a8
wip: fix parsing preview files
MarcMcIntosh May 17, 2024
103d4ec
fix: formating preview files for chat
MarcMcIntosh May 17, 2024
68c1c3a
fix multiple instance of lsp for project
reymondzzzz May 20, 2024
fe7bbbd
refactor(chat): load local resources
MarcMcIntosh May 20, 2024
9ec7b28
fix(combobox colour): typo in accentColor
MarcMcIntosh May 21, 2024
133831b
ci(chat): download refact-chat-js artefacts
MarcMcIntosh May 21, 2024
bd09033
ci: typo in chat-js action name
MarcMcIntosh May 21, 2024
78291c0
ci(chat): move the download to before the lsp and check if dist direc…
MarcMcIntosh May 21, 2024
1c5597d
ci: run and use can be used in the same block
MarcMcIntosh May 21, 2024
214d260
ci: chat fix typo in download asset
MarcMcIntosh May 21, 2024
510b8ee
ci: remove making the directory for the chat files from the action
MarcMcIntosh May 21, 2024
edfc27e
ci: add name of assets to download
MarcMcIntosh May 21, 2024
a222811
ci: fix typo when downloading chat-js
MarcMcIntosh May 21, 2024
cca9ab6
test(chat events): fix typo in tests grey / gray
MarcMcIntosh May 22, 2024
58043d5
move lsp request in another worker thread
reymondzzzz May 23, 2024
8575c4e
disable context menu; redirect all hyperlinks to desktop browser
reymondzzzz May 23, 2024
fe9de70
ci: update chat branch to main
MarcMcIntosh May 23, 2024
014c825
disable for android studio
reymondzzzz May 23, 2024
52a1577
return context menu
reymondzzzz May 27, 2024
478e251
fix(chat-alpha): add fallback copy function for button
MarcMcIntosh May 27, 2024
532b587
Merge branch 'shared-chat-lib' of https://github.com/smallcloudai/ref…
MarcMcIntosh May 27, 2024
9167a05
chore: remove refact-chat-js files
MarcMcIntosh May 27, 2024
91184c6
disable context menu
reymondzzzz May 27, 2024
ce8598c
fix replace paste behaviour
reymondzzzz May 27, 2024
902d5b6
update gitignore
reymondzzzz May 27, 2024
ac9d459
update version
reymondzzzz May 27, 2024
16fccaf
Merge branch 'main' into shared-chat-lib
reymondzzzz May 27, 2024
8f93d6c
fix compilation
reymondzzzz May 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ jobs:
run: |
echo "lsp_version=$(cat refact_lsp)" >> $GITHUB_OUTPUT

- name: Download refact-chat-js
id: download-refact-chat-js
uses: dawidd6/action-download-artifact@v3
with:
github_token: ${{secrets.GITHUB_TOKEN}}
workflow: node.js.yml
workflow_search: true
repo: smallcloudai/refact-chat-js
branch: alpha
name: refact-chat-js-latest
path: ./src/main/resources/webview/dist

- uses: convictional/[email protected]
name: "Build refact-lsp"
with:
Expand All @@ -54,6 +66,7 @@ jobs:
branch: ${{ steps.setupvars.outputs.lsp_version }}
path: ./src/main/resources/bin


# Validate wrapper
- name: Gradle Wrapper Validation
uses: gradle/wrapper-validation-action@v3
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ bin/
### Mac OS ###
.DS_Store

src/main/resources/bin/
src/main/resources/bin/
src/main/resources/webview/dist
12 changes: 10 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,23 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.10")
implementation("com.vladsch.flexmark:flexmark-all:0.64.8")
implementation("io.github.kezhenxu94:cache-lite:0.2.0")

// test libraries
testImplementation(kotlin("test"))
}



group = "com.smallcloud"
version = getVersionString("1.2.25")
version = getVersionString("1.3.0")

repositories {
mavenCentral()
}


// Configure Gradle IntelliJ Plugin
// Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
// Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
intellij {
// version.set("LATEST-EAP-SNAPSHOT")
version.set("2022.3.1")
Expand Down Expand Up @@ -65,6 +69,10 @@ tasks {
channels.set(listOf(System.getenv("PUBLISH_CHANNEL")))
token.set(System.getenv("PUBLISH_TOKEN"))
}

test {
useJUnitPlatform()
}
}

fun String.runCommand(
Expand Down
2 changes: 1 addition & 1 deletion refact_lsp
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.8.0
v0.8.2
10 changes: 9 additions & 1 deletion src/main/kotlin/com/smallcloud/refactai/io/AsyncConnection.kt
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ class AsyncConnection : Disposable {
failedDataReceiveEnded: (Throwable?) -> Unit = {},
requestId: String = ""
): CompletableFuture<Future<*>> {
var canceled = false;
return CompletableFuture.supplyAsync {
return@supplyAsync client.execute(
requestProducer,
Expand All @@ -173,6 +174,8 @@ class AsyncConnection : Disposable {

override fun data(src: ByteBuffer?, endOfStream: Boolean) {
src ?: return
if(canceled) return;

val part = Charset.forName("UTF-8").decode(src)
bufferStr += part
if (part.startsWith(STREAMING_PREFIX)) {
Expand Down Expand Up @@ -223,7 +226,11 @@ class AsyncConnection : Disposable {
failedDataReceiveEnded(ex)
}

override fun cancelled() {}
override fun cancelled() {
// TODO: figure out how to stop the stream fro the lsp
canceled = true
dataReceiveEnded("Canceled")
}
}
)
}
Expand Down Expand Up @@ -253,4 +260,5 @@ class AsyncConnection : Disposable {
override fun dispose() {
client.close()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class InferenceGlobalContext : Disposable {
get() {
return AppSettingsState.inferenceUri?.let { URI(it) }
}


var isNewChatStyle: Boolean = false

Expand Down
122 changes: 119 additions & 3 deletions src/main/kotlin/com/smallcloud/refactai/lsp/LSPProcessHolder.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.smallcloud.refactai.lsp

import com.google.gson.Gson
import com.google.gson.JsonObject
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationInfo
Expand All @@ -16,18 +17,20 @@ import com.intellij.util.messages.MessageBus
import com.intellij.util.messages.Topic
import com.smallcloud.refactai.Resources
import com.smallcloud.refactai.Resources.binPrefix
import com.smallcloud.refactai.account.AccountManager.Companion.instance
import com.smallcloud.refactai.account.AccountManagerChangedNotifier
import com.smallcloud.refactai.io.InferenceGlobalContextChangedNotifier
import com.smallcloud.refactai.notifications.emitError
import com.smallcloud.refactai.panes.sharedchat.*
import org.apache.hc.core5.concurrent.ComplexFuture
import java.net.URI
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Future
import java.util.concurrent.TimeUnit
import kotlin.io.path.Path
import com.smallcloud.refactai.account.AccountManager.Companion.instance as AccountManager
import com.smallcloud.refactai.io.InferenceGlobalContext.Companion.instance as InferenceGlobalContext


Expand Down Expand Up @@ -159,7 +162,7 @@ class LSPProcessHolder(val project: Project): Disposable {
InferenceGlobalContext.inferenceUri
val newConfig = LSPConfig(
address = address,
apiKey = instance.apiKey,
apiKey = AccountManager.apiKey,
port = 0,
clientVersion = "${Resources.client}-${Resources.version}/${Resources.jbBuildVersion}",
useTelemetry = true,
Expand Down Expand Up @@ -246,6 +249,7 @@ class LSPProcessHolder(val project: Project): Disposable {
private val BIN_PATH = Path(getTempDirectory(),
ApplicationInfo.getInstance().build.toString().replace(Regex("[^A-Za-z0-9 ]"), "_") +
"_refact_lsp${getExeSuffix()}").toString()
// here ?
@JvmStatic
fun getInstance(project: Project): LSPProcessHolder = project.service()

Expand Down Expand Up @@ -288,7 +292,7 @@ class LSPProcessHolder(val project: Project): Disposable {
try {
requestFuture = it.get() as ComplexFuture
val out = requestFuture.get()
logger.warn("LSP caps_received " + out)
// logger.warn("LSP caps_received " + out)
val gson = Gson()
res = gson.fromJson(out as String, LSPCapabilities::class.java)
logger.debug("caps_received request finished")
Expand All @@ -298,4 +302,116 @@ class LSPProcessHolder(val project: Project): Disposable {
return res
}
}

fun fetchCaps(): Future<LSPCapabilities> {
// // This causes the ide to crash :/
// if(this.capabilities.codeChatModels.isNotEmpty()) {
// println("caps_cached")
// return FutureTask { this.capabilities }
// }

val res = InferenceGlobalContext.connection.get(
url.resolve("/v1/caps"),
dataReceiveEnded = {},
errorDataReceived = {}
)

return res.thenApply {
val body = it.get() as String
val caps = Gson().fromJson(body, LSPCapabilities::class.java)
caps
}
}

fun fetchSystemPrompts(): Future<SystemPromptMap> {
val res = InferenceGlobalContext.connection.get(
url.resolve("/v1/customization"),
dataReceiveEnded = {},
errorDataReceived = {}
)
val json = res.thenApply {
val body = it.get() as String
val prompts = Gson().fromJson<CustomPromptsResponse>(body, CustomPromptsResponse::class.java)
prompts.systemPrompts
}

return json
}

fun fetchCommandCompletion(query: String, cursor: Int, count: Int = 5): Future<CommandCompletionResponse> {

val requestBody = Gson().toJson(mapOf("query" to query, "cursor" to cursor, "top_n" to count))

val res = InferenceGlobalContext.connection.post(
url.resolve("/v1/at-command-completion"),
requestBody,
)
// TODO: could this have a detail message?
val json = res.thenApply {
val body = it.get() as String
// handle error
// if(body.startsWith("detail"))
Gson().fromJson<CommandCompletionResponse>(body, CommandCompletionResponse::class.java)
}

return json
}

fun fetchCommandPreview(query: String): Future<Events.AtCommands.Preview.Response> {
val requestBody = Gson().toJson(mapOf("query" to query))

val response = InferenceGlobalContext.connection.post(
url.resolve("/v1/at-command-preview"),
requestBody
)

val json: Future<Events.AtCommands.Preview.Response> = response.thenApply {
val responseBody = it.get() as String
if (responseBody.startsWith("detail")) {
Events.AtCommands.Preview.Response(emptyArray())
} else {
Events.gson.fromJson(responseBody, Events.AtCommands.Preview.Response::class.java)
}
}

return json
}

fun sendChat(
id: String,
messages: ChatMessages,
model: String,
dataReceived: (String, String) -> Unit,
dataReceiveEnded: (String) -> Unit,
errorDataReceived: (JsonObject) -> Unit,
failedDataReceiveEnded: (Throwable?) -> Unit,
): CompletableFuture<Future<*>> {

val parameters = mapOf("max_new_tokens" to 1000)

val requestBody = Gson().toJson(mapOf(
"messages" to messages.map {
val content = if(it.content is String) { it.content } else { Gson().toJson(it.content) }
mapOf("role" to it.role, "content" to content)
},
"model" to model,
"parameters" to parameters,
"stream" to true
))

val headers = mapOf("Authorization" to "Bearer ${AccountManager.apiKey}")
val request = InferenceGlobalContext.connection.post(
url.resolve("/v1/chat"),
requestBody,
headers = headers,
dataReceived = dataReceived,
dataReceiveEnded = dataReceiveEnded,
errorDataReceived = errorDataReceived,
failedDataReceiveEnded = failedDataReceiveEnded,
requestId = id,
)

return request

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,74 @@ import com.intellij.openapi.wm.ToolWindowFactory
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.ui.content.Content
import com.intellij.ui.content.ContentFactory
import com.intellij.ui.jcef.JBCefApp
import com.smallcloud.refactai.Resources
import com.smallcloud.refactai.panes.gptchat.ChatGPTPanes
import com.smallcloud.refactai.panes.sharedchat.ChatPanes
import com.smallcloud.refactai.utils.getLastUsedProject


class RefactAIToolboxPaneFactory : ToolWindowFactory {
override fun init(toolWindow: ToolWindow) {
toolWindow.setIcon(Resources.Icons.LOGO_RED_13x13)
super.init(toolWindow)
}

override fun isApplicable(project: Project): Boolean {
return try {
JBCefApp.isSupported() && JBCefApp.isStarted()
JBCefApp.isSupported()
} catch (_: Exception) {
false
}
}


override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
val contentFactory = ContentFactory.getInstance()

val gptChatPanes = ChatGPTPanes(project, toolWindow.disposable)
val content: Content = contentFactory.createContent(
gptChatPanes.getComponent(),
"Chat",
false
)
// val gptChatPanes = ChatGPTPanes(project, toolWindow.disposable)
// val content: Content = contentFactory.createContent(
// gptChatPanes.getComponent(),
// "Chat",
// false
// )
// content.isCloseable = false
// content.putUserData(panesKey, gptChatPanes)
// toolWindow.contentManager.addContent(content)

val chatPanes = ChatPanes(project, toolWindow.disposable)
val content: Content = contentFactory.createContent(chatPanes.getComponent(), "Chat", false)
content.isCloseable = false
content.putUserData(panesKey, gptChatPanes)
toolWindow.contentManager.addContent(content)

// val sp = SharedChatPane(project)
//
// val chatIframeContent: Content = contentFactory.createContent(
// sp.getComponent(),
// "Shared Chat",
// false
// )
// chatIframeContent.isCloseable = false
//
// toolWindow.contentManager.addContent(chatIframeContent)


// Uncomment to enable dev tools
// val devToolsBrowser = JBCefBrowser.createBuilder()
// .setCefBrowser(sp.webView.cefBrowser.devTools)
// .setClient(sp.webView.jbCefClient)
// .build();
//
// val c = contentFactory.createContent(devToolsBrowser.component, "Shared Chat Dev", false)
// toolWindow.contentManager.addContent(c)
// devToolsBrowser.openDevtools()


}



companion object {
private val panesKey = Key.create<ChatGPTPanes>("refact.panes")
val chat: ChatGPTPanes?
Expand Down
Loading
Loading