use crate::host::database::{LuaRuntimeDatabaseCallbackMode, LuaRuntimeDatabaseProviderMode};
use crate::runtime_context::RuntimeRequestContext;
use crate::tool_cache::ToolCacheConfig;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use std::path::PathBuf;
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum LuaRuntimeSpaceControllerProcessMode {
Service,
#[default]
Managed,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct LuaRuntimeSpaceControllerOptions {
pub endpoint: Option<String>,
pub auto_spawn: bool,
pub executable_path: Option<PathBuf>,
pub process_mode: LuaRuntimeSpaceControllerProcessMode,
pub minimum_uptime_secs: u64,
pub idle_timeout_secs: u64,
pub default_lease_ttl_secs: u64,
pub connect_timeout_secs: u64,
pub startup_timeout_secs: u64,
pub startup_retry_interval_ms: u64,
pub lease_renew_interval_secs: u64,
}
impl Default for LuaRuntimeSpaceControllerOptions {
fn default() -> Self {
Self {
endpoint: None,
auto_spawn: true,
executable_path: None,
process_mode: LuaRuntimeSpaceControllerProcessMode::Managed,
minimum_uptime_secs: 300,
idle_timeout_secs: 900,
default_lease_ttl_secs: 120,
connect_timeout_secs: 5,
startup_timeout_secs: 15,
startup_retry_interval_ms: 250,
lease_renew_interval_secs: 30,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct LuaRuntimeCapabilityOptions {
#[serde(default)]
pub enable_skill_management_bridge: bool,
pub enable_managed_io_compat: bool,
}
impl Default for LuaRuntimeCapabilityOptions {
fn default() -> Self {
Self {
enable_skill_management_bridge: false,
enable_managed_io_compat: true,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, serde::Deserialize)]
pub struct RuntimeSkillRoot {
pub name: String,
pub skills_dir: PathBuf,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub struct LuaRuntimeRunLuaPoolConfig {
pub min_size: usize,
pub max_size: usize,
pub idle_ttl_secs: u64,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct LuaRuntimeHostOptions {
pub temp_dir: Option<PathBuf>,
pub resources_dir: Option<PathBuf>,
pub lua_packages_dir: Option<PathBuf>,
pub host_provided_tool_root: Option<PathBuf>,
pub host_provided_lua_root: Option<PathBuf>,
pub host_provided_ffi_root: Option<PathBuf>,
pub system_lua_lib_dir: Option<PathBuf>,
pub download_cache_root: Option<PathBuf>,
pub dependency_dir_name: String,
pub state_dir_name: String,
pub database_dir_name: String,
pub skill_config_file_path: Option<PathBuf>,
pub allow_network_download: bool,
pub github_base_url: Option<String>,
pub github_api_base_url: Option<String>,
#[serde(default)]
pub default_text_encoding: Option<String>,
pub sqlite_library_path: Option<PathBuf>,
#[serde(default)]
pub sqlite_provider_mode: LuaRuntimeDatabaseProviderMode,
#[serde(default)]
pub sqlite_callback_mode: LuaRuntimeDatabaseCallbackMode,
pub lancedb_library_path: Option<PathBuf>,
#[serde(default)]
pub lancedb_provider_mode: LuaRuntimeDatabaseProviderMode,
#[serde(default)]
pub lancedb_callback_mode: LuaRuntimeDatabaseCallbackMode,
#[serde(default)]
pub space_controller: LuaRuntimeSpaceControllerOptions,
pub cache_config: Option<ToolCacheConfig>,
#[serde(default)]
pub runlua_pool_config: Option<LuaRuntimeRunLuaPoolConfig>,
pub reserved_entry_names: Vec<String>,
#[serde(default)]
pub ignored_skill_ids: Vec<String>,
#[serde(default)]
pub capabilities: LuaRuntimeCapabilityOptions,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct LuaInvocationContext {
pub request_context: Option<RuntimeRequestContext>,
pub client_budget: Value,
pub tool_config: Value,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct EffectiveBudgetScope {
pub bytes: u64,
pub lines: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ClientBudgetSnapshot {
pub client_name: Option<String>,
pub tool_name: Option<String>,
pub skill_name: Option<String>,
pub matched_client_pattern: Option<String>,
pub tool_result: EffectiveBudgetScope,
pub file_read: EffectiveBudgetScope,
pub tool_config: Value,
}
#[cfg(test)]
mod tests {
use super::LuaRuntimeCapabilityOptions;
use serde_json::json;
#[test]
fn capability_options_require_explicit_managed_io_compat_flag() {
let error = serde_json::from_value::<LuaRuntimeCapabilityOptions>(json!({
"enable_skill_management_bridge": true
}))
.expect_err("partial capability options should fail without managed io flag");
assert!(
error.to_string().contains("enable_managed_io_compat"),
"missing-field error should mention enable_managed_io_compat, got: {error}"
);
}
}
impl LuaInvocationContext {
pub fn new(
request_context: Option<RuntimeRequestContext>,
client_budget: Value,
tool_config: Value,
) -> Self {
Self {
request_context,
client_budget: normalize_context_object(client_budget),
tool_config: normalize_context_object(tool_config),
}
}
pub fn empty() -> Self {
Self::default()
}
}
fn normalize_context_object(value: Value) -> Value {
match value {
Value::Object(_) => value,
_ => Value::Object(Map::new()),
}
}