Skip to main content

synwire_core/agents/
directive_executor.rs

1//! Directive execution traits and implementations.
2
3use crate::BoxFuture;
4use crate::agents::directive::Directive;
5use serde_json::Value;
6use thiserror::Error;
7
8/// Directive execution error.
9#[derive(Error, Debug)]
10#[non_exhaustive]
11pub enum DirectiveError {
12    /// Execution failed.
13    #[error("Execution failed: {0}")]
14    ExecutionFailed(String),
15
16    /// Unsupported directive type.
17    #[error("Unsupported directive: {0}")]
18    Unsupported(String),
19}
20
21/// Executes directives and produces optional results.
22///
23/// The default implementation is `NoOpExecutor` which records without executing.
24pub trait DirectiveExecutor: Send + Sync {
25    /// Execute a directive, returning an optional result value.
26    ///
27    /// Returns `Some(value)` for directives like `RunInstruction` that need a result
28    /// routed back to the agent.
29    fn execute_directive(
30        &self,
31        directive: &Directive,
32    ) -> BoxFuture<'_, Result<Option<Value>, DirectiveError>>;
33}
34
35/// No-op executor that records directives without executing them.
36///
37/// Useful for testing - directives are collected but no side effects occur.
38#[derive(Debug, Default, Clone)]
39pub struct NoOpExecutor;
40
41impl DirectiveExecutor for NoOpExecutor {
42    fn execute_directive(
43        &self,
44        _directive: &Directive,
45    ) -> BoxFuture<'_, Result<Option<Value>, DirectiveError>> {
46        Box::pin(async { Ok(None) })
47    }
48}
49
50#[cfg(test)]
51#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
52mod tests {
53    use super::*;
54
55    #[tokio::test]
56    async fn test_noop_executor_returns_none() {
57        let executor = NoOpExecutor;
58        let directive = Directive::Stop { reason: None };
59        let result = executor
60            .execute_directive(&directive)
61            .await
62            .expect("execute");
63        assert!(result.is_none());
64    }
65}