feature(event-sourcing): baseline for the architecture review fixes.
- fixed the tool overlay in tui. - fixed tool calling - added schemas. - getting all sessionIds via event store. - instead of sending all events on the replay - there's a new way for replaying. - session snapshot is now a thing getting sent for previously created sessions. - added logging to important parts. - revert workflowId from WorkflowCompletedEvent.
This commit is contained in:
+33
-4
@@ -12,8 +12,13 @@ import kotlinx.coroutines.TimeoutCancellationException
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.buildJsonArray
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.put
|
||||
import kotlinx.serialization.json.putJsonObject
|
||||
import java.nio.file.Path
|
||||
|
||||
class ShellTool(
|
||||
@@ -23,18 +28,36 @@ class ShellTool(
|
||||
) : Tool, ToolExecutor {
|
||||
override val name: String = "shell"
|
||||
override val description: String = "Execute a shell command"
|
||||
override val parametersSchema: JsonObject = buildJsonObject {}
|
||||
override val parametersSchema: JsonObject = buildJsonObject {
|
||||
put("type", "object")
|
||||
putJsonObject("properties") {
|
||||
putJsonObject("argv") {
|
||||
put("type", "array")
|
||||
putJsonObject("items") { put("type", "string") }
|
||||
put("description", "Command and arguments as a list. Example: [\"bash\", \"script.sh\"]")
|
||||
}
|
||||
}
|
||||
put("required", buildJsonArray { add(JsonPrimitive("argv")) })
|
||||
}
|
||||
override val tier: Tier = Tier.T2
|
||||
override val requiredCapabilities: Set<ToolCapability> =
|
||||
setOf(ToolCapability.SHELL_EXEC, ToolCapability.PROCESS_SPAWN)
|
||||
|
||||
override fun validateRequest(request: ToolRequest): ValidationResult {
|
||||
val argv = (request.parameters["argv"] as? List<*>)?.filterIsInstance<String>()
|
||||
val argv = when (val raw = request.parameters["argv"]) {
|
||||
is List<*> -> raw.filterIsInstance<String>()
|
||||
is String -> runCatching {
|
||||
Json.decodeFromString<List<String>>(raw)
|
||||
}.getOrElse { emptyList() }
|
||||
else -> emptyList()
|
||||
}
|
||||
return when {
|
||||
argv.isNullOrEmpty() ->
|
||||
argv.isEmpty() ->
|
||||
ValidationResult.Invalid("Missing or empty 'argv' parameter. Expected List<String>.")
|
||||
|
||||
allowedExecutables.isNotEmpty() && argv[0] !in allowedExecutables ->
|
||||
ValidationResult.Invalid("Executable '${argv[0]}' is not in the allowed list.")
|
||||
|
||||
else -> ValidationResult.Valid
|
||||
}
|
||||
}
|
||||
@@ -42,7 +65,13 @@ class ShellTool(
|
||||
override suspend fun execute(request: ToolRequest): ToolResult = withContext(Dispatchers.IO) {
|
||||
validateRequest(request).run {
|
||||
takeIf { this is ValidationResult.Valid }?.let {
|
||||
val argv = (request.parameters["argv"] as? List<*>)?.filterIsInstance<String>()
|
||||
val argv = when (val raw = request.parameters["argv"]) {
|
||||
is List<*> -> raw.filterIsInstance<String>()
|
||||
is String -> runCatching {
|
||||
Json.decodeFromString<List<String>>(raw)
|
||||
}.getOrElse { emptyList() }
|
||||
else -> emptyList()
|
||||
}
|
||||
val process = ProcessBuilder(argv).apply {
|
||||
workingDir?.let { directory(it.toFile()) }
|
||||
}.start()
|
||||
|
||||
Reference in New Issue
Block a user