pub mod external;
pub mod sequence;
#[cfg(feature = "rhai-runtime")]
pub mod rhai;
#[cfg(feature = "lua-runtime")]
pub mod lua;
#[cfg(feature = "wasm-runtime")]
pub mod wasm;
pub(crate) mod path_safety;
use std::sync::Arc;
use crate::error::SkillError;
use synwire_core::agents::sampling::SamplingProvider;
use synwire_core::tools::ToolProvider;
#[derive(Debug, Clone)]
pub struct SkillInput {
pub args: serde_json::Value,
}
#[derive(Debug, Clone)]
pub struct SkillOutput {
pub result: serde_json::Value,
}
#[derive(Clone)]
pub struct SkillContext {
pub project_root: std::path::PathBuf,
pub available_tools: Vec<String>,
pub tool_provider: Option<Arc<dyn ToolProvider>>,
pub sampling: Option<Arc<dyn SamplingProvider>>,
pub progress_tx: Option<tokio::sync::mpsc::Sender<String>>,
}
impl Default for SkillContext {
fn default() -> Self {
Self {
project_root: std::path::PathBuf::new(),
available_tools: Vec::new(),
tool_provider: None,
sampling: None,
progress_tx: None,
}
}
}
impl std::fmt::Debug for SkillContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SkillContext")
.field("project_root", &self.project_root)
.field("available_tools", &self.available_tools)
.field("tool_provider", &self.tool_provider.is_some())
.field("sampling", &self.sampling.is_some())
.field("progress_tx", &self.progress_tx.is_some())
.finish()
}
}
#[cfg(any(feature = "rhai-runtime", feature = "lua-runtime"))]
pub(crate) fn block_on_result<F, T, E>(fut: F) -> Result<T, SkillError>
where
F: std::future::Future<Output = Result<T, E>>,
E: std::fmt::Display,
{
match tokio::runtime::Handle::try_current() {
Err(_) => Err(SkillError::Runtime {
runtime: "async_bridge".to_owned(),
message: "no tokio runtime available for async operations".to_owned(),
}),
Ok(handle) => {
if handle.runtime_flavor() == tokio::runtime::RuntimeFlavor::CurrentThread {
return Err(SkillError::Runtime {
runtime: "async_bridge".to_owned(),
message: "block_in_place not supported on current-thread runtime".to_owned(),
});
}
tokio::task::block_in_place(|| handle.block_on(fut)).map_err(|e| SkillError::Runtime {
runtime: "async_bridge".to_owned(),
message: e.to_string(),
})
}
}
}
pub trait SkillExecutor: Send + Sync {
fn execute(&self, input: SkillInput) -> Result<SkillOutput, SkillError>;
fn execute_with_context(
&self,
input: SkillInput,
_context: Option<&SkillContext>,
) -> Result<SkillOutput, SkillError> {
self.execute(input)
}
}