Skip to content

Commit

Permalink
Create SingleTaskApp.kt
Browse files Browse the repository at this point in the history
  • Loading branch information
acharneski committed Dec 10, 2024
1 parent 22c9179 commit 8a29399
Showing 1 changed file with 162 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package com.simiacryptus.skyenet.apps.general

import com.simiacryptus.jopenai.API
import com.simiacryptus.jopenai.ChatClient
import com.simiacryptus.jopenai.OpenAIClient
import com.simiacryptus.jopenai.models.ChatModel
import com.simiacryptus.skyenet.apps.plan.PlanCoordinator
import com.simiacryptus.skyenet.apps.plan.PlanSettings
import com.simiacryptus.skyenet.apps.plan.TaskConfigBase
import com.simiacryptus.skyenet.apps.plan.TaskType
import com.simiacryptus.skyenet.core.actors.ParsedActor
import com.simiacryptus.skyenet.core.platform.Session
import com.simiacryptus.skyenet.core.platform.model.User
import com.simiacryptus.skyenet.util.MarkdownUtil.renderMarkdown
import com.simiacryptus.skyenet.webui.application.ApplicationInterface
import com.simiacryptus.util.JsonUtil
import java.io.File
import java.util.*

open class SingleTaskApp(
applicationName: String = "Single Task App",
path: String = "/singleTask",
planSettings: PlanSettings,
model: ChatModel,
parsingModel: ChatModel,
domainName: String = "localhost",
showMenubar: Boolean = true,
api: API? = null,
api2: OpenAIClient,
) : PlanChatApp(
applicationName = applicationName,
path = path,
planSettings = planSettings,
model = model,
parsingModel = parsingModel,
domainName = domainName,
showMenubar = showMenubar,
api = api,
api2 = api2
) {
open fun contextData() = emptyList<String>()
private val log = org.slf4j.LoggerFactory.getLogger(SingleTaskApp::class.java)
override val stickyInput = false
override val singleInput = true

init {
val enabledTasks = TaskType.getAvailableTaskTypes(planSettings)
require(enabledTasks.size == 1) {
"SingleTaskApp requires exactly one enabled task type. Found ${enabledTasks.size}: ${enabledTasks.map { it.name }}"
}
}

override fun userMessage(
session: Session,
user: User?,
userMessage: String,
ui: ApplicationInterface,
api: API
) {
try {

log.debug("Received user message: ${JsonUtil.toJson(userMessage)}")
val task = ui.newTask(true)
task.echo(renderMarkdown(userMessage))
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: <a href=\"file:///$this\">$this</a>")
}
}
val settings = getSettings(session, user, PlanSettings::class.java) ?: planSettings
api.budget = settings.budget
val coordinator = PlanCoordinator(
user = user,
session = session,
dataStorage = dataStorage,
ui = ui,
root = settings.workingDir?.let { File(it).toPath() } ?: dataStorage.getDataDir(user, session).toPath(),
planSettings = settings
)
val taskType = TaskType.getAvailableTaskTypes(settings).first()
val describer = planSettings.describer()
val taskConfig = ParsedActor(
name = "SingleTaskChooser",
resultClass = TaskConfigBase::class.java,
prompt = """
Given the following input, choose ONE task to execute. Do not create a full plan, just select the most appropriate task types for the given input.
Available task types:
${
TaskType.getAvailableTaskTypes(coordinator.planSettings).joinToString("\n") { taskType ->
"* ${TaskType.getImpl(coordinator.planSettings, taskType).promptSegment()}"
}
}
Choose the most suitable task types and provide details of how they should be executed.
""".trimIndent(),
model = coordinator.planSettings.defaultModel,
parsingModel = coordinator.planSettings.parsingModel,
temperature = coordinator.planSettings.temperature,
describer = describer,
parserPrompt = """
Task Subtype Schema:
${
TaskType.getAvailableTaskTypes(coordinator.planSettings).joinToString("\n\n") { taskType ->
"""
${taskType.name}:
${describer.describe(taskType.taskDataClass).replace("\n", "\n ")}
""".trim()
}
}
""".trimIndent()
).answer(
listOf(userMessage) + contextData() +
listOf(
"""
Please choose the next single task to execute based on the current status.
If there are no tasks to execute, return {}.
""".trimIndent()
), api
).obj
task.add(
renderMarkdown(
"""
Executing ${taskType.name}:
```json
${JsonUtil.toJson(taskConfig)}
```
""".trimIndent()
)
)
val taskImpl = TaskType.getImpl(settings, taskConfig)
val result = StringBuilder()
taskImpl.run(
agent = coordinator,
messages = listOf(
userMessage
),
task = task,
api = api,
resultFn = { result.append(it) },
api2 = api2,
planSettings = settings,
)
task.add(renderMarkdown("Task completed. Result:\n${result}"))
task.complete()
} catch (e: Exception) {
log.error("Error processing user message", e)
ui.newTask().add(renderMarkdown("An error occurred while processing your message: ${e.message}"))
}
}

protected open fun logDebug(message: String, data: Any? = null) {
if (data != null) {
log.debug("$message: ${JsonUtil.toJson(data)}")
} else {
log.debug(message)
}
}
}

0 comments on commit 8a29399

Please sign in to comment.