pub const EVENT_KIND_SANDBOX_EXECUTE: &str = "sandbox.execute";
pub const EVENT_KIND_SESSION_CREATE: &str = "session.create";
pub const EVENT_KIND_SESSION_DESTROY: &str = "session.destroy";
pub const EVENT_KIND_WORKSPACE_CREATE: &str = "workspace.create";
pub const EVENT_KIND_WORKSPACE_CONFIG: &str = "workspace.config";
pub const EVENT_KIND_TOOL_REGISTER: &str = "tool.register";
#[derive(Debug, Clone)]
pub struct PendingChainEvent {
pub source: String,
pub kind: String,
pub payload: Option<serde_json::Value>,
}
use std::sync::Mutex;
static PENDING_CHAIN_EVENTS: Mutex<Vec<PendingChainEvent>> = Mutex::new(Vec::new());
pub fn push_chain_event(source: &str, kind: &str, payload: Option<serde_json::Value>) {
if let Ok(mut buf) = PENDING_CHAIN_EVENTS.lock() {
buf.push(PendingChainEvent {
source: source.to_string(),
kind: kind.to_string(),
payload,
});
}
}
pub fn drain_pending_chain_events() -> Vec<PendingChainEvent> {
match PENDING_CHAIN_EVENTS.lock() {
Ok(mut buf) => std::mem::take(&mut *buf),
Err(_) => Vec::new(),
}
}
#[macro_export]
macro_rules! chain_event {
($source:expr, $kind:expr, { $($key:tt : $val:expr),* $(,)? }) => {
{
tracing::info!(
target: "chain_event",
source = $source,
kind = $kind,
$( $key = %$val, )*
"chain"
);
$crate::chain_event::push_chain_event(
$source,
$kind,
Some(serde_json::json!({ $( stringify!($key): format!("{}", $val) ),* })),
);
}
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn constants_match_expected_values() {
assert_eq!(EVENT_KIND_SANDBOX_EXECUTE, "sandbox.execute");
assert_eq!(EVENT_KIND_SESSION_CREATE, "session.create");
assert_eq!(EVENT_KIND_SESSION_DESTROY, "session.destroy");
assert_eq!(EVENT_KIND_WORKSPACE_CREATE, "workspace.create");
assert_eq!(EVENT_KIND_WORKSPACE_CONFIG, "workspace.config");
assert_eq!(EVENT_KIND_TOOL_REGISTER, "tool.register");
}
#[test]
fn macro_compiles_and_pushes_event() {
drain_pending_chain_events();
chain_event!("test", "test.event", { "foo": "bar" });
let events = drain_pending_chain_events();
assert!(!events.is_empty(), "macro should push to pending buffer");
assert_eq!(events[0].source, "test");
assert_eq!(events[0].kind, "test.event");
}
#[test]
fn push_and_drain_chain_events() {
drain_pending_chain_events();
push_chain_event("src", "kind.test", Some(serde_json::json!({"a": 1})));
push_chain_event("src2", "kind.test2", None);
let events = drain_pending_chain_events();
assert_eq!(events.len(), 2);
assert_eq!(events[0].source, "src");
assert_eq!(events[1].kind, "kind.test2");
assert!(drain_pending_chain_events().is_empty());
}
}