Skip to content

Commit

Permalink
feat(chat): add ChatRole enum and FileGenerateTask for file output
Browse files Browse the repository at this point in the history
Introduced a new enum, ChatRole, to better categorize chat roles. Also added a new task, FileGenerateTask, to handle file generation based on chat messages. This task runs in the background and refreshes the project model upon completion.
  • Loading branch information
phodal committed Jun 29, 2024
1 parent 734ab43 commit 9bf98d5
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ package com.phodal.shirelang.run.runner

import com.intellij.execution.process.ProcessHandler
import com.intellij.execution.ui.ConsoleView
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator
import com.intellij.openapi.project.Project
import com.phodal.shire.llm.model.ChatMessage
import com.phodal.shirecore.agent.InteractionType
import com.phodal.shirelang.compiler.hobbit.HobbitHole
import com.phodal.shirelang.run.ShireConfiguration
import com.phodal.shirelang.run.runner.tasks.FileGenerateTask

data class ShireRunnerContext(
val configuration: ShireConfiguration,
Expand All @@ -25,12 +30,29 @@ abstract class ShireRunner(open val context: ShireRunnerContext) {
}

fun handleResult() {
val msgs: List<ChatMessage> = listOf()
val targetFile = context.editor?.virtualFile

when (context.hole?.interaction) {
InteractionType.AppendCursor -> TODO()
InteractionType.AppendCursorStream -> TODO()
InteractionType.OutputFile -> TODO()
InteractionType.ReplaceSelection -> TODO()
InteractionType.ReplaceCurrentFile -> TODO()
InteractionType.OutputFile -> {
// todo: replace real file name
val fileName = targetFile?.name
val task = FileGenerateTask(context.myProject, msgs, fileName)
ProgressManager.getInstance()
.runProcessWithProgressAsynchronously(task, BackgroundableProcessIndicator(task))
}
InteractionType.ReplaceSelection -> {
}
InteractionType.ReplaceCurrentFile -> {
// todo: replace real file name
val fileName = targetFile?.name
val task = FileGenerateTask(context.myProject, msgs, fileName)

ProgressManager.getInstance()
.runProcessWithProgressAsynchronously(task, BackgroundableProcessIndicator(task))
}
InteractionType.InsertBeforeSelection -> {
TODO()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.phodal.shirelang.run.runner.tasks

import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileTypes.PlainTextLanguage
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import com.phodal.shire.llm.LlmProvider
import com.phodal.shire.llm.model.ChatMessage
import com.phodal.shire.llm.model.ChatRole
import com.phodal.shirecore.markdown.Code
import com.phodal.shirelang.ShireBundle
import kotlinx.coroutines.flow.cancellable
import kotlinx.coroutines.runBlocking
import java.nio.file.Path
import kotlin.io.path.Path
import kotlinx.coroutines.flow.*

class FileGenerateTask(
@JvmField val project: Project,
val messages: List<ChatMessage>,
val fileName: String?,
val codeOnly: Boolean = false,
val taskName: String = ShireBundle.message("intentions.request.background.process.title")
) :
Task.Backgroundable(project, taskName) {
private val projectRoot = project.guessProjectDir()!!

override fun run(indicator: ProgressIndicator) {
val requestPrompt = messages.filter { it.role == ChatRole.User }.joinToString("\n") { it.content }
val systemPrompt = messages.filter { it.role == ChatRole.System }.joinToString("\n") { it.content }

val stream = LlmProvider.provider(project)?.stream(requestPrompt, systemPrompt, false)
?: return

var result = ""
runBlocking {
stream.cancellable().collect {
result += it
}
}

val inferFileName = if (fileName == null) {
val language = Code.parse(result).language
val timestamp = System.currentTimeMillis()
"output-" + timestamp + if (language == PlainTextLanguage.INSTANCE) ".txt" else ".$language"
} else {
fileName
}

val file = project.guessProjectDir()!!.toNioPath().resolve(inferFileName).toFile()
if (!file.exists()) {
file.createNewFile()
}

if (codeOnly) {
val code = Code.parse(result).text
file.writeText(code)
refreshAndOpenInEditor(file.toPath(), projectRoot)
return
} else {
file.writeText(result)
refreshAndOpenInEditor(Path(projectRoot.path), projectRoot)
}
}

protected fun refreshAndOpenInEditor(file: Path, parentDir: VirtualFile) {
runBlocking {
ProgressManager.getInstance().run(object : Modal(project, "Refreshing Project Model", true) {
override fun run(indicator: ProgressIndicator) {
repeat(5) {
val virtualFile = LocalFileSystem.getInstance().findFileByNioFile(file)
if (virtualFile == null) {
VfsUtil.markDirtyAndRefresh(true, true, true, parentDir)
} else {
try {
FileEditorManager.getInstance(project).openFile(virtualFile, true)
return
} catch (e: Exception) {
//
}
}
}
}
})
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ shire.llm.done=\nDone!

shire.prompt.fix.command=You are a top software developer in the world, which can help me to fix the issue.\nWhen I use shell-like language and compile the script, I got an error, can you help me to fix it?\n\nOrigin script:\n```\n{0}\n```\n\nScript with result:\n####\n{1}\n####
shire.prompt.fix.run-result=You are a top software developer in the world, which can help me to fix the issue.\n\nHere is the run result, can you help me to fix it?\nRun result:\n####\n{0}\n####
intentions.request.background.process.title=Generate File
10 changes: 0 additions & 10 deletions src/main/kotlin/com/phodal/shire/llm/LlmProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,5 @@ interface LlmProvider {
providers.first()
}
}

enum class ChatRole {
System,
Assistant,
User;

fun roleName(): String {
return this.name.lowercase()
}
}
}
}
12 changes: 11 additions & 1 deletion src/main/kotlin/com/phodal/shire/llm/model/ChatMessage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@ package com.phodal.shire.llm.model

import kotlinx.serialization.Serializable

enum class ChatRole {
System,
Assistant,
User;

fun roleName(): String {
return this.name.lowercase()
}
}

@Serializable
data class ChatMessage(val role: String, val content: String)
data class ChatMessage(val role: ChatRole, val content: String)

@Serializable
data class CustomRequest(val chatMessages: List<ChatMessage>)

0 comments on commit 9bf98d5

Please sign in to comment.