diff --git a/README.md b/README.md index 6c7fc797..cda6bdaa 100644 --- a/README.md +++ b/README.md @@ -76,18 +76,18 @@ Maven: com.simiacryptus skyenet-webui - 1.0.17 + 1.0.18 ``` Gradle: ```groovy -implementation group: 'com.simiacryptus', name: 'skyenet', version: '1.0.17' +implementation group: 'com.simiacryptus', name: 'skyenet', version: '1.0.18' ``` ```kotlin -implementation("com.simiacryptus:skyenet:1.0.17") +implementation("com.simiacryptus:skyenet:1.0.18") ``` ### 🌟 To Use diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 831de98f..99fd29da 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -30,7 +30,7 @@ val kotlin_version = "1.7.22" val junit_version = "5.9.2" dependencies { - implementation(group = "com.simiacryptus", name = "joe-penai", version = "1.0.19") + implementation(group = "com.simiacryptus", name = "joe-penai", version = "1.0.20") implementation(group = "org.slf4j", name = "slf4j-api", version = "2.0.5") diff --git a/core/src/main/java/com/simiacryptus/skyenet/OutputInterceptor.java b/core/src/main/java/com/simiacryptus/skyenet/OutputInterceptor.java index 0ac06e5f..5e8a6ea9 100644 --- a/core/src/main/java/com/simiacryptus/skyenet/OutputInterceptor.java +++ b/core/src/main/java/com/simiacryptus/skyenet/OutputInterceptor.java @@ -2,6 +2,8 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; public class OutputInterceptor { @@ -21,13 +23,6 @@ public static void setupInterceptor() { } private static final ByteArrayOutputStream centralStream = new ByteArrayOutputStream(); - private static final ThreadLocal threadLocalBuffer = new ThreadLocal() { - @Override - protected ByteArrayOutputStream initialValue() { - return new ByteArrayOutputStream(); - //return centralStream; - } - }; public static void initThreadOutputStream() { setOutputStream(new ByteArrayOutputStream()); @@ -37,21 +32,45 @@ public static void resetThreadOutputStream() { setOutputStream(centralStream); } + private static final Map threadLocalBuffer = new HashMap<>(); + public static void setOutputStream(ByteArrayOutputStream stream) { - threadLocalBuffer.set(stream); + threadLocalBuffer.put(Thread.currentThread(), stream); } public static ByteArrayOutputStream getOutputStream() { - return threadLocalBuffer.get(); + return threadLocalBuffer.get(Thread.currentThread()); + } + + public static String getThreadOutput() { + return getOutputStream().toString(); + } + + public static void clearThreadOutput() { + getOutputStream().reset(); + } + + public static String getGlobalOutput() { + return centralStream.toString(); + } + + public static void clearGlobalOutput() { + centralStream.reset(); } public static PrintStream createInterceptorStream(PrintStream originalStream) { + int maxGlobalBuffer = 8 * 1024 * 1024; + int maxThreadBuffer = 1024 * 1024; return new PrintStream(new ByteArrayOutputStream() { @Override public void write(int b) { originalStream.write(b); + if(centralStream.size() > maxGlobalBuffer) { + centralStream.reset(); + } + centralStream.write(b); ByteArrayOutputStream stream = getOutputStream(); - if(stream.size() > 1024 * 1024) { + if(stream.size() > maxThreadBuffer) { stream.reset(); } stream.write(b); @@ -60,6 +79,10 @@ public void write(int b) { @Override public void write(byte[] b, int off, int len) { originalStream.write(b, off, len); + if(centralStream.size() > 1024 * 1024) { + centralStream.reset(); + } + centralStream.write(b, off, len); ByteArrayOutputStream stream = getOutputStream(); if(stream.size() > 1024 * 1024) { stream.reset(); @@ -69,11 +92,4 @@ public void write(byte[] b, int off, int len) { }); } - public static String getThreadOutput() { - return getOutputStream().toString(); - } - - public static void clearThreadOutput() { - getOutputStream().reset(); - } } diff --git a/gradle.properties b/gradle.properties index 98d27202..10a05366 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # Gradle Releases -> https://github.com/gradle/gradle/releases libraryGroup = com.simiacryptus.skyenet -libraryVersion = 1.0.17 +libraryVersion = 1.0.18 gradleVersion = 7.6.1 # Opt-out flag for bundling Kotlin standard library -> https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library diff --git a/util/build.gradle.kts b/util/build.gradle.kts index 464763bd..2c9f1227 100644 --- a/util/build.gradle.kts +++ b/util/build.gradle.kts @@ -33,7 +33,7 @@ val logback_version = "1.2.12" dependencies { - implementation(group = "com.simiacryptus", name = "joe-penai", version = "1.0.19") + implementation(group = "com.simiacryptus", name = "joe-penai", version = "1.0.20") implementation(project(":core")) implementation(project(":webui")) diff --git a/webui/build.gradle.kts b/webui/build.gradle.kts index 8e99e862..7853ba65 100644 --- a/webui/build.gradle.kts +++ b/webui/build.gradle.kts @@ -32,7 +32,7 @@ val jetty_version = "11.0.17" val jackson_version = "2.15.2" dependencies { - implementation(group = "com.simiacryptus", name = "joe-penai", version = "1.0.19") + implementation(group = "com.simiacryptus", name = "joe-penai", version = "1.0.20") implementation(project(":core")) testImplementation(project(":groovy")) diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/ChatSession.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/ChatSession.kt index 1db05dc9..cb84af54 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/ChatSession.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/ChatSession.kt @@ -15,7 +15,7 @@ abstract class ChatSession( if (visiblePrompt.isNotBlank()) send("""aaa,${visiblePrompt}""") } - val messages = listOf( + open val messages = listOf( OpenAIClient.ChatMessage(OpenAIClient.ChatMessage.Role.system, systemPrompt), OpenAIClient.ChatMessage(OpenAIClient.ChatMessage.Role.assistant, hiddenPrompt), ).toMutableList() diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/OperationStatus.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/OperationStatus.kt index e437c7ee..1c407c78 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/OperationStatus.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/OperationStatus.kt @@ -22,16 +22,19 @@ class OperationStatus @JsonCreator constructor( Pending, Implemented, Running, Complete, Cancelled, Error } + companion object { + val logger = org.slf4j.LoggerFactory.getLogger(SkyenetCodingSessionServer::class.java) + } fun onMessage(code: String) { if (code.lowercase() == "run") { runSemaphore.release() - SkyenetCodingSessionServer.logger.debug("$operationID - Running") + logger.debug("$operationID - Running") } else if (code.lowercase() == "stop") { cancelFlag.set(true) thread?.interrupt() - SkyenetCodingSessionServer.logger.debug("$operationID - Stopping") + logger.debug("$operationID - Stopping") } else { - SkyenetCodingSessionServer.logger.warn("$operationID - Unknown command: $code") + logger.warn("$operationID - Unknown command: $code") } } diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/PersistentSessionBase.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/PersistentSessionBase.kt index 05b75a02..9360da75 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/PersistentSessionBase.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/PersistentSessionBase.kt @@ -47,7 +47,7 @@ abstract class PersistentSessionBase( override fun onWebSocketText(socket: WebSocketServer.MessageWebSocket, message: String) { pool.submit { - SkyenetCodingSessionServer.logger.debug("$sessionId - Received message: $message") + logger.debug("$sessionId - Received message: $message") try { val opCmdPattern = """![a-z]{3,7},.*""".toRegex() if (opCmdPattern.matches(message)) { @@ -58,7 +58,7 @@ abstract class PersistentSessionBase( onRun(message) } } catch (e: Exception) { - SkyenetCodingSessionServer.logger.warn("$sessionId - Error processing message: $message", e) + logger.warn("$sessionId - Error processing message: $message", e) } } } @@ -68,7 +68,7 @@ abstract class PersistentSessionBase( try { run(describedInstruction) } catch (e: Exception) { - SkyenetCodingSessionServer.logger.warn( + logger.warn( "$sessionId - Error processing message: $describedInstruction", e ) diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SessionServerUtil.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SessionServerUtil.kt index 3b0b2308..625dbc61 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SessionServerUtil.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SessionServerUtil.kt @@ -24,15 +24,17 @@ object SessionServerUtil { } } + val logger = org.slf4j.LoggerFactory.getLogger(SkyenetCodingSessionServer::class.java) + fun getCode(language: String, textSegments: List>) = textSegments.joinToString("\n") { if (it.first.lowercase() == "code" || it.first.lowercase() == language.lowercase()) { - SkyenetCodingSessionServer.logger.debug("Selected: $language: ${it.second}") + logger.debug("Selected: $language: ${it.second}") """ |${it.second} |""".trimMargin().trim() } else { - SkyenetCodingSessionServer.logger.debug("Not Selected: ${it.first}: ${it.second}") + logger.debug("Not Selected: ${it.first}: ${it.second}") "" } } diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetBasicChat.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetBasicChat.kt index 0a0afa3d..f5483af4 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetBasicChat.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetBasicChat.kt @@ -4,7 +4,8 @@ import com.simiacryptus.openai.OpenAIClient open class SkyenetBasicChat( applicationName: String, - oauthConfig: String? = null + oauthConfig: String? = null, + val model: OpenAIClient.Model = OpenAIClient.Models.GPT35Turbo, ) : SkyenetSessionServerBase( applicationName = applicationName, oauthConfig = oauthConfig, @@ -16,6 +17,7 @@ open class SkyenetBasicChat( val handler = MutableSessionHandler(null) val basicChatSession = BasicChatSession( parent = this@SkyenetBasicChat, + model = model, sessionId = sessionId ) handler.setDelegate(basicChatSession) diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetCodingSession.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetCodingSession.kt index b25c2474..779167cd 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetCodingSession.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetCodingSession.kt @@ -46,7 +46,7 @@ open class SkyenetCodingSession( userMessage: String, ) { OutputInterceptor.setupInterceptor() - SkyenetCodingSessionServer.logger.debug("${sessionId} - Processing message: $userMessage") + logger.debug("${sessionId} - Processing message: $userMessage") val operationID = (0..5).map { ('a'..'z').random() }.joinToString("") val status = OperationStatus( operationID = operationID, @@ -84,9 +84,9 @@ open class SkyenetCodingSession( if (!parent.autoRun) { //language=HTML send("""$messageTrail▶""") - SkyenetCodingSessionServer.logger.debug("${sessionId} - Waiting for run") + logger.debug("${sessionId} - Waiting for run") status.runSemaphore.acquire() - SkyenetCodingSessionServer.logger.debug("${sessionId} - Run received") + logger.debug("${sessionId} - Run received") } if (status.cancelFlag.get()) { status.status = OperationStatus.OperationState.Cancelled @@ -100,17 +100,17 @@ open class SkyenetCodingSession( send(messageTrail) break } catch (e: Exception) { - SkyenetCodingSessionServer.logger.info("${sessionId} - Error", e) + logger.info("${sessionId} - Error", e) //language=HTML messageTrail += """Error:${parent.toString(e)}""" status.status = OperationStatus.OperationState.Error - status.resultOutput = OutputInterceptor.getThreadOutput() + status.resultOutput = OutputInterceptor.getGlobalOutput() status.resultValue = parent.toString(e) parent.sessionDataStorage.updateOperationStatus(sessionId, operationID, status) if (retries <= 0 || status.cancelFlag.get()) { //language=HTML messageTrail += """Out of Retries!""" - SkyenetCodingSessionServer.logger.debug("${sessionId} - Out of retries") + logger.debug("${sessionId} - Out of retries") this@SkyenetCodingSession.send(messageTrail) break } else { @@ -134,7 +134,7 @@ open class SkyenetCodingSession( } catch (e: Exception) { //language=HTML messageTrail += """Error:${e.message}""" - SkyenetCodingSessionServer.logger.warn("${sessionId} - Error: ${e.message}") + logger.warn("${sessionId} - Error: ${e.message}") this@SkyenetCodingSession.send(messageTrail) } finally { parent.sessionDataStorage.updateOperationStatus(sessionId, operationID, status) @@ -161,8 +161,8 @@ open class SkyenetCodingSession( val codeBlocks = Brain.extractCodeBlocks(response) var renderedResponse = SessionServerUtil.getRenderedResponse(codeBlocks) var codedInstruction = SessionServerUtil.getCode(language, codeBlocks) - SkyenetCodingSessionServer.logger.debug("$sessionId - Response: $renderedResponse") - SkyenetCodingSessionServer.logger.debug("$sessionId - Code: $codedInstruction") + logger.debug("$sessionId - Response: $renderedResponse") + logger.debug("$sessionId - Code: $codedInstruction") status.responseText = renderedResponse status.responseCode = codedInstruction buffer.append("""${renderedResponse}""") @@ -180,8 +180,8 @@ open class SkyenetCodingSession( renderedResponse = SessionServerUtil.getRenderedResponse(respondWithCode.second) codedInstruction = SessionServerUtil.getCode(language, respondWithCode.second) buffer.append("""${renderedResponse}""") - SkyenetCodingSessionServer.logger.debug("$sessionId - Response: $renderedResponse") - SkyenetCodingSessionServer.logger.debug("$sessionId - Code: $codedInstruction") + logger.debug("$sessionId - Response: $renderedResponse") + logger.debug("$sessionId - Code: $codedInstruction") } } status.status = OperationStatus.OperationState.Implemented @@ -204,8 +204,8 @@ open class SkyenetCodingSession( brain.fixCommand(describedInstruction, codedInstruction, e, status.resultOutput) val renderedResponse = SessionServerUtil.getRenderedResponse(respondWithCode.second) val newCode = SessionServerUtil.getCode(language, respondWithCode.second) - SkyenetCodingSessionServer.logger.debug("$sessionId - Response: $renderedResponse") - SkyenetCodingSessionServer.logger.debug("$sessionId - Code: $newCode") + logger.debug("$sessionId - Response: $renderedResponse") + logger.debug("$sessionId - Code: $newCode") status.responseText = renderedResponse status.responseCode = newCode //language=HTML @@ -218,13 +218,17 @@ open class SkyenetCodingSession( codedInstruction: String, ): String { //language=HTML - SkyenetCodingSessionServer.logger.info("$sessionId - Running $codedInstruction") - OutputInterceptor.clearThreadOutput() + logger.info("$sessionId - Running $codedInstruction") + OutputInterceptor.clearGlobalOutput() val result = heart.run(codedInstruction) - SkyenetCodingSessionServer.logger.info("$sessionId - Result: $result") + logger.info("$sessionId - Result: $result") status.resultValue = result.toString() - status.resultOutput = OutputInterceptor.getThreadOutput() + val output = OutputInterceptor.getGlobalOutput() + status.resultOutput = output //language=HTML - return """Output:${OutputInterceptor.getThreadOutput()}Returns:${result}""" + return """Output:$outputReturns:${result}""" + } + companion object { + val logger = org.slf4j.LoggerFactory.getLogger(SkyenetCodingSessionServer::class.java) } } \ No newline at end of file diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetCodingSessionServer.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetCodingSessionServer.kt index bf82d542..4e15069c 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetCodingSessionServer.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetCodingSessionServer.kt @@ -38,7 +38,7 @@ abstract class SkyenetCodingSessionServer( override fun configure(context: WebAppContext, prefix: String, baseUrl: String) { super.configure(context, prefix, baseUrl) - context.addServlet(descriptorServlet, "/yamlDescriptor") + context.addServlet(descriptorServlet, prefix + "yamlDescriptor") } protected open val descriptorServlet = ServletHolder( diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetInterviewer.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetInterviewer.kt index 9ae5218a..d1cb01c0 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetInterviewer.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetInterviewer.kt @@ -36,7 +36,7 @@ open class SkyenetInterviewer( resp.status = HttpServletResponse.SC_OK resp.writer.write(describer.describe(dataClass)) } - }), "/yamlDescriptor" + }), prefix + "yamlDescriptor" ) } diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetSessionServerBase.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetSessionServerBase.kt index 33a32be9..d75c5408 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetSessionServerBase.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/SkyenetSessionServerBase.kt @@ -33,10 +33,10 @@ abstract class SkyenetSessionServerBase( FileUtils.openInputStream(File(oauthConfig)) }).configure(context) - context.addServlet(appInfo, prefix+"/appInfo") - context.addServlet(fileIndex, prefix+"/fileIndex/*") - context.addServlet(fileZip, prefix+"/fileZip") - context.addServlet(sessionList, prefix+"/sessions") + context.addServlet(appInfo, prefix+"appInfo") + context.addServlet(fileIndex, prefix+"fileIndex/*") + context.addServlet(fileZip, prefix+"fileZip") + context.addServlet(sessionList, prefix+"sessions") } protected open val fileZip = ServletHolder( diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/WebSocketServer.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/WebSocketServer.kt index a05dc93c..e4b5169c 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/body/WebSocketServer.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/body/WebSocketServer.kt @@ -93,22 +93,22 @@ abstract class WebSocketServer(val resourceBase: String) { return server } - open fun configure(server: Server, baseUrl: String) { + open fun configure(server: Server, baseUrl: String, path: String = "/") { val webAppContext = WebAppContext() webAppContext.baseResource = baseResource - webAppContext.contextPath = "/" + webAppContext.contextPath = path webAppContext.welcomeFiles = arrayOf("index.html") JettyWebSocketServletContainerInitializer.configure(webAppContext, null) - configure(webAppContext, baseUrl = baseUrl) + configure(webAppContext, path, baseUrl) server.handler = webAppContext } open val baseResource: Resource? get() = Resource.newResource(javaClass.classLoader.getResource(resourceBase)) - open fun configure(webAppContext: WebAppContext, prefix: String = "", baseUrl: String) { - webAppContext.addServlet(ServletHolder(javaClass.simpleName + "/default", defaultServlet), prefix + "/") - webAppContext.addServlet(ServletHolder(javaClass.simpleName + "/ws", webSocketHandler), prefix + "/ws/*") - webAppContext.addServlet(ServletHolder(javaClass.simpleName + "/newSession", newSessionServlet),prefix + "/newSession") + open fun configure(webAppContext: WebAppContext, prefix: String = "/", baseUrl: String) { + webAppContext.addServlet(ServletHolder(javaClass.simpleName + "/default", defaultServlet), prefix + "") + webAppContext.addServlet(ServletHolder(javaClass.simpleName + "/ws", webSocketHandler), prefix + "ws/*") + webAppContext.addServlet(ServletHolder(javaClass.simpleName + "/newSession", newSessionServlet),prefix + "newSession") } open val newSessionServlet get() = NewSessionServlet()
${parent.toString(e)}
${e.message}
${OutputInterceptor.getThreadOutput()}
${result}
$output