orcs_lua/lib.rs
1//! Lua scripting support for ORCS components.
2//!
3//! This crate enables writing ORCS Components and Children in Lua scripts.
4//!
5//! # Architecture
6//!
7//! ```text
8//! ┌─────────────────────────────────────────────────────┐
9//! │ LuaComponent (Rust) │
10//! │ impl Component for LuaComponent │
11//! │ ┌───────────────────────────────────────────────┐ │
12//! │ │ lua: Lua (mlua) │ │
13//! │ │ id: ComponentId │ │
14//! │ │ callbacks: LuaCallbacks │ │
15//! │ └───────────────────────────────────────────────┘ │
16//! │ │ │
17//! │ ▼ │
18//! │ ┌───────────────────────────────────────────────┐ │
19//! │ │ Lua Script (.lua) │ │
20//! │ │ return { │ │
21//! │ │ id = "my-component", │ │
22//! │ │ subscriptions = {"Echo"}, │ │
23//! │ │ on_request = function(req) ... end, │ │
24//! │ │ on_signal = function(sig) ... end, │ │
25//! │ │ } │ │
26//! │ └───────────────────────────────────────────────┘ │
27//! └─────────────────────────────────────────────────────┘
28//! ```
29//!
30//! # Example Lua Script
31//!
32//! ```lua
33//! -- echo_component.lua
34//! return {
35//! id = "lua-echo",
36//! subscriptions = {"Echo"},
37//!
38//! on_request = function(request)
39//! if request.operation == "echo" then
40//! return { success = true, data = request.payload }
41//! end
42//! return { success = false, error = "unknown operation" }
43//! end,
44//!
45//! on_signal = function(signal)
46//! if signal.kind == "Veto" then
47//! return "Abort"
48//! end
49//! return "Ignored"
50//! end,
51//! }
52//! ```
53//!
54//! # Sandbox
55//!
56//! All file operations (`orcs.read`, `orcs.write`, `orcs.grep`, `orcs.glob`,
57//! `orcs.mkdir`, `orcs.remove`, `orcs.mv`) are sandboxed via
58//! [`SandboxPolicy`](orcs_runtime::sandbox::SandboxPolicy). The sandbox is
59//! injected at construction time and controls:
60//!
61//! - Which filesystem paths are accessible for reads and writes
62//! - The working directory for `orcs.exec()` commands
63//! - The value of `orcs.pwd` in Lua
64//!
65//! Dangerous Lua stdlib functions (`io.*`, `os.execute`, `loadfile`, etc.)
66//! are disabled after registration to prevent sandbox bypass.
67//!
68//! # Hot Reload
69//!
70//! `LuaComponent::reload()` allows reloading the script from file.
71//!
72//! # Script Loading
73//!
74//! Scripts are loaded from filesystem search paths:
75//!
76//! ```ignore
77//! use orcs_lua::ScriptLoader;
78//! use orcs_runtime::sandbox::ProjectSandbox;
79//! use std::sync::Arc;
80//!
81//! let sandbox = Arc::new(ProjectSandbox::new(".").unwrap());
82//!
83//! let loader = ScriptLoader::new(sandbox)
84//! .with_path("~/.orcs/components")
85//! .with_path("/versioned/builtins/components");
86//! let component = loader.load("echo")?;
87//! ```
88
89pub(crate) mod cap_tools;
90mod child;
91mod component;
92mod error;
93pub mod hook_helpers;
94pub mod http_command;
95pub mod llm_adapter;
96pub mod llm_command;
97mod loader;
98mod lua_env;
99pub mod orcs_helpers;
100pub mod sanitize;
101#[cfg(any(test, feature = "test-utils"))]
102pub mod scenario;
103#[cfg(any(test, feature = "test-utils"))]
104pub mod testing;
105pub mod tool_registry;
106pub mod tools;
107mod types;
108
109pub use child::LuaChild;
110pub use component::{LuaComponent, LuaComponentLoader};
111pub use error::LuaError;
112pub use hook_helpers::{
113 load_hooks_from_config, register_hook_function, register_hook_stub, register_unhook_function,
114 HookLoadError, HookLoadResult, LuaHook,
115};
116pub use llm_command::{llm_request_impl, register_llm_deny_stub};
117pub use loader::{LoadResult, LoadWarning, ScriptLoader};
118pub use lua_env::LuaEnv;
119pub use orcs_helpers::{ensure_orcs_table, register_base_orcs_functions};
120pub use tools::register_tool_functions;
121pub use types::{LuaRequest, LuaResponse, LuaSignal};