Skip to main content

xz_agent_core/traits/
processor.rs

1use std::future::Future;
2
3use crate::error::EngineError;
4use crate::types::signal::Signal;
5
6/// Output processor — handles Thinker output and decides flow control.
7///
8/// After a Thinker produces output, each OutputProcessor in the chain
9/// processes it and returns Continue or Stop.
10///
11/// # Chain semantics
12///
13/// Processors are consulted **in registration order** and share a single
14/// immutable reference to the thinker's output (no per-processor clone).
15/// The first processor that returns [`Signal::Stop`] terminates the loop;
16/// subsequent processors in the chain are **not** invoked for that turn.
17///
18/// Recommended registration order for side-effect + termination processors:
19///
20/// 1. Safety / policy gates (may Stop early)
21/// 2. Side-effect processors (tool execution, message recording)
22/// 3. Loop guards (doom-loop detection)
23/// 4. Round limits (max turns)
24///
25/// # Example
26///
27/// ```rust
28/// use xz_agent_core::traits::processor::OutputProcessor;
29/// use xz_agent_core::error::EngineError;
30/// use xz_agent_core::types::signal::Signal;
31///
32/// struct StopOnHello;
33///
34/// impl OutputProcessor for StopOnHello {
35///     type Context = String;
36///     type Output = String;
37///     async fn process(&self, output: &Self::Output, ctx: &mut Self::Context) -> Result<Signal, EngineError> {
38///         if output == "stop" {
39///             Ok(Signal::Stop)
40///         } else {
41///             ctx.push_str(output);
42///             Ok(Signal::Continue)
43///         }
44///     }
45/// }
46/// ```
47pub trait OutputProcessor: Send + Sync {
48    /// The type of context modified during processing.
49    type Context;
50    /// The type of output produced by the Thinker.
51    type Output;
52    /// Process the Thinker's output.
53    ///
54    /// Receives a shared reference so the full processor chain can inspect
55    /// the same output without requiring [`Clone`].
56    ///
57    /// Returns Continue to proceed or Stop to terminate the engine loop.
58    fn process(
59        &self,
60        output: &Self::Output,
61        ctx: &mut Self::Context,
62    ) -> impl Future<Output = Result<Signal, EngineError>> + Send;
63}