feat(workflow): root description field in workflow TOML surfaced through registry

This commit is contained in:
2026-06-11 11:03:19 +04:00
parent ed0dca8b78
commit ac458d83e5
6 changed files with 122 additions and 7 deletions
@@ -9,6 +9,8 @@ import kotlin.io.path.listDirectoryEntries
private val log = LoggerFactory.getLogger(FileSystemWorkflowRegistry::class.java)
private data class WorkflowEntry(val graph: WorkflowGraph, val description: String)
class FileSystemWorkflowRegistry(
private val loader: WorkflowLoader,
private val workflowsDir: Path = Path.of(
@@ -16,23 +18,33 @@ class FileSystemWorkflowRegistry(
),
) : WorkflowRegistry {
private val cache: Map<String, WorkflowGraph> by lazy { loadAll() }
private val cache: Map<String, WorkflowEntry> by lazy { loadAll() }
override fun listAll(): List<WorkflowSummary> =
cache.values.map { WorkflowSummary(workflowId = it.id, description = it.id) }
cache.values.map { entry ->
WorkflowSummary(
workflowId = entry.graph.id,
description = entry.description.ifBlank { entry.graph.id },
stageIds = entry.graph.stages.keys.map { it.value },
)
}
override fun find(workflowId: String): WorkflowGraph? = cache[workflowId]
override fun find(workflowId: String): WorkflowGraph? = cache[workflowId]?.graph
private fun loadAll(): Map<String, WorkflowGraph> {
private fun loadAll(): Map<String, WorkflowEntry> {
if (!workflowsDir.exists()) return emptyMap()
return workflowsDir.listDirectoryEntries("*.toml")
.mapNotNull { file ->
runCatching { loader.load(file) }
runCatching {
val graph = loader.load(file)
val meta = loader.loadMeta(file)
WorkflowEntry(graph = graph, description = meta.description)
}
.onFailure { logWarning(file, it) }
.getOrNull()
}
.associateBy { graph ->
graph.id.ifBlank { graph.start.value }
.associateBy { entry ->
entry.graph.id.ifBlank { entry.graph.start.value }
}.also { log.info("cache init done, cache keys: {}", it.keys) }
}
@@ -1,13 +1,16 @@
package com.correx.apps.server.registry
import com.correx.core.transitions.graph.WorkflowGraph
import kotlinx.serialization.Serializable
interface WorkflowRegistry {
fun listAll(): List<WorkflowSummary>
fun find(workflowId: String): WorkflowGraph?
}
@Serializable
data class WorkflowSummary(
val workflowId: String,
val description: String,
val stageIds: List<String> = emptyList(),
)
@@ -0,0 +1,71 @@
package com.correx.apps.server.registry
import com.correx.infrastructure.workflow.TomlWorkflowLoader
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import java.nio.file.Path
import kotlin.io.path.writeText
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class FileSystemWorkflowRegistryTest {
@TempDir
lateinit var dir: Path
private val validToml = """
id = "healthcheck"
start = "collect"
description = "Runs the health check pipeline"
[[stages]]
id = "collect"
prompt = "prompts/collect.md"
produces = [{ name = "system_stats", kind = "file_written" }]
allowed_tools = ["ShellTool"]
token_budget = 2048
max_retries = 2
[[stages]]
id = "report"
prompt = "prompts/report.md"
needs = ["system_stats"]
produces = [{ name = "report", kind = "file_written" }]
token_budget = 2048
[[transitions]]
id = "collect-to-report"
from = "collect"
to = "report"
condition_type = "artifact_present"
condition_artifact_id = "system_stats"
[[transitions]]
id = "report-to-done"
from = "report"
to = "done"
condition_type = "always_true"
""".trimIndent()
@Test
fun `listAll returns description from toml`() {
dir.resolve("healthcheck.toml").writeText(validToml)
val summaries = FileSystemWorkflowRegistry(TomlWorkflowLoader(), dir).listAll()
assertEquals("Runs the health check pipeline", summaries.single().description)
}
@Test
fun `listAll falls back to workflowId when description absent`() {
dir.resolve("healthcheck.toml").writeText(validToml.replace("description = \"Runs the health check pipeline\"\n", ""))
assertEquals("healthcheck", FileSystemWorkflowRegistry(TomlWorkflowLoader(), dir).listAll().single().description)
}
@Test
fun `listAll returns stageIds for each workflow`() {
dir.resolve("healthcheck.toml").writeText(validToml)
assertTrue(
FileSystemWorkflowRegistry(TomlWorkflowLoader(), dir).listAll().single()
.stageIds.containsAll(listOf("collect", "report")),
)
}
}