From 0a30f7c06a0ab082d504fff756dfbbff7a7fd1d4 Mon Sep 17 00:00:00 2001 From: Andrew Charneski Date: Sat, 25 Nov 2023 02:08:03 -0500 Subject: [PATCH] fixes --- .../simiacryptus/skyenet/core/Interpreter.kt | 1 + .../skyenet/core/actors/ActorSystem.kt | 4 +- .../skyenet/core/actors/BaseActor.kt | 25 +--- .../skyenet/core/actors/CodingActor.kt | 138 ++++++++++-------- .../skyenet/core/actors/ImageActor.kt | 18 ++- .../skyenet/core/actors/ParsedActor.kt | 21 ++- .../skyenet/core/actors/SimpleActor.kt | 20 ++- .../core/actors/opt/ActorOptimization.kt | 6 +- .../actors/record/CodingActorInterceptor.kt | 80 +--------- .../actors/record/ImageActorInterceptor.kt | 12 +- .../actors/record/ParsedActorInterceptor.kt | 24 ++- .../actors/record/SimpleActorInterceptor.kt | 12 +- .../skyenet/core/actors/test/ActorTestBase.kt | 17 ++- .../core/actors/test/CodingActorTestBase.kt | 4 +- .../core/actors/test/ImageActorTestBase.kt | 5 +- .../core/actors/test/ParsedActorTestBase.kt | 4 +- .../skyenet/core/platform/ClientManager.kt | 16 +- .../skyenet/groovy/GroovyInterpreter.kt | 4 +- .../skyenet/kotlin/KotlinInterpreter.kt | 34 ++--- .../skyenet/scala/ScalaLocalInterpreter.scala | 7 +- .../skyenet/webui/test/CodingActorTestApp.kt | 4 +- .../skyenet/webui/test/ImageActorTestApp.kt | 3 +- .../skyenet/webui/test/ParsedActorTestApp.kt | 2 +- .../skyenet/webui/test/SimpleActorTestApp.kt | 2 +- 24 files changed, 219 insertions(+), 244 deletions(-) diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/Interpreter.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/Interpreter.kt index 55c2e60c..9da6422e 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/Interpreter.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/Interpreter.kt @@ -3,6 +3,7 @@ package com.simiacryptus.skyenet.core interface Interpreter { fun getLanguage(): String + fun symbols() : Map fun run(code: String): Any? fun validate(code: String): Throwable? diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ActorSystem.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ActorSystem.kt index ab26dd5f..eb4d5917 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ActorSystem.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ActorSystem.kt @@ -12,13 +12,13 @@ import com.simiacryptus.skyenet.core.util.JsonFunctionRecorder import java.io.File open class ActorSystem>( - private val actors: Map>, + private val actors: Map>, val dataStorage: DataStorage, val user: User?, val session: Session ) { private val sessionDir = dataStorage.getSessionDir(user, session) - fun getActor(actor: T): BaseActor<*> { + fun getActor(actor: T): BaseActor<*,*> { val wrapper = getWrapper(actor.name) return when (val baseActor = actors[actor]) { null -> throw RuntimeException("No actor for $actor") diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/BaseActor.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/BaseActor.kt index bdbbe1f9..d7ee8d34 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/BaseActor.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/BaseActor.kt @@ -1,41 +1,28 @@ package com.simiacryptus.skyenet.core.actors -import com.fasterxml.jackson.annotation.JsonIgnore import com.simiacryptus.jopenai.API import com.simiacryptus.jopenai.ApiModel -import com.simiacryptus.jopenai.ClientUtil.toContentList import com.simiacryptus.jopenai.OpenAIClient import com.simiacryptus.jopenai.models.ChatModels import com.simiacryptus.jopenai.models.OpenAIModel -import com.simiacryptus.jopenai.models.OpenAITextModel -abstract class BaseActor( +abstract class BaseActor( open val prompt: String, val name: String? = null, val model: ChatModels = ChatModels.GPT35Turbo, val temperature: Double = 0.3, ) { - abstract fun answer(vararg messages: ApiModel.ChatMessage, api: API): T - open fun response(vararg messages: ApiModel.ChatMessage, model: OpenAIModel = this.model, api: API) = (api as OpenAIClient).chat( + abstract fun answer(vararg messages: ApiModel.ChatMessage, input: I, api: API): R + open fun response(vararg input: ApiModel.ChatMessage, model: OpenAIModel = this.model, api: API) = (api as OpenAIClient).chat( ApiModel.ChatRequest( - messages = ArrayList(messages.toList()), + messages = ArrayList(input.toList()), temperature = temperature, model = this.model.modelName, ), model = this.model ) - open fun answer(vararg questions: String, api: API): T = answer(*chatMessages(*questions), api = api) + open fun answer(input: I, api: API): R = answer(*chatMessages(input), input=input, api = api) - fun chatMessages(vararg questions: String) = arrayOf( - ApiModel.ChatMessage( - role = com.simiacryptus.jopenai.ApiModel.Role.system, - content = prompt.toContentList() - ), - ) + questions.map { - ApiModel.ChatMessage( - role = com.simiacryptus.jopenai.ApiModel.Role.user, - content = it.toContentList() - ) - } + abstract fun chatMessages(questions: I): Array } \ No newline at end of file diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/CodingActor.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/CodingActor.kt index 7cdd4ae1..0423215e 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/CodingActor.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/CodingActor.kt @@ -26,21 +26,23 @@ open class CodingActor( model: ChatModels = ChatModels.GPT35Turbo, val fallbackModel: ChatModels = ChatModels.GPT4Turbo, temperature: Double = 0.1, - val autoEvaluate: Boolean = false, private val fixIterations: Int = 3, private val fixRetries: Int = 2, val runtimeSymbols: Map = mapOf() -) : BaseActor( +) : BaseActor( prompt = "", name = name, model = model, temperature = temperature, ) { + val interpreter: Interpreter get() = interpreterClass.java.getConstructor(Map::class.java).newInstance(symbols + runtimeSymbols) - data class ExecutionResult( - val resultValue: String, - val resultOutput: String + data class CodeRequest( + val messages: List, + val codePrefix: String = "", + val autoEvaluate: Boolean = false ) + interface CodeResult { enum class Status { Coding, Correcting, Success, Failure @@ -48,9 +50,14 @@ open class CodingActor( fun getStatus(): Status fun getCode(): String - fun run(): ExecutionResult + fun result(): ExecutionResult } + data class ExecutionResult( + val resultValue: String, + val resultOutput: String + ) + override val prompt: String get() = if (symbols.isNotEmpty()) """ |You will translate natural language instructions into @@ -81,41 +88,49 @@ open class CodingActor( |""".trimMargin().trim() }.joinToString("\n") - open val interpreter: Interpreter by lazy { interpreterClass.java.getConstructor(Map::class.java).newInstance(symbols + runtimeSymbols) } val language: String by lazy { interpreter.getLanguage() } - override fun answer(vararg questions: String, api: API): CodeResult = - if (!autoEvaluate) answer(*chatMessages(*questions), api = api) - else answerWithAutoEval(*chatMessages(*questions), api = api).first + override fun chatMessages(questions: CodeRequest): Array { + //injectCodePrefix + var chatMessages = arrayOf( + ChatMessage( + role = Role.system, + content = prompt.toContentList() + ), + ) + questions.messages.map { + ChatMessage( + role = Role.user, + content = it.toContentList() + ) + } + if (questions.codePrefix.isNotBlank()) { + chatMessages = injectCodePrefix(chatMessages, questions.codePrefix) + } + return chatMessages - override fun answer(vararg messages: ChatMessage, api: API): CodeResult = - if (!autoEvaluate) CodeResultImpl(*messages, api = (api as OpenAIClient)) - else answerWithAutoEval(*messages, api = api).first + } - open fun answerWithPrefix( + fun answerWithPrefix( codePrefix: String, vararg messages: ChatMessage, api: API - ): CodeResult = - if (!autoEvaluate) CodeResultImpl(*injectCodePrefix(messages, codePrefix), api = (api as OpenAIClient)) - else answerWithAutoEval(*injectCodePrefix(messages, codePrefix), api = api, codePrefix=codePrefix).first - - open fun answerWithAutoEval( - vararg messages: String, - api: API, - codePrefix: String = "" - ) = answerWithAutoEval(*injectCodePrefix(chatMessages(*messages), codePrefix), api = api) + ): CodeResult = answer(CodeRequest( + messages = messages.map { it.content?.first()?.text!! }.toList(), + codePrefix = codePrefix + ), api = api) - open fun answerWithAutoEval( + override fun answer( vararg messages: ChatMessage, + input: CodeRequest, api: API, - codePrefix: String = "" - ): Pair { - var result = CodeResultImpl(*messages, api = (api as OpenAIClient), codePrefix = codePrefix) + ): CodeResult { + var result = CodeResultImpl(*messages, api = (api as OpenAIClient), codePrefix = input.codePrefix) + if(!input.autoEvaluate) return result var lastError: Throwable? = null for (i in 0..fixIterations) try { - return result to result.run() + result.result() + return result } catch (ex: Throwable) { lastError = ex result = run { @@ -123,8 +138,8 @@ open class CodingActor( val renderedResponse = getRenderedResponse(respondWithCode.second) val codedInstruction = getCode(language, respondWithCode.second) log.info("Response: \n\t${renderedResponse.replace("\n", "\n\t", false)}".trimMargin()) - log.info("Code: \n\t${codedInstruction.replace("\n", "\n\t", false)}".trimMargin()) - CodeResultImpl(*messages, codePrefix = codedInstruction, api = api) + log.info("New Code: \n\t${codedInstruction.replace("\n", "\n\t", false)}".trimMargin()) + CodeResultImpl(*messages, codePrefix = input.codePrefix, api = api, givenCode = codedInstruction) } } throw RuntimeException( @@ -138,32 +153,12 @@ open class CodingActor( |``` |${lastError?.message} |``` - |""".trimMargin().trim() + |""".trimMargin().trim(), lastError ) } - open fun implement( - self: CodeResult, - api: OpenAIClient, - messages: Array, - codePrefix: String, - model: ChatModels - ): String { - var request = ChatRequest() - request = request.copy(messages = ArrayList(messages.toList())) - val response = chat(api, request, this.model) - val codeBlocks = extractCodeBlocks(response) - for (codingAttempt in 0..fixRetries) { - val renderedResponse = getRenderedResponse(codeBlocks) - val codedInstruction = getCode(language, codeBlocks) - log.info("Response: \n\t${renderedResponse.replace("\n", "\n\t", false)}".trimMargin()) - log.info("Code: \n\t${codedInstruction.replace("\n", "\n\t", false)}".trimMargin()) - return validateAndFix(self, codedInstruction, codePrefix, api, messages, model) ?: continue - } - return "" - } - open fun validateAndFix( + private fun validateAndFix( self: CodeResult, initialCode: String, codePrefix: String, @@ -186,7 +181,7 @@ open class CodingActor( val response = getRenderedResponse(respondWithCode.second) workingCode = getCode(language, respondWithCode.second) log.info("Response: \n\t${response.replace("\n", "\n\t", false)}".trimMargin()) - log.info("Code: \n\t${workingCode.replace("\n", "\n\t", false)}".trimMargin()) + log.info("New Code: \n\t${workingCode.replace("\n", "\n\t", false)}".trimMargin()) } } return null @@ -218,13 +213,14 @@ open class CodingActor( vararg messages: ChatMessage, val codePrefix: String = "", api: OpenAIClient, + val givenCode: String? = null, ) : CodeResult { var _status = CodeResult.Status.Coding - override fun getStatus(): CodeResult.Status { - return _status - } - private val impl by lazy { + override fun getStatus() = _status + + private val _code by lazy { + if(null != givenCode) return@lazy givenCode var codedInstruction = implement( this, api, messages, codePrefix = codePrefix, model ) @@ -239,11 +235,31 @@ open class CodingActor( } codedInstruction } + private fun implement( + self: CodeResult, + api: OpenAIClient, + messages: Array, + codePrefix: String, + model: ChatModels + ): String { + val request = ChatRequest(messages = ArrayList(messages.toList())) + val response = chat(api, request, model) + val codeBlocks = extractCodeBlocks(response) + for (codingAttempt in 0..fixRetries) { + val renderedResponse = getRenderedResponse(codeBlocks) + val codedInstruction = getCode(language, codeBlocks) + log.info("Response: \n\t${renderedResponse.replace("\n", "\n\t", false)}".trimMargin()) + log.info("New Code: \n\t${codedInstruction.replace("\n", "\n\t", false)}".trimMargin()) + return validateAndFix(self, codedInstruction, codePrefix, api, messages, model) ?: continue + } + return "" + } @JsonIgnore - override fun getCode(): String = impl + override fun getCode(): String = _code - override fun run() = execute(codePrefix + "\n" + getCode().sortCode()) + private val executionResult by lazy { execute((codePrefix + "\n" + getCode()).sortCode()) } + override fun result() = executionResult } private fun injectCodePrefix( @@ -283,7 +299,8 @@ open class CodingActor( |Correct the code and try again. |""".trimMargin().trim().toContentList() ) - )) + ) + ) ) val response = chat(api, request, model) val codeBlocks = extractCodeBlocks(response) @@ -426,4 +443,3 @@ open class CodingActor( } } - diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ImageActor.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ImageActor.kt index e3619288..dcd325b7 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ImageActor.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ImageActor.kt @@ -1,8 +1,10 @@ package com.simiacryptus.skyenet.core.actors import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.ApiModel import com.simiacryptus.jopenai.ApiModel.ChatMessage import com.simiacryptus.jopenai.ApiModel.ImageGenerationRequest +import com.simiacryptus.jopenai.ClientUtil.toContentList import com.simiacryptus.jopenai.OpenAIClient import com.simiacryptus.jopenai.models.ChatModels import com.simiacryptus.jopenai.models.ImageModels @@ -16,12 +18,24 @@ open class ImageActor( temperature: Double = 0.3, val width: Int = 1024, val height: Int = 1024, -) : BaseActor( +) : BaseActor, ImageResponse>( prompt = prompt, name = name, model = textModel, temperature = temperature, ) { + override fun chatMessages(questions: List) = arrayOf( + ChatMessage( + role = ApiModel.Role.system, + content = prompt.toContentList() + ), + ) + questions.map { + ChatMessage( + role = ApiModel.Role.user, + content = it.toContentList() + ) + } + private inner class ImageResponseImpl(vararg messages: ChatMessage, val api: API) : ImageResponse { private val _text: String by lazy { response(*messages, api = api).choices.first().message?.content ?: throw RuntimeException("No response") } @@ -38,7 +52,7 @@ open class ImageActor( } } - override fun answer(vararg messages: ChatMessage, api: API): ImageResponse { + override fun answer(vararg messages: ChatMessage, input: List, api: API): ImageResponse { return ImageResponseImpl(*messages, api = api) } } diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ParsedActor.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ParsedActor.kt index ca4b5118..45116be0 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ParsedActor.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/ParsedActor.kt @@ -1,26 +1,39 @@ package com.simiacryptus.skyenet.core.actors import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.ApiModel +import com.simiacryptus.jopenai.ClientUtil.toContentList import com.simiacryptus.jopenai.OpenAIClient import com.simiacryptus.jopenai.models.ChatModels import com.simiacryptus.jopenai.proxy.ChatProxy import java.util.function.Function -open class ParsedActor( +open class ParsedActor( val parserClass: Class>, prompt: String, name: String? = parserClass.simpleName, model: ChatModels = ChatModels.GPT35Turbo, temperature: Double = 0.3, -) : BaseActor>( +) : BaseActor, ParsedResponse>( prompt = prompt, name = name, model = model, temperature = temperature, ) { val resultClass: Class by lazy { parserClass.getMethod("apply", String::class.java).returnType as Class } + override fun chatMessages(questions: List) = arrayOf( + ApiModel.ChatMessage( + role = ApiModel.Role.system, + content = prompt.toContentList() + ), + ) + questions.map { + ApiModel.ChatMessage( + role = ApiModel.Role.user, + content = it.toContentList() + ) + } - private inner class ParsedResponseImpl(vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, api: API) : ParsedResponse(resultClass) { + private inner class ParsedResponseImpl(vararg messages: ApiModel.ChatMessage, api: API) : ParsedResponse(resultClass) { private val parser: Function = ChatProxy( clazz = parserClass, api = (api as OpenAIClient), @@ -33,7 +46,7 @@ open class ParsedActor( override fun getObj(clazz: Class): T = _obj } - override fun answer(vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, api: API): ParsedResponse { + override fun answer(vararg messages: ApiModel.ChatMessage, input: List, api: API): ParsedResponse { return ParsedResponseImpl(*messages, api = api) } } diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/SimpleActor.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/SimpleActor.kt index 438a3b23..e7fc1e0b 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/SimpleActor.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/SimpleActor.kt @@ -1,22 +1,32 @@ package com.simiacryptus.skyenet.core.actors import com.simiacryptus.jopenai.API +import com.simiacryptus.jopenai.ApiModel +import com.simiacryptus.jopenai.ClientUtil.toContentList import com.simiacryptus.jopenai.models.ChatModels -import com.simiacryptus.jopenai.models.OpenAITextModel open class SimpleActor( prompt: String, name: String? = null, model: ChatModels = ChatModels.GPT35Turbo, temperature: Double = 0.3, -) : BaseActor( +) : BaseActor,String>( prompt = prompt, name = name, model = model, temperature = temperature, ) { - override fun answer(vararg questions: String, api: API): String = answer(*chatMessages(*questions), api = api) - - override fun answer(vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, api: API): String = response(*messages, api = api).choices.first().message?.content ?: throw RuntimeException("No response") + override fun answer(vararg messages: ApiModel.ChatMessage, input: List, api: API): String = response(*messages, api = api).choices.first().message?.content ?: throw RuntimeException("No response") + override fun chatMessages(questions: List) = arrayOf( + ApiModel.ChatMessage( + role = ApiModel.Role.system, + content = prompt.toContentList() + ), + ) + questions.map { + ApiModel.ChatMessage( + role = ApiModel.Role.user, + content = it.toContentList() + ) + } } diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/opt/ActorOptimization.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/opt/ActorOptimization.kt index 09551631..daa75558 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/opt/ActorOptimization.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/opt/ActorOptimization.kt @@ -35,10 +35,10 @@ open class ActorOptimization( val retries: Int = 3 ) - open fun runGeneticGenerations( + open fun ,T:Any> runGeneticGenerations( prompts: List, testCases: List, - actorFactory: (String) -> BaseActor, + actorFactory: (String) -> BaseActor, resultMapper: (T) -> String, selectionSize: Int = defaultSelectionSize(prompts), populationSize: Int = defaultPositionSize(selectionSize, prompts), @@ -54,7 +54,7 @@ open class ActorOptimization( role = ApiModel.Role.system, content = actor.prompt.toContentList() ), - ) + testCase.userMessages).toTypedArray(), api = api) + ) + testCase.userMessages).toTypedArray(), input = listOf(actor.prompt) as I, api = api) testCase.expectations.map { it.score(api, resultMapper(answer)) }.average() }.average() } diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/CodingActorInterceptor.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/CodingActorInterceptor.kt index 45d5c497..3cb7f752 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/CodingActorInterceptor.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/CodingActorInterceptor.kt @@ -2,8 +2,6 @@ package com.simiacryptus.skyenet.core.actors.record import com.simiacryptus.jopenai.API import com.simiacryptus.jopenai.ApiModel.ChatMessage -import com.simiacryptus.jopenai.OpenAIClient -import com.simiacryptus.jopenai.models.ChatModels import com.simiacryptus.jopenai.models.OpenAIModel import com.simiacryptus.skyenet.core.actors.CodingActor import com.simiacryptus.skyenet.core.util.FunctionWrapper @@ -20,19 +18,13 @@ class CodingActorInterceptor( model = inner.model, fallbackModel = inner.fallbackModel, temperature = inner.temperature, - autoEvaluate = inner.autoEvaluate, ) { - override fun answer(vararg messages: ChatMessage, api: API) = - functionInterceptor.wrap(messages.toList().toTypedArray()) { - inner.answer(*it, api = api) - } - override fun response( - vararg messages: ChatMessage, + vararg input: ChatMessage, model: OpenAIModel, api: API ) = functionInterceptor.wrap( - messages.toList().toTypedArray(), + input.toList().toTypedArray(), model ) { messages: Array, model: OpenAIModel -> @@ -40,71 +32,9 @@ class CodingActorInterceptor( } - override fun answer(vararg questions: String, api: API) = functionInterceptor.wrap(questions) { - inner.answer(*it, api = api) - } - - override fun answerWithPrefix( - codePrefix: String, - vararg messages: ChatMessage, - api: API - ) = functionInterceptor.wrap( - messages.toList().toTypedArray(), - codePrefix - ) { messages: Array, - codePrefix: String -> - inner.answerWithPrefix(codePrefix, *messages, api = api) - } - - override fun answerWithAutoEval( - vararg messages: String, - api: API, - codePrefix: String - ) = functionInterceptor.wrap( - messages.toList().toTypedArray(), - codePrefix - ) { messages: Array, - codePrefix: String -> - inner.answerWithAutoEval(*messages, api = api, codePrefix = codePrefix) - } - - override fun answerWithAutoEval( - vararg messages: ChatMessage, - api: API, - codePrefix: String, - ) = functionInterceptor.wrap(messages.toList().toTypedArray()) { - inner.answerWithAutoEval(*messages, api = api, codePrefix = codePrefix) - } - - override fun implement( - self: CodeResult, - brain: OpenAIClient, - messages: Array, - codePrefix: String, - model: ChatModels - ) = functionInterceptor.wrap( - messages.toList().toTypedArray(), - codePrefix - ) { messages: Array, - codePrefix: String -> - inner.implement(self, brain, messages, codePrefix, inner.model) - } - - override fun validateAndFix( - self: CodeResult, - initialCode: String, - codePrefix: String, - brain: OpenAIClient, - messages: Array, - model: ChatModels - ) = functionInterceptor.wrap( - messages.toList().toTypedArray(), - initialCode, - codePrefix - ) { messages: Array, - initialCode: String, - codePrefix: String -> - inner.validateAndFix(self, initialCode, codePrefix, brain, messages, inner.model) ?: "" + override fun answer(vararg messages: ChatMessage, input: CodeRequest, api: API) = + functionInterceptor.wrap(messages, input) { messages, input -> + inner.answer(*messages, input=input, api = api) } override fun execute(code: String) = functionInterceptor.wrap(code) { diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/ImageActorInterceptor.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/ImageActorInterceptor.kt index 522d0e32..3ff7b6b9 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/ImageActorInterceptor.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/ImageActorInterceptor.kt @@ -17,23 +17,23 @@ class ImageActorInterceptor( width = inner.width, height = inner.height, ) { - override fun answer(vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, api: API) = + override fun answer(vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, input: List, api: API) = functionInterceptor.wrap(messages.toList().toTypedArray()) { - inner.answer(*it, api = api) + inner.answer(*it, input=input, api = api) } override fun response( - vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, + vararg input: com.simiacryptus.jopenai.ApiModel.ChatMessage, model: OpenAIModel, api: API - ) = functionInterceptor.wrap(messages.toList().toTypedArray(), model) { + ) = functionInterceptor.wrap(input.toList().toTypedArray(), model) { messages: Array, model: OpenAIModel -> inner.response(*messages, model = model, api = api) } - override fun answer(vararg questions: String, api: API) = functionInterceptor.wrap(questions) { - inner.answer(*it, api = api) + override fun answer(input: List, api: API) = functionInterceptor.wrap(input) { + inner.answer(it, api = api) } } \ No newline at end of file diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/ParsedActorInterceptor.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/ParsedActorInterceptor.kt index 868e06bf..4f72aff6 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/ParsedActorInterceptor.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/ParsedActorInterceptor.kt @@ -3,35 +3,33 @@ package com.simiacryptus.skyenet.core.actors.record import com.simiacryptus.jopenai.API import com.simiacryptus.jopenai.models.OpenAIModel import com.simiacryptus.skyenet.core.actors.ParsedActor +import com.simiacryptus.skyenet.core.actors.ParsedResponse import com.simiacryptus.skyenet.core.util.FunctionWrapper -class ParsedActorInterceptor( - val inner: ParsedActor, +class ParsedActorInterceptor( + val inner: ParsedActor<*>, private val functionInterceptor: FunctionWrapper, -) : ParsedActor( - parserClass = inner.parserClass, +) : ParsedActor( + parserClass = inner.parserClass as Class>, prompt = inner.prompt, name = inner.name, model = inner.model, temperature = inner.temperature, ) { - override fun answer(vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, api: API) = + + override fun answer(vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, input: List, api: API) = functionInterceptor.wrap(messages.toList().toTypedArray()) { - inner.answer(*it, api = api) - } + inner.answer(*it, input=input, api = api) + } as ParsedResponse override fun response( - vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, + vararg input: com.simiacryptus.jopenai.ApiModel.ChatMessage, model: OpenAIModel, api: API - ) = functionInterceptor.wrap(messages.toList().toTypedArray(), model) { + ) = functionInterceptor.wrap(input.toList().toTypedArray(), model) { messages: Array, model: OpenAIModel -> inner.response(*messages, model = model, api = api) } - override fun answer(vararg questions: String, api: API) = functionInterceptor.wrap(questions) { - inner.answer(*it, api = api) - } - } \ No newline at end of file diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/SimpleActorInterceptor.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/SimpleActorInterceptor.kt index 38aab9a1..121234c0 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/SimpleActorInterceptor.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/record/SimpleActorInterceptor.kt @@ -15,23 +15,23 @@ class SimpleActorInterceptor( temperature = inner.temperature, ) { - override fun answer(vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, api: API) = + override fun answer(vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, input: List, api: API) = functionInterceptor.wrap(messages.toList().toTypedArray()) { messages: Array -> - inner.answer(*messages, api = api) + inner.answer(*messages, input=input, api = api) } override fun response( - vararg messages: com.simiacryptus.jopenai.ApiModel.ChatMessage, + vararg input: com.simiacryptus.jopenai.ApiModel.ChatMessage, model: OpenAIModel, api: API - ) = functionInterceptor.wrap(messages.toList().toTypedArray(), model) { + ) = functionInterceptor.wrap(input.toList().toTypedArray(), model) { messages: Array, model: OpenAIModel -> inner.response(*messages, model = model, api = api) } - override fun answer(vararg questions: String, api: API) = functionInterceptor.wrap(questions) { - inner.answer(*it, api = api) + override fun answer(input: List, api: API) = functionInterceptor.wrap(input) { + inner.answer(it, api = api) } } \ No newline at end of file diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ActorTestBase.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ActorTestBase.kt index 5cdf3073..c8b2c427 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ActorTestBase.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ActorTestBase.kt @@ -8,20 +8,20 @@ import com.simiacryptus.skyenet.core.actors.opt.ActorOptimization import org.slf4j.LoggerFactory import org.slf4j.event.Level -abstract class ActorTestBase { +abstract class ActorTestBase { open val api = OpenAIClient(logLevel = Level.DEBUG) abstract val testCases: List - abstract val actor: BaseActor - abstract fun actorFactory(prompt: String): BaseActor - abstract fun getPrompt(actor: BaseActor): String + abstract val actor: BaseActor + abstract fun actorFactory(prompt: String): BaseActor + abstract fun getPrompt(actor: BaseActor): String abstract fun resultMapper(result: R): String open fun opt( - actor: BaseActor = this.actor, + actor: BaseActor = this.actor, testCases: List = this.testCases, - actorFactory: (String) -> BaseActor = this::actorFactory, + actorFactory: (String) -> BaseActor = this::actorFactory, resultMapper: (R) -> String = this::resultMapper ) { ActorOptimization( @@ -30,7 +30,7 @@ abstract class ActorTestBase { populationSize = 1, generations = 1, selectionSize = 1, - actorFactory = actorFactory, + actorFactory = actorFactory as (String) -> BaseActor, R>, resultMapper = resultMapper, prompts = listOf( getPrompt(actor), @@ -56,7 +56,8 @@ abstract class ActorTestBase { } } - open fun answer(messages: Array): R = actor.answer(messages = messages, api) + open fun answer(messages: Array): R = actor.answer(*messages, + input = (messages.map { it.content?.first()?.text }) as I, api=api) companion object { private val log = LoggerFactory.getLogger(ActorTestBase::class.java) diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/CodingActorTestBase.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/CodingActorTestBase.kt index ba7152c1..5adf0788 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/CodingActorTestBase.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/CodingActorTestBase.kt @@ -6,14 +6,14 @@ import com.simiacryptus.skyenet.core.actors.CodingActor import com.simiacryptus.skyenet.core.actors.CodingActor.CodeResult import kotlin.reflect.KClass -abstract class CodingActorTestBase : ActorTestBase() { +abstract class CodingActorTestBase : ActorTestBase() { abstract val interpreterClass: KClass override fun actorFactory(prompt: String): CodingActor = CodingActor( interpreterClass = interpreterClass, details = prompt, ) - override fun getPrompt(actor: BaseActor): String = (actor as CodingActor).details!! + override fun getPrompt(actor: BaseActor): String = (actor as CodingActor).details!! override fun resultMapper(result: CodeResult): String = result.getCode() } diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ImageActorTestBase.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ImageActorTestBase.kt index 1660e401..e2db5232 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ImageActorTestBase.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ImageActorTestBase.kt @@ -1,12 +1,9 @@ package com.simiacryptus.skyenet.core.actors.test -import com.simiacryptus.skyenet.core.actors.BaseActor import com.simiacryptus.skyenet.core.actors.ImageActor import com.simiacryptus.skyenet.core.actors.ImageResponse -import com.simiacryptus.skyenet.core.actors.ParsedResponse -import java.util.function.Function -abstract class ImageActorTestBase() : ActorTestBase() { +abstract class ImageActorTestBase() : ActorTestBase,ImageResponse>() { override fun actorFactory(prompt: String) = ImageActor( prompt = prompt, ) diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ParsedActorTestBase.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ParsedActorTestBase.kt index a6ed1558..a272e2a0 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ParsedActorTestBase.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/test/ParsedActorTestBase.kt @@ -7,14 +7,14 @@ import java.util.function.Function abstract class ParsedActorTestBase( private val parserClass: Class>, -) : ActorTestBase>() { +) : ActorTestBase,ParsedResponse>() { override fun actorFactory(prompt: String) = ParsedActor( parserClass = parserClass, prompt = prompt, ) - override fun getPrompt(actor: BaseActor>): String = actor.prompt + override fun getPrompt(actor: BaseActor,ParsedResponse>): String = actor.prompt override fun resultMapper(result: ParsedResponse): String = result.getText() diff --git a/core/src/main/kotlin/com/simiacryptus/skyenet/core/platform/ClientManager.kt b/core/src/main/kotlin/com/simiacryptus/skyenet/core/platform/ClientManager.kt index 398fdb41..e99a8218 100644 --- a/core/src/main/kotlin/com/simiacryptus/skyenet/core/platform/ClientManager.kt +++ b/core/src/main/kotlin/com/simiacryptus/skyenet/core/platform/ClientManager.kt @@ -5,6 +5,7 @@ import com.simiacryptus.jopenai.ClientUtil import com.simiacryptus.jopenai.OpenAIClient import com.simiacryptus.jopenai.models.OpenAIModel +import org.slf4j.LoggerFactory import org.slf4j.event.Level import java.io.File @@ -33,12 +34,19 @@ open class ClientManager { protected open fun createClient( session: Session, user: User?, logfile: File, key: String? = ClientUtil.keyTxt - ): OpenAIClient? = if (key.isNullOrBlank()) null else object : OpenAIClient( + ): OpenAIClient? = if (key.isNullOrBlank()) null else MonitoredClient(key, logfile, session, user) + + inner class MonitoredClient( + key: String, + logfile: File, + private val session: Session, + private val user: User? + ) : OpenAIClient( key = key, logLevel = Level.DEBUG, logStreams = mutableListOf( - logfile.outputStream()?.buffered() - ).filterNotNull().toMutableList(), + logfile.outputStream().buffered() + ), ) { override fun incrementTokens(model: OpenAIModel?, tokens: ApiModel.Usage) { ApplicationServices.usageManager.incrementUsage(session, user, model!!, tokens) @@ -46,5 +54,5 @@ open class ClientManager { } } - private val log = org.slf4j.LoggerFactory.getLogger(ClientManager::class.java) + private val log = LoggerFactory.getLogger(ClientManager::class.java) } \ No newline at end of file diff --git a/groovy/src/main/kotlin/com/simiacryptus/skyenet/groovy/GroovyInterpreter.kt b/groovy/src/main/kotlin/com/simiacryptus/skyenet/groovy/GroovyInterpreter.kt index 1c66046d..6e37ae97 100644 --- a/groovy/src/main/kotlin/com/simiacryptus/skyenet/groovy/GroovyInterpreter.kt +++ b/groovy/src/main/kotlin/com/simiacryptus/skyenet/groovy/GroovyInterpreter.kt @@ -6,7 +6,7 @@ import groovy.lang.Script import org.codehaus.groovy.control.CompilationFailedException import org.codehaus.groovy.control.CompilerConfiguration -open class GroovyInterpreter(defs: java.util.Map) : Interpreter { +open class GroovyInterpreter(val defs: java.util.Map) : Interpreter { private val shell: GroovyShell @@ -22,6 +22,8 @@ open class GroovyInterpreter(defs: java.util.Map) : Interpreter return "groovy" } + override fun symbols() = defs as Map + override fun run(code: String): Any? { val wrapExecution = wrapExecution { diff --git a/kotlin/src/main/kotlin/com/simiacryptus/skyenet/kotlin/KotlinInterpreter.kt b/kotlin/src/main/kotlin/com/simiacryptus/skyenet/kotlin/KotlinInterpreter.kt index a78837e6..1cb406b2 100644 --- a/kotlin/src/main/kotlin/com/simiacryptus/skyenet/kotlin/KotlinInterpreter.kt +++ b/kotlin/src/main/kotlin/com/simiacryptus/skyenet/kotlin/KotlinInterpreter.kt @@ -25,6 +25,8 @@ import org.slf4j.LoggerFactory import java.io.File import java.lang.ref.WeakReference import java.lang.reflect.Proxy +import java.net.URL +import java.net.URLClassLoader import java.util.* import java.util.Map import javax.script.Bindings @@ -34,10 +36,7 @@ import kotlin.script.experimental.api.with import kotlin.script.experimental.host.ScriptDefinition import kotlin.script.experimental.jsr223.KOTLIN_JSR223_RESOLVE_FROM_CLASSLOADER_PROPERTY import kotlin.script.experimental.jsr223.KotlinJsr223DefaultScript -import kotlin.script.experimental.jvm.JvmDependencyFromClassLoader -import kotlin.script.experimental.jvm.JvmScriptCompilationConfigurationBuilder -import kotlin.script.experimental.jvm.jvm -import kotlin.script.experimental.jvm.updateClasspath +import kotlin.script.experimental.jvm.* import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContext import kotlin.script.experimental.jvmhost.createJvmScriptDefinitionFromTemplate import kotlin.script.experimental.jvmhost.jsr223.KotlinJsr223ScriptEngineImpl @@ -45,6 +44,7 @@ import kotlin.script.experimental.jvmhost.jsr223.KotlinJsr223ScriptEngineImpl open class KotlinInterpreter( private val defs: Map = HashMap() as Map ) : Interpreter { + override fun symbols() = defs as kotlin.collections.Map override fun validate(code: String): Throwable? { val messageCollector = MessageCollectorImpl(code) @@ -124,33 +124,18 @@ open class KotlinInterpreter( protected open fun jvmCompilerArguments(code: String): K2JVMCompilerArguments { val arguments = K2JVMCompilerArguments() - //arguments.fragmentSources = arrayOf(tempFile.absolutePath) -// arguments.allowNoSourceFiles = false arguments.expression = code arguments.classpath = System.getProperty("java.class.path") -// arguments.compileJava = true -// arguments.allowAnyScriptsInSourceRoots = true -// arguments.allowUnstableDependencies = false -// arguments.checkPhaseConditions = true arguments.enableDebugMode = true -// arguments.enableSignatureClashChecks = true arguments.extendedCompilerChecks = true -// arguments.linkViaSignatures = true arguments.reportOutputFiles = true arguments.moduleName = "KotlinInterpreter" arguments.noOptimize = true -// arguments.noReflect = true arguments.script = true arguments.validateIr = true arguments.validateBytecode = true arguments.verbose = true -// arguments.javaParameters = true arguments.useTypeTable = true -// arguments.useJavac = true -// arguments.useFirExtendedCheckers = true -// arguments.destination = "kotlinBuild" -// File(arguments.destination).mkdirs() - return arguments } @@ -174,6 +159,7 @@ open class KotlinInterpreter( updateClasspath(classPath) } + protected open val scriptEngineFactory by lazy { KotlinScriptEngineFactory() } inner class KotlinScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() { @@ -188,7 +174,11 @@ open class KotlinInterpreter( } } }, - scriptDefinition.evaluationConfiguration + scriptDefinition.evaluationConfiguration.with { + jvm { + set(baseClassLoader, Thread.currentThread().contextClassLoader.isolatedClassLoader()) + } + } ) { ScriptArgsWithTypes( arrayOf(it.getBindings(ScriptContext.ENGINE_SCOPE).orEmpty()), @@ -218,7 +208,7 @@ open class KotlinInterpreter( } } throw RuntimeException( - errorMessage(code, lineNumber, column, ex.message ?: ""), ex + errorMessage(wrappedCode, lineNumber, column, ex.message ?: ""), ex ) } } @@ -261,6 +251,8 @@ open class KotlinInterpreter( | ${code.split("\n")[line - 1]} | ${" ".repeat(column - 1) + "^"} """.trimMargin().trim() + + fun ClassLoader.isolatedClassLoader() = URLClassLoader(arrayOf(), this) } override fun getLanguage(): String { diff --git a/scala/src/main/scala/com/simiacryptus/skyenet/scala/ScalaLocalInterpreter.scala b/scala/src/main/scala/com/simiacryptus/skyenet/scala/ScalaLocalInterpreter.scala index a37cab41..ead5140d 100644 --- a/scala/src/main/scala/com/simiacryptus/skyenet/scala/ScalaLocalInterpreter.scala +++ b/scala/src/main/scala/com/simiacryptus/skyenet/scala/ScalaLocalInterpreter.scala @@ -4,8 +4,9 @@ import com.simiacryptus.skyenet.core.Interpreter import com.simiacryptus.skyenet.scala.ScalaLocalInterpreter.log import java.nio.file.Paths +import java.util import java.util.function.Supplier -import scala.jdk.CollectionConverters.MapHasAsScala +import scala.jdk.CollectionConverters.{MapHasAsJava, MapHasAsScala} import scala.reflect.internal.util.Position import scala.reflect.runtime.universe._ import scala.tools.nsc.Settings @@ -148,4 +149,8 @@ class ScalaLocalInterpreter(javaDefs: java.util.Map[String, Object]) extends Int override def wrapExecution[T](fn: Supplier[T]): T = fn.get() + override def symbols(): util.Map[String, AnyRef] = defs.map { t => + (t._1, t._2.asInstanceOf[AnyRef]) + }.asJava + } \ No newline at end of file diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/CodingActorTestApp.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/CodingActorTestApp.kt index e9c633f6..f8fba397 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/CodingActorTestApp.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/CodingActorTestApp.kt @@ -30,7 +30,7 @@ open class CodingActorTestApp( val message = ui.newTask() try { message.echo(renderMarkdown(userMessage)) - val response = actor.answer(userMessage, api = api) + val response = actor.answer(CodingActor.CodeRequest(listOf(userMessage)), api = api) val canPlay = ApplicationServices.authorizationManager.isAuthorized( this::class.java, user, @@ -39,7 +39,7 @@ open class CodingActorTestApp( val playLink = if (!canPlay) "" else { ui.hrefLink("▶", "href-link play-button") { message.add("Running...") - val result = response.run() + val result = response.result() message.complete( """ |
${result.resultValue}
diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/ImageActorTestApp.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/ImageActorTestApp.kt index 60be2062..faecf7bd 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/ImageActorTestApp.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/ImageActorTestApp.kt @@ -35,7 +35,8 @@ open class ImageActorTestApp( try { val actor = getSettings(session, user)?.actor ?: actor message.echo(renderMarkdown(userMessage)) - val response = actor.answer(userMessage, api = api) + val response = actor.answer( + listOf(userMessage), api = api) message.verbose(response.getText()) message.image(response.getImage()) message.complete() diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/ParsedActorTestApp.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/ParsedActorTestApp.kt index 16651af2..9b52e3e4 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/ParsedActorTestApp.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/ParsedActorTestApp.kt @@ -28,7 +28,7 @@ open class ParsedActorTestApp( val message = ui.newTask() try { message.echo(renderMarkdown(userMessage)) - val response = actor.answer(userMessage, api = api) + val response = actor.answer(listOf(userMessage), api = api) message.complete( renderMarkdown( """ diff --git a/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/SimpleActorTestApp.kt b/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/SimpleActorTestApp.kt index 9e6fda25..180ebfdc 100644 --- a/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/SimpleActorTestApp.kt +++ b/webui/src/main/kotlin/com/simiacryptus/skyenet/webui/test/SimpleActorTestApp.kt @@ -35,7 +35,7 @@ open class SimpleActorTestApp( try { val actor = getSettings(session, user)?.actor ?: actor message.echo(renderMarkdown(userMessage)) - val response = actor.answer(userMessage, api = api) + val response = actor.answer(listOf(userMessage), api = api) message.complete(renderMarkdown(response)) } catch (e: Throwable) { log.warn("Error", e)