use std::sync::Arc;
use nexo_tool_meta::{BindingContext, InboundMessageMeta};
use uuid::Uuid;
#[cfg(feature = "outbound")]
use crate::outbound::OutboundDispatcher;
#[derive(Debug, Clone)]
pub struct ToolCtx {
pub agent_id: String,
pub session_id: Option<Uuid>,
pub binding: Option<BindingContext>,
pub inbound: Option<InboundMessageMeta>,
#[cfg(feature = "outbound")]
pub(crate) outbound: Arc<OutboundDispatcher>,
#[cfg(not(feature = "outbound"))]
#[allow(dead_code)]
pub(crate) _outbound_marker: std::marker::PhantomData<Arc<()>>,
#[cfg(feature = "admin")]
pub(crate) admin: Option<Arc<crate::admin::AdminClient>>,
}
impl ToolCtx {
pub fn binding(&self) -> Option<&BindingContext> {
self.binding.as_ref()
}
pub fn inbound(&self) -> Option<&InboundMessageMeta> {
self.inbound.as_ref()
}
#[cfg(feature = "outbound")]
pub fn outbound(&self) -> &OutboundDispatcher {
&self.outbound
}
#[cfg(feature = "admin")]
pub fn admin(&self) -> Option<&crate::admin::AdminClient> {
self.admin.as_deref()
}
}
#[derive(Debug, Clone)]
pub struct HookCtx {
pub agent_id: String,
pub binding: Option<BindingContext>,
pub inbound: Option<InboundMessageMeta>,
#[cfg(feature = "admin")]
pub(crate) admin: Option<Arc<crate::admin::AdminClient>>,
}
impl HookCtx {
pub fn inbound(&self) -> Option<&InboundMessageMeta> {
self.inbound.as_ref()
}
#[cfg(feature = "admin")]
pub fn admin(&self) -> Option<&crate::admin::AdminClient> {
self.admin.as_deref()
}
}
#[cfg(test)]
mod tests {
use super::*;
use nexo_tool_meta::BindingContext;
fn ctx_with_binding(b: Option<BindingContext>) -> ToolCtx {
ToolCtx {
agent_id: "ana".into(),
session_id: None,
binding: b,
inbound: None,
#[cfg(not(feature = "outbound"))]
_outbound_marker: std::marker::PhantomData,
#[cfg(feature = "outbound")]
outbound: Arc::new(OutboundDispatcher::new_stub()),
#[cfg(feature = "admin")]
admin: None,
}
}
#[test]
fn binding_accessor_returns_some_when_present() {
let b = BindingContext::agent_only("ana");
let ctx = ctx_with_binding(Some(b.clone()));
assert_eq!(ctx.binding(), Some(&b));
}
#[test]
fn binding_accessor_returns_none_when_absent() {
let ctx = ctx_with_binding(None);
assert!(ctx.binding().is_none());
}
#[test]
fn inbound_accessor_returns_none_when_absent() {
let ctx = ctx_with_binding(None);
assert!(ctx.inbound().is_none());
}
#[test]
fn inbound_accessor_returns_some_when_present() {
let inbound = nexo_tool_meta::InboundMessageMeta::external_user("+5491100", "wa.X");
let mut ctx = ctx_with_binding(None);
ctx.inbound = Some(inbound.clone());
assert_eq!(ctx.inbound(), Some(&inbound));
}
#[test]
fn hook_ctx_round_trip() {
let b = BindingContext::agent_only("ana");
let h = HookCtx {
agent_id: "ana".into(),
binding: Some(b.clone()),
inbound: None,
#[cfg(feature = "admin")]
admin: None,
};
assert_eq!(h.binding, Some(b));
assert!(h.inbound().is_none());
}
}