///|
fn moon_openclaw_workspace_dir() -> String {
@moonsuite.product_artifact_for_workspace_root(
moongate_active_workspace_root(),
"moongate",
"openclaw/workspace",
)
}
///|
fn moon_openclaw_memory_dir() -> String {
@pathx.join(moon_openclaw_workspace_dir(), "memory")
}
///|
async fn OpenClawService::handle_get_openclaw_default_model(
self : OpenClawService,
w : @httpx.ResponseWriter,
) -> Unit {
write_usage_json(w, self.openclaw_default_model.unwrap_or(Json::null()))
}
///|
async fn OpenClawService::handle_set_openclaw_default_model(
self : OpenClawService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard openclaw_default_model_from_request(r.path, body) is Some(model) else {
write_usage_bad_request(w, "invalid_openclaw_default_model")
return
}
self.openclaw_default_model = Some(model)
write_usage_json(w, suite_write_outcome_json())
}
///|
async fn OpenClawService::handle_get_openclaw_model_catalog(
self : OpenClawService,
w : @httpx.ResponseWriter,
) -> Unit {
write_usage_json(w, self.openclaw_model_catalog.unwrap_or(Json::null()))
}
///|
async fn OpenClawService::handle_set_openclaw_model_catalog(
self : OpenClawService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard suite_object_request(r.path, body, "catalog") is Some(catalog) else {
write_usage_bad_request(w, "invalid_openclaw_model_catalog")
return
}
self.openclaw_model_catalog = Some(catalog)
write_usage_json(w, suite_write_outcome_json())
}
///|
async fn OpenClawService::handle_get_openclaw_agents_defaults(
self : OpenClawService,
w : @httpx.ResponseWriter,
) -> Unit {
write_usage_json(w, self.openclaw_agents_defaults.unwrap_or(Json::null()))
}
///|
async fn OpenClawService::handle_set_openclaw_agents_defaults(
self : OpenClawService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
let defaults = match suite_object_request(r.path, body, "defaults") {
Some(defaults) => Some(defaults)
None =>
match openclaw_default_model_from_request(r.path, body) {
Some(model) => Some({ "model": model }.to_json())
None => None
}
}
guard defaults is Some(defaults_json) else {
write_usage_bad_request(w, "invalid_openclaw_agents_defaults")
return
}
self.openclaw_agents_defaults = Some(defaults_json)
write_usage_json(w, suite_write_outcome_json())
}
///|
async fn OpenClawService::handle_get_openclaw_env(
self : OpenClawService,
w : @httpx.ResponseWriter,
) -> Unit {
write_usage_json(w, self.openclaw_env)
}
///|
async fn OpenClawService::handle_set_openclaw_env(
self : OpenClawService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard openclaw_env_from_request(r.path, body) is Some(env) else {
write_usage_bad_request(w, "invalid_openclaw_env")
return
}
self.openclaw_env = env
write_usage_json(w, suite_write_outcome_json())
}
///|
async fn OpenClawService::handle_get_openclaw_tools(
self : OpenClawService,
w : @httpx.ResponseWriter,
) -> Unit {
write_usage_json(w, self.openclaw_tools)
}
///|
async fn OpenClawService::handle_set_openclaw_tools(
self : OpenClawService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard openclaw_tools_from_request(r.path, body) is Some(tools) else {
write_usage_bad_request(w, "invalid_openclaw_tools")
return
}
self.openclaw_tools = tools
write_usage_json(w, suite_write_outcome_json())
}
///|
async fn OpenClawService::handle_get_hermes_memory(
self : OpenClawService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard hermes_memory_kind_from_request(r.path, body) is Some(kind) else {
write_usage_bad_request(w, "invalid_hermes_memory_kind")
return
}
write_usage_json(w, Json::string(self.hermes_memory.get(kind).unwrap_or("")))
}
///|
async fn OpenClawService::handle_set_hermes_memory(
self : OpenClawService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard hermes_memory_kind_from_request(r.path, body) is Some(kind) else {
write_usage_bad_request(w, "invalid_hermes_memory_kind")
return
}
let content = proxy_string_request(r.path, body, "content").unwrap_or("")
self.hermes_memory[kind] = content
write_usage_json(w, Json::null())
}
///|
async fn OpenClawService::handle_get_hermes_memory_limits(
self : OpenClawService,
w : @httpx.ResponseWriter,
) -> Unit {
write_usage_json(w, hermes_memory_limits_json(self.hermes_memory_enabled))
}
///|
async fn OpenClawService::handle_set_hermes_memory_enabled(
self : OpenClawService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
let body = proxy_json_body(r)
guard hermes_memory_kind_from_request(r.path, body) is Some(kind) else {
write_usage_bad_request(w, "invalid_hermes_memory_kind")
return
}
guard proxy_bool_request(r.path, body, "enabled") is Some(enabled) else {
write_usage_bad_request(w, "missing_enabled")
return
}
self.hermes_memory_enabled[kind] = enabled
write_usage_json(w, suite_write_outcome_json())
}
///|
async fn OpenClawService::handle_open_hermes_web_ui(
self : OpenClawService,
r : @httpx.RequestReader,
w : @httpx.ResponseWriter,
) -> Unit {
ignore(self)
let body = proxy_json_body(r)
let port = hermes_web_port_from_request(r.path)
let path = proxy_string_request(r.path, body, "path").unwrap_or("/")
if !hermes_web_ui_is_live(port) {
write_usage_bad_request(w, HERMES_WEB_OFFLINE_ERROR)
return
}
ignore(hermes_web_ui_target_url(port, path))
write_usage_json(w, Json::null())
}
///|
async fn OpenClawService::handle_launch_hermes_dashboard(
self : OpenClawService,
w : @httpx.ResponseWriter,
) -> Unit {
ignore(self)
match launch_hermes_dashboard_standalone() {
Ok(result) => write_usage_json(w, result)
Err(error) => write_usage_bad_request(w, error)
}
}
///|
fn openclaw_default_tools_json() -> Json {
{ "allow": Json::array([]), "deny": Json::array([]) }.to_json()
}
///|
fn openclaw_tools_profile_is_supported(profile : String) -> Bool {
profile == "minimal" ||
profile == "coding" ||
profile == "messaging" ||
profile == "full"
}
///|
fn openclaw_health_warning_json(
code : String,
message : String,
path : String?,
) -> Json {
let warning : Map[String, Json] = {
"code": Json::string(code),
"message": Json::string(message),
}
match path {
Some(path) => warning["path"] = Json::string(path)
None => ()
}
Json::object(warning)
}
///|
fn openclaw_nested_json(config : Json, keys : Array[String]) -> Json? {
let mut current = config
for key in keys {
match current {
Object(obj) =>
match obj.get(key) {
Some(value) => current = value
None => return None
}
_ => return None
}
}
Some(current)
}
///|
fn openclaw_default_model_from_request(
path : StringView,
body : Json?,
) -> Json? {
match suite_object_payload(body, "model") {
Some(model) => return Some(model)
None => ()
}
guard proxy_string_request(path, body, "primary") is Some(primary) &&
!primary.trim().is_empty() else {
return None
}
Some(
{
"primary": Json::string(primary.trim().to_owned()),
"fallbacks": split_csv_json(
proxy_string_request(path, body, "fallbacks").unwrap_or(""),
),
}.to_json(),
)
}
///|
fn openclaw_env_from_request(path : StringView, body : Json?) -> Json? {
match suite_object_request(path, body, "env") {
Some(env) => return Some(env)
None => ()
}
guard proxy_string_request(path, body, "key") is Some(key) &&
!key.trim().is_empty() else {
return None
}
let value = proxy_string_request(path, body, "value").unwrap_or("")
let env : Map[String, Json] = {}
env[key.trim().to_owned()] = Json::string(value)
Some(Json::object(env))
}
///|
fn openclaw_tools_from_request(path : StringView, body : Json?) -> Json? {
match suite_object_request(path, body, "tools") {
Some(tools) => return Some(tools)
None => ()
}
let tools : Map[String, Json] = {
"allow": split_csv_json(
proxy_string_request(path, body, "allow").unwrap_or(""),
),
"deny": split_csv_json(
proxy_string_request(path, body, "deny").unwrap_or(""),
),
}
match proxy_string_request(path, body, "profile") {
Some(profile) if !profile.trim().is_empty() =>
tools["profile"] = Json::string(profile.trim().to_owned())
_ => ()
}
Some(Json::object(tools))
}
///|
fn hermes_memory_kind_from_request(path : StringView, body : Json?) -> String? {
match proxy_string_request(path, body, "kind") {
Some(raw) =>
match raw.trim().to_lower() {
"memory" => Some("memory")
"user" => Some("user")
_ => None
}
None => None
}
}
///|
fn hermes_memory_limits_json(enabled : Map[String, Bool]) -> Json {
{
"memory": Json::number(2200.0),
"user": Json::number(1375.0),
"memoryEnabled": Json::boolean(enabled.get("memory").unwrap_or(true)),
"userEnabled": Json::boolean(enabled.get("user").unwrap_or(true)),
}.to_json()
}
///|
fn hermes_web_port_from_request(path : StringView) -> Int {
match usage_query_int(path, "port") {
Some(port) if port > 0 && port <= 65535 => return port
_ => ()
}
let env_port = @os.getenv("HERMES_WEB_PORT") catch { _ => None }
match env_port {
Some(raw) => {
let port = @string.parse_int(raw.trim().to_owned(), base=10) catch {
_ => -1
}
if port > 0 && port <= 65535 {
port
} else {
9119
}
}
None => 9119
}
}
///|
fn hermes_web_ui_path(path : String) -> String {
if path.is_empty() {
"/"
} else if path.has_prefix("/") {
path
} else {
"/\{path}"
}
}
///|
fn hermes_web_ui_target_url(port : Int, path : String) -> String {
"http://127.0.0.1:\{port}\{hermes_web_ui_path(path)}"
}
///|
fn hermes_web_ui_probe_url(port : Int) -> String {
"http://127.0.0.1:\{port}/api/status"
}
///|
fn hermes_dashboard_background_shell_command() -> String {
"nohup \{HERMES_DASHBOARD_COMMAND} >\{HERMES_DASHBOARD_LOG_PATH} 2>&1 &"
}
///|
async fn launch_hermes_dashboard_standalone() -> Result[Json, String] {
let result = @spawn.spawn(
"sh",
["-lc", hermes_dashboard_background_shell_command()],
timeout=2000,
) catch {
_ => return Err("hermes_dashboard_launch_failed")
}
if result.status != 0 {
return Err("hermes_dashboard_launch_failed")
}
Ok(Json::null())
}
///|
async fn hermes_web_ui_is_live(port : Int) -> Bool {
if !@net.localhost_port_open(port, timeout_ms=1200) {
return false
}
let result = moon_async_result(() => @http.get(hermes_web_ui_probe_url(port)))
match result {
Ok(_) => true
Err(_) => false
}
}