diff --git a/README.md b/README.md index d96f3f8c..fad9ef9e 100644 --- a/README.md +++ b/README.md @@ -76,18 +76,18 @@ Maven: com.simiacryptus skyenet-webui - 1.1.5 + 1.1.6 ``` Gradle: ```groovy -implementation group: 'com.simiacryptus', name: 'skyenet', version: '1.1.5' +implementation group: 'com.simiacryptus', name: 'skyenet', version: '1.1.6' ``` ```kotlin -implementation("com.simiacryptus:skyenet:1.1.5") +implementation("com.simiacryptus:skyenet:1.1.6") ``` ### 🌟 To Use diff --git a/build.gradle.kts b/build.gradle.kts index 46e18853..84c66e27 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,10 +2,6 @@ fun properties(key: String) = project.findProperty(key).toString() group = properties("libraryGroup") version = properties("libraryVersion") -//plugins { -// id("org.jetbrains.kotlin.jvm") version "2.0.20" -//} - tasks { wrapper { gradleVersion = properties("gradleVersion") diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 2058c0ae..4560f284 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -33,7 +33,7 @@ val hsqldb_version = "2.7.2" dependencies { - implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.1.5") + implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.1.6") implementation(group = "org.hsqldb", name = "hsqldb", version = hsqldb_version) implementation("org.apache.commons:commons-text:1.11.0") diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/util/GetModuleRootForFile.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/util/GetModuleRootForFile.kt index 7bf3b458..84926e62 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/util/GetModuleRootForFile.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/util/GetModuleRootForFile.kt @@ -3,12 +3,15 @@ package com.simiacryptus.skyenet.core.util import java.io.File fun getModuleRootForFile(file: File): File { + if (file.isFile) { + return getModuleRootForFile(file.parentFile) + } var current = file - while (current.parentFile != null) { + do { if (current.resolve(".git").exists()) { return current } - current = current.parentFile - } + current = current.parentFile ?: break + } while (true) return file } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index cbff40b4..ada092f9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Gradle Releases -> https://github.com/gradle/gradle/releases libraryGroup = com.simiacryptus.skyenet -libraryVersion = 1.2.5 +libraryVersion = 1.2.6 gradleVersion = 7.6.1 kotlin.daemon.jvmargs=-Xmx2g diff --git a/kotlin/build.gradle.kts b/kotlin/build.gradle.kts index dab91d13..93ce6341 100644 --- a/kotlin/build.gradle.kts +++ b/kotlin/build.gradle.kts @@ -75,7 +75,6 @@ tasks { exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL } jvmArgs( - "-Xlog:class+load=info:classloader.log", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "--add-opens", "java.base/java.util=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED" diff --git a/webui/build.gradle.kts b/webui/build.gradle.kts index 5fafc433..c90595f5 100644 --- a/webui/build.gradle.kts +++ b/webui/build.gradle.kts @@ -36,7 +36,7 @@ val jackson_version = "2.17.2" dependencies { - implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.1.5") { + implementation(group = "com.simiacryptus", name = "jo-penai", version = "1.1.6") { exclude(group = "org.slf4j") } diff --git a/webui/src/main/kotlin/com/simiacryptus/diff/AddApplyFileDiffLinks.kt b/webui/src/main/kotlin/com/simiacryptus/diff/AddApplyFileDiffLinks.kt index 1b547196..dbd519a0 100644 --- a/webui/src/main/kotlin/com/simiacryptus/diff/AddApplyFileDiffLinks.kt +++ b/webui/src/main/kotlin/com/simiacryptus/diff/AddApplyFileDiffLinks.kt @@ -45,20 +45,30 @@ fun SocketManagerBase.addApplyFileDiffLinks( val headers = headerPattern.findAll(response).map { it.range to it.groupValues[1] }.toList() val findAll = codeblockPattern.findAll(response).toList() val codeblocks = findAll.filter { block -> - val header = headers.lastOrNull { it.first.last <= block.range.first } - if (header == null) { - return@filter false + try { + val header = headers.lastOrNull { it.first.last <= block.range.first } + if (header == null) { + return@filter false + } + val filename = resolve(root, header.second) + !root.resolve(filename).toFile().exists() + } catch (e: Throwable) { + log.info("Error processing code block", e) + false } - val filename = resolve(root, header.second) - !root.resolve(filename).toFile().exists() }.map { it.range to it }.toList() val patchBlocks = findAll.filter { block -> - val header = headers.lastOrNull { it.first.last <= block.range.first } - if (header == null) { - return@filter false + try { + val header = headers.lastOrNull { it.first.last <= block.range.first } + if (header == null) { + return@filter false + } + val filename = resolve(root, header.second) + root.resolve(filename).toFile().exists() + } catch (e: Throwable) { + log.info("Error processing code block", e) + false } - val filename = resolve(root, header.second) - root.resolve(filename).toFile().exists() }.map { it.range to it }.toList() // Process diff blocks and add patch links val withPatchLinks: String = patchBlocks.fold(response) { markdown, diffBlock -> @@ -156,11 +166,15 @@ fun resolve(root: Path, filename: String): String { filename } - if (!root.resolve(filename).toFile().exists()) { - root.toFile().listFilesRecursively().find { it.toString().replace("\\", "/").endsWith(filename.replace("\\", "/")) } - ?.toString()?.apply { - filename = relativizeFrom(root) - } + try { + if (!root.resolve(filename).toFile().exists()) { + root.toFile().listFilesRecursively().find { it.toString().replace("\\", "/").endsWith(filename.replace("\\", "/")) } + ?.toString()?.apply { + filename = relativizeFrom(root) + } + } + } catch (e: Throwable) { + log.error("Error resolving filename", e) } return filename diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/AbstractTask.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/AbstractTask.kt index 7afb49e3..86e7e600 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/AbstractTask.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/AbstractTask.kt @@ -25,7 +25,7 @@ abstract class AbstractTask( Completed, } - protected fun getPriorCode(planProcessingState: PlanProcessingState) = + protected open fun getPriorCode(planProcessingState: PlanProcessingState) = planTask?.task_dependencies?.joinToString("\n\n\n") { dependency -> """ |# $dependency @@ -59,7 +59,8 @@ abstract class AbstractTask( plan: Map, planProcessingState: PlanProcessingState, task: SessionTask, - api: API + api: API, + resultFn: (String) -> Unit ) companion object { diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/CommandAutoFixTask.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/CommandAutoFixTask.kt index 1be71058..1a9315cd 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/CommandAutoFixTask.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/CommandAutoFixTask.kt @@ -51,7 +51,8 @@ CommandAutoFix - Run a command and automatically fix any issues that arise plan: Map, planProcessingState: PlanProcessingState, task: SessionTask, - api: API + api: API, + resultFn: (String) -> Unit ) { val semaphore = Semaphore(0) val onComplete = { @@ -91,7 +92,7 @@ CommandAutoFix - Run a command and automatically fix any issues that arise ui = agent.ui, task = task ) - planProcessingState.taskResult[taskId] = "Command Auto Fix completed" + resultFn("Command Auto Fix completed") task.add(if (outputResult.exitCode == 0) { if (agent.planSettings.autoFix) { onComplete() diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/ForeachTask.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/ForeachTask.kt index a0a1eb69..e5c0bd1c 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/ForeachTask.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/ForeachTask.kt @@ -43,7 +43,8 @@ ForeachTask - Execute a task for each item in a list plan: Map, planProcessingState: PlanProcessingState, task: SessionTask, - api: API + api: API, + resultFn: (String) -> Unit ) { val items = planTask?.foreach_items ?: throw RuntimeException("No items specified for ForeachTask") diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/PlanCoordinator.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/PlanCoordinator.kt index b7a220e0..074395c9 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/PlanCoordinator.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/PlanCoordinator.kt @@ -249,7 +249,8 @@ class PlanCoordinator( plan = plan, planProcessingState = planProcessingState, task = task1, - api = api + api = api, + resultFn = { planProcessingState.taskResult[taskId] = it } ) } catch (e: Throwable) { log.warn("Error during task execution", e) diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/PlanningTask.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/PlanningTask.kt index d0fa7824..033ca03a 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/PlanningTask.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/PlanningTask.kt @@ -10,7 +10,6 @@ import com.simiacryptus.skyenet.apps.plan.PlanUtil.executionOrder import com.simiacryptus.skyenet.apps.plan.PlanUtil.filterPlan import com.simiacryptus.skyenet.apps.plan.PlanUtil.render import com.simiacryptus.skyenet.apps.plan.PlanningTask.PlanningTaskData -import com.simiacryptus.skyenet.apps.plan.file.AbstractFileTask import com.simiacryptus.skyenet.core.actors.ParsedResponse import com.simiacryptus.skyenet.webui.application.ApplicationInterface import com.simiacryptus.skyenet.webui.session.SessionTask @@ -59,7 +58,8 @@ class PlanningTask( plan: Map, planProcessingState: PlanProcessingState, task: SessionTask, - api: API + api: API, + resultFn: (String) -> Unit ) { val newTask = agent.ui.newTask(false).apply { add(placeholder) } fun toInput(s: String) = listOf( diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/RunShellCommandTask.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/RunShellCommandTask.kt index 35f6cdc9..c2ef7a56 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/RunShellCommandTask.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/RunShellCommandTask.kt @@ -5,7 +5,6 @@ import com.simiacryptus.jopenai.describe.Description import com.simiacryptus.jopenai.models.ApiModel import com.simiacryptus.skyenet.apps.coding.CodingAgent import com.simiacryptus.skyenet.apps.plan.RunShellCommandTask.RunShellCommandTaskData -import com.simiacryptus.skyenet.apps.plan.file.AbstractFileTask import com.simiacryptus.skyenet.core.actors.CodingActor import com.simiacryptus.skyenet.interpreter.ProcessInterpreter import com.simiacryptus.skyenet.webui.session.SessionTask @@ -73,7 +72,8 @@ Note: This task is for running simple and safe commands. Avoid executing command plan: Map, planProcessingState: PlanProcessingState, task: SessionTask, - api: API + api: API, + resultFn: (String) -> Unit ) { val semaphore = Semaphore(0) object : CodingAgent( @@ -114,7 +114,7 @@ Note: This task is for running simple and safe commands. Avoid executing command response: CodingActor.CodeResult ): String { return ui.hrefLink("Accept", "href-link play-button") { - planProcessingState.taskResult[taskId] = response.let { + response.let { """ |## Shell Command Output | @@ -127,7 +127,7 @@ Note: This task is for running simple and safe commands. Avoid executing command |${TRIPLE_TILDE} | """.trimMargin() - } + }.apply { resultFn(this) } semaphore.release() } } diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/AbstractAnalysisTask.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/AbstractAnalysisTask.kt index 8df2b44e..705599ab 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/AbstractAnalysisTask.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/AbstractAnalysisTask.kt @@ -36,7 +36,8 @@ abstract class AbstractAnalysisTask( plan: Map, planProcessingState: PlanProcessingState, task: SessionTask, - api: API + api: API, + resultFn: (String) -> Unit ) { val analysisResult = analysisActor.answer( listOf( @@ -47,7 +48,7 @@ abstract class AbstractAnalysisTask( "${getAnalysisInstruction()}:\n${getInputFileCode()}", ).filter { it.isNotBlank() }, api = api ) - planProcessingState.taskResult[taskId] = analysisResult + resultFn(analysisResult) applyChanges(agent, task, analysisResult, api) } diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/DocumentationTask.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/DocumentationTask.kt index 5bb9b6e1..a5ec7a44 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/DocumentationTask.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/DocumentationTask.kt @@ -61,7 +61,8 @@ class DocumentationTask( plan: Map, planProcessingState: PlanProcessingState, task: SessionTask, - api: API + api: API, + resultFn: (String) -> Unit ) { val semaphore = Semaphore(0) val onComplete = { @@ -78,7 +79,7 @@ class DocumentationTask( "Items to document: ${itemsToDocument.joinToString(", ")}" ).filter { it.isNotBlank() }, api ) - planProcessingState.taskResult[taskId] = docResult + resultFn(docResult) if (agent.planSettings.autoFix) { task.complete() onComplete() diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/FileModificationTask.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/FileModificationTask.kt index 4959c22b..59d9d94f 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/FileModificationTask.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/FileModificationTask.kt @@ -103,7 +103,8 @@ class FileModificationTask( plan: Map, planProcessingState: PlanProcessingState, task: SessionTask, - api: API + api: API, + resultFn: (String) -> Unit ) { if (((planTask?.input_files ?: listOf()) + (planTask?.output_files ?: listOf())).isEmpty()) { task.complete("No input files specified") @@ -121,7 +122,7 @@ class FileModificationTask( this.planTask?.task_description ?: "", ).filter { it.isNotBlank() }, api ) - planProcessingState.taskResult[taskId] = codeResult + resultFn(codeResult) if (agent.planSettings.autoFix) { val diffLinks = agent.ui.socketManager!!.addApplyFileDiffLinks( root = agent.root, diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/InquiryTask.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/InquiryTask.kt index 1c8e4dad..d042ab80 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/InquiryTask.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/apps/plan/file/InquiryTask.kt @@ -49,8 +49,7 @@ class InquiryTask( When generating insights, consider the existing project context and focus on information that is directly relevant and applicable. Focus on generating insights and information that support the task types available in the system (${ - planSettings.taskSettings.filter { it.value.enabled }.keys.joinToString(", ") - }). + planSettings.taskSettings.filter { it.value.enabled }.keys.joinToString(", ")}). This will ensure that the inquiries are tailored to assist in the planning and execution of tasks within the system's framework. """.trimMargin(), model = planSettings.getTaskSettings(TaskType.valueOf(planTask?.task_type!!)).model @@ -59,13 +58,11 @@ class InquiryTask( ) } - override fun promptSegment(): String { - return """ - Inquiry - Answer questions by reading in files and providing a summary that can be discussed with and approved by the user - ** Specify the questions and the goal of the inquiry - ** List input files to be examined when answering the questions - """.trimMargin() - } + override fun promptSegment() = """ + |Inquiry - Answer questions by reading in files and providing a summary that can be discussed with and approved by the user + | ** Specify the questions and the goal of the inquiry + | ** List input files to be examined when answering the questions + """.trimMargin() override fun run( agent: PlanCoordinator, @@ -74,7 +71,8 @@ class InquiryTask( plan: Map, planProcessingState: PlanProcessingState, task: SessionTask, - api: API + api: API, + resultFn: (String) -> Unit ) { val toInput = { it: String -> listOf( @@ -127,7 +125,7 @@ class InquiryTask( ).apply { task.add(MarkdownUtil.renderMarkdown(this, ui = agent.ui)) } - planProcessingState.taskResult[taskId] = inquiryResult + resultFn(inquiryResult) } companion object { diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/chat/ChatSocketManager.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/chat/ChatSocketManager.kt index 43a7097d..5b358411 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/chat/ChatSocketManager.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/chat/ChatSocketManager.kt @@ -12,6 +12,7 @@ import com.simiacryptus.skyenet.webui.application.ApplicationServer import com.simiacryptus.skyenet.webui.session.SessionTask import com.simiacryptus.skyenet.webui.session.SocketManagerBase import com.simiacryptus.skyenet.util.MarkdownUtil +import java.util.* open class ChatSocketManager( session: Session, @@ -43,6 +44,13 @@ open class ChatSocketManager( @Synchronized override fun onRun(userMessage: String, socket: ChatSocket) { val task = newTask() + val api = (api as ChatClient).getChildClient().apply { + val createFile = task.createFile(".logs/api-${UUID.randomUUID()}.log") + createFile.second?.apply { + logStreams += this.outputStream().buffered() + task.verbose("API log: $this") + } + } val responseContents = renderResponse(userMessage, task) task.echo(responseContents) messages += ApiModel.ChatMessage(ApiModel.Role.user, userMessage.toContentList())