diff --git a/README.md b/README.md
index c779bae..62aa045 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# LLM Agent Builder
+[![build](https://github.com/LLMAgentBuilder/llm-agent-builder/actions/workflows/build.yaml/badge.svg)](https://github.com/LLMAgentBuilder/llm-agent-builder/actions/workflows/build.yaml)
+
**LLM Agent Powered by Java / Spring AI**
## Documentation
diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml
index 2a65804..cb733a3 100644
--- a/bootstrap/pom.xml
+++ b/bootstrap/pom.xml
@@ -48,6 +48,11 @@
open-telemetry
${project.version}
+
+ io.github.llmagentbuilder
+ chat-agent-ui
+ 0.3.0
+
io.github.llmagentbuilder
llm-openai
diff --git a/bootstrap/src/main/kotlin/io/github/llmagentbuilder/bootstrap/AgentBootstrap.kt b/bootstrap/src/main/kotlin/io/github/llmagentbuilder/bootstrap/AgentBootstrap.kt
index 406e402..706782e 100644
--- a/bootstrap/src/main/kotlin/io/github/llmagentbuilder/bootstrap/AgentBootstrap.kt
+++ b/bootstrap/src/main/kotlin/io/github/llmagentbuilder/bootstrap/AgentBootstrap.kt
@@ -122,7 +122,7 @@ object AgentBootstrap {
UUID.randomUUID().toString(),
observationRegistry,
)
- KtorLauncher.launch(chatAgent)
+ KtorLauncher.launch(chatAgent, agentConfig.launch)
}
private fun profileAdvisor(agentConfig: AgentConfig): Advisor? {
diff --git a/core/src/main/kotlin/io/github/llmagentbuilder/core/AgentConfig.kt b/core/src/main/kotlin/io/github/llmagentbuilder/core/AgentConfig.kt
index 691f118..99e1c5d 100644
--- a/core/src/main/kotlin/io/github/llmagentbuilder/core/AgentConfig.kt
+++ b/core/src/main/kotlin/io/github/llmagentbuilder/core/AgentConfig.kt
@@ -63,6 +63,21 @@ class ObservationConfig {
var metrics: MetricsConfig? = null
}
+class LaunchConfig {
+ var server: ServerConfig? = null
+ val feature: FeatureConfig? = null
+}
+
+class ServerConfig {
+ var host: String? = "localhost"
+ var port: Int? = 8080
+}
+
+class FeatureConfig {
+ var devUiEnabled: Boolean? = true
+}
+
+
class AgentConfig {
var metadata: AgentMetadata? = null
var profile: ProfileConfig? = null
@@ -71,6 +86,7 @@ class AgentConfig {
var planner: Map? = null
var tools: List? = null
var observation: ObservationConfig? = null
+ var launch: LaunchConfig? = null
}
object AgentConfigLoader {
diff --git a/launchers/ktor/pom.xml b/launchers/ktor/pom.xml
index ca5dc04..e27eae0 100644
--- a/launchers/ktor/pom.xml
+++ b/launchers/ktor/pom.xml
@@ -65,6 +65,11 @@
ktor-serialization-jackson-jvm
${ktor.version}
+
+ io.ktor
+ ktor-server-webjars-jvm
+ ${ktor.version}
+
\ No newline at end of file
diff --git a/launchers/ktor/src/main/kotlin/io/github/llmagentbuilder/launcher/ktor/server/AppMain.kt b/launchers/ktor/src/main/kotlin/io/github/llmagentbuilder/launcher/ktor/server/AppMain.kt
index cf52d24..4aee183 100644
--- a/launchers/ktor/src/main/kotlin/io/github/llmagentbuilder/launcher/ktor/server/AppMain.kt
+++ b/launchers/ktor/src/main/kotlin/io/github/llmagentbuilder/launcher/ktor/server/AppMain.kt
@@ -1,7 +1,10 @@
package io.github.llmagentbuilder.launcher.ktor.server
import io.github.llmagentbuilder.core.ChatAgent
+import io.github.llmagentbuilder.core.FeatureConfig
+import io.github.llmagentbuilder.core.LaunchConfig
import io.github.llmagentbuilder.launcher.ktor.server.apis.AgentApi
+import io.github.llmagentbuilder.launcher.ktor.server.apis.devUI
import io.ktor.serialization.jackson.*
import io.ktor.server.application.*
import io.ktor.server.cio.*
@@ -11,13 +14,20 @@ import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.plugins.defaultheaders.*
import io.ktor.server.resources.*
import io.ktor.server.routing.*
+import io.ktor.server.webjars.*
+import org.slf4j.LoggerFactory
object KtorLauncher {
- fun launch(chatAgent: ChatAgent) {
+ private val logger = LoggerFactory.getLogger(KtorLauncher::class.java)
+
+ fun launch(chatAgent: ChatAgent, launchConfig: LaunchConfig? = null) {
+ val host = launchConfig?.server?.host ?: "localhost"
+ val port = launchConfig?.server?.port ?: 8080
+ logger.info("Starting agent server: $host:$port")
embeddedServer(
CIO,
- port = 8080,
- host = "0.0.0.0",
+ port,
+ host,
module = {
module(chatAgent)
}
@@ -25,7 +35,13 @@ object KtorLauncher {
}
}
-fun Application.module(chatAgent: ChatAgent) {
+fun Application.module(
+ chatAgent: ChatAgent,
+ featureConfig: FeatureConfig? = null
+) {
+ install(Webjars) {
+ path = "/webjars"
+ }
install(DefaultHeaders)
install(ContentNegotiation) {
jackson()
@@ -37,5 +53,8 @@ fun Application.module(chatAgent: ChatAgent) {
install(Resources)
install(Routing) {
AgentApi(chatAgent)
+ if (featureConfig?.devUiEnabled != false) {
+ devUI()
+ }
}
}
diff --git a/launchers/ktor/src/main/kotlin/io/github/llmagentbuilder/launcher/ktor/server/apis/DevUI.kt b/launchers/ktor/src/main/kotlin/io/github/llmagentbuilder/launcher/ktor/server/apis/DevUI.kt
new file mode 100644
index 0000000..48b6e71
--- /dev/null
+++ b/launchers/ktor/src/main/kotlin/io/github/llmagentbuilder/launcher/ktor/server/apis/DevUI.kt
@@ -0,0 +1,15 @@
+package io.github.llmagentbuilder.launcher.ktor.server.apis
+
+import io.ktor.server.application.*
+import io.ktor.server.response.*
+import io.ktor.server.routing.*
+
+fun Route.devUI() {
+ get("/") {
+ call.respondRedirect("/webjars/chat-agent-ui/index.html")
+ }
+ get("/_next/{path...}") {
+ val redirectPath = call.parameters.getAll("path")?.joinToString("/")
+ call.respondRedirect("/webjars/chat-agent-ui/${redirectPath}")
+ }
+}