Skip to main content

funera_core/
middleware.rs

1//! # Middleware — agent 事件拦截与处理管道
2//!
3//! 提供对 ReAct 循环**内部**的可插拔拦截机制,作用于 `process_token_stream` 和
4//! `handle_turn_finish` 之后、数据写入 session 历史之前。
5//!
6//! 分为两类:
7//!
8//! | 类型 | 特征 | 执行方式 | 影响事件流 |
9//! |------|------|----------|------------|
10//! | [`InspectorMiddleware`] | 只读观察 | `tokio::spawn` 后台并行 | ❌ 不等待,不阻塞 |
11//! | [`MutatorMiddleware`] | 可变处理 | 同步顺序执行 | ✅ 可 Pass/Modify/Block |
12//!
13//! ## 架构位置
14//!
15//! ```text
16//! LLM Stream → process_token_stream → 聚合结果
17//!                                         │
18//!                          create E events │
19//!                                         ▼
20//!                              [middleware chain]
21//!                           Pass / Modify / Block
22//!                                  │
23//!                         ┌────────┴────────┐
24//!                         ▼                 ▼
25//!                    session 历史         event_tx (通知/callback)
26//!                    (下一轮用)           (聚合生成 ChatResponse)
27//! ```
28//!
29//! Middleware 直接操作 session 写入前的数据,因此修改会**持久化**到下一轮
30//! ReAct 循环的历史上下文中。
31//!
32//! ## 快速使用 (在 `funera-orchestrate` 层)
33//!
34//! ```rust,no_run
35//! # use funera_core::middleware::{MiddlewareChain, InspectorMiddleware, MutatorMiddleware,
36//! #     InspectorError, MutatorAction, ErrorsDisabled};
37//! // 1. 定义 Inspector
38//! struct Logger;
39//! impl InspectorMiddleware<String> for Logger {
40//!     fn name(&self) -> &str { "log" }
41//!     fn inspect(&self, _: &String) -> Result<(), InspectorError> { Ok(()) }
42//! }
43//!
44//! // 2. 定义 Mutator
45//! struct Censor;
46//! impl MutatorMiddleware<String> for Censor {
47//!     fn name(&self) -> &str { "censor" }
48//!     fn process(&self, s: String) -> MutatorAction<String> { MutatorAction::Pass }
49//! }
50//!
51//! // 3. 构建链
52//! let chain = MiddlewareChain::<String>::new()
53//!     .with_inspectors((Logger,))
54//!     .with_mutator(Censor);
55//!
56//! // 4. 执行(由 react_loop 内部调用)
57//! let result = chain.process("hello".into());
58//! ```
59//!
60//! ## Typestate 错误通道
61//!
62//! 错误通道通过 typestate 管理:默认 `ErrorsDisabled`,调用
63//! [`MiddlewareChain::activate_error_channel`] 后变为 `ErrorsEnabled`,编译期防止重复激活。
64//!
65//! ```rust,no_run
66//! # use funera_core::middleware::{MiddlewareChain, ErrorsEnabled, InspectorMiddleware, InspectorError};
67//! # struct Insp;
68//! # impl InspectorMiddleware<String> for Insp {
69//! #     fn name(&self) -> &str { "i" }
70//! #     fn inspect(&self, _: &String) -> Result<(), InspectorError> { Ok(()) }
71//! # }
72//! let chain = MiddlewareChain::<String>::new()
73//!     .with_inspector(Insp);
74//! let (enabled, error_rx) = chain.activate_error_channel();
75//! // enabled 的类型是 MiddlewareChain<String, ErrorsEnabled>
76//! // 无法再次调用 activate_error_channel()
77//! ```
78
79use std::marker::PhantomData;
80use std::sync::Arc;
81
82use serde_json::Value as JsonValue;
83use tokio::sync::mpsc;
84
85use crate::chat::message::{MsgVariant, Role};
86
87// ═══════════════════════════════════════════════════════════════
88// Inspector — 只读观察,后台并行,不等待
89// ═══════════════════════════════════════════════════════════════
90
91/// Inspector 错误的类型别名。
92///
93/// 任何实现了 `std::error::Error + Send + Sync + 'static` 的类型都可以作为
94/// inspector 错误返回。
95pub type InspectorError = Box<dyn std::error::Error + Send + Sync + 'static>;
96
97/// 只读检查器——接收 `&Evt`,后台并行执行,不阻塞事件流。
98///
99/// Inspector 通过 `tokio::spawn` 并发执行,其错误通过异步 error channel 报告,
100/// 不会影响 Mutator 阶段的事件处理。
101///
102/// # 示例
103///
104/// ```rust,no_run
105/// # use funera_core::middleware::{InspectorMiddleware, InspectorError};
106/// struct TokenLogger;
107/// impl InspectorMiddleware<String> for TokenLogger {
108///     fn name(&self) -> &str { "token_logger" }
109///     fn inspect(&self, event: &String) -> Result<(), InspectorError> {
110///         eprintln!("[inspector] event: {event}");
111///         Ok(())
112///     }
113/// }
114/// ```
115pub trait InspectorMiddleware<Evt>: Send + Sync {
116    /// 返回此 inspector 的唯一标识名称。
117    fn name(&self) -> &str;
118
119    /// 检查事件(只读),返回 `Ok(())` 或错误(通过 error channel 报告)。
120    ///
121    /// Inspect 的返回值**不会**影响事件流——即使返回 `Err`,事件也会继续传递。
122    fn inspect(&self, event: &Evt) -> Result<(), InspectorError>;
123}
124
125// ═══════════════════════════════════════════════════════════════
126// Mutator — 可变处理,顺序执行,可放行/修改/阻止
127// ═══════════════════════════════════════════════════════════════
128
129/// Mutator 对事件的处理决策。
130pub enum MutatorAction<Evt> {
131    /// 不做任何修改,事件原样放行。
132    Pass,
133    /// 将事件替换为新的值。
134    Modify(Evt),
135    /// 阻止事件继续传递,并附上原因。
136    Block { reason: String },
137}
138
139/// 可变处理器——接收 `Evt`,选择放行/修改/阻止。
140///
141/// 与 [`InspectorMiddleware`] 不同,mutator 在事件流程中**同步顺序执行**,
142/// 其返回的 [`MutatorAction`] 直接决定事件是否继续传递。
143///
144/// # 示例
145///
146/// ```rust,no_run
147/// # use funera_core::middleware::{MutatorMiddleware, MutatorAction};
148/// struct Censor;
149/// impl MutatorMiddleware<String> for Censor {
150///     fn name(&self) -> &str { "censor" }
151///     fn process(&self, event: String) -> MutatorAction<String> {
152///         if event.contains("bad") {
153///             MutatorAction::Modify(event.replace("bad", "***"))
154///         } else {
155///             MutatorAction::Block { reason: "contains bad word".into() }
156///         }
157///     }
158/// }
159/// ```
160pub trait MutatorMiddleware<Evt>: Send + Sync {
161    /// 返回此 mutator 的唯一标识名称。
162    fn name(&self) -> &str;
163
164    /// 处理事件。支持三种决策:
165    /// - [`MutatorAction::Pass`]:放行,事件不变
166    /// - [`MutatorAction::Modify`]:替换事件
167    /// - [`MutatorAction::Block`]:阻止后续传递
168    fn process(&self, event: Evt) -> MutatorAction<Evt>;
169}
170
171// ═══════════════════════════════════════════════════════════════
172// 注册 trait — Bevy 风格 tuple(不提供 blanket impl,避免冲突)
173// ═══════════════════════════════════════════════════════════════
174
175/// 将一组 inspector 转换为 `Vec<Arc<dyn InspectorMiddleware>>`。
176///
177/// 该 trait 为元组 `(A,)` 到 `(A, B, ..., L, M)`(arity 1..=12)实现,
178/// 用于 [`MiddlewareChain::with_inspectors`]。
179///
180/// 单值 inspector 应使用 [`MiddlewareChain::with_inspector`]。
181pub trait IntoInspectors<Evt> {
182    /// 将 self 转换为 inspector 向量。
183    fn into_inspectors(self) -> Vec<Arc<dyn InspectorMiddleware<Evt>>>;
184}
185
186/// 将一组 mutator 转换为 `Vec<Arc<dyn MutatorMiddleware>>`。
187///
188/// 该 trait 为元组 `(A,)` 到 `(A, B, ..., L, M)`(arity 1..=12)实现,
189/// 用于 [`MiddlewareChain::with_mutators`]。
190///
191/// 单值 mutator 应使用 [`MiddlewareChain::with_mutator`]。
192pub trait IntoMutators<Evt> {
193    /// 将 self 转换为 mutator 向量。
194    fn into_mutators(self) -> Vec<Arc<dyn MutatorMiddleware<Evt>>>;
195}
196
197// ── tuple impls (arity 1..=12) ───────────────────────────
198
199macro_rules! impl_into_inspectors_tuple {
200    ($($T:ident),+) => {
201        impl<Evt, $($T: InspectorMiddleware<Evt> + 'static),+> IntoInspectors<Evt>
202            for ($($T,)+)
203        {
204            #[allow(non_snake_case)]
205            fn into_inspectors(self) -> Vec<Arc<dyn InspectorMiddleware<Evt>>> {
206                let ($($T,)+) = self;
207                vec![$(Arc::new($T) as Arc<dyn InspectorMiddleware<Evt>>),+]
208            }
209        }
210    };
211}
212
213macro_rules! impl_into_mutators_tuple {
214    ($($T:ident),+) => {
215        impl<Evt, $($T: MutatorMiddleware<Evt> + 'static),+> IntoMutators<Evt>
216            for ($($T,)+)
217        {
218            #[allow(non_snake_case)]
219            fn into_mutators(self) -> Vec<Arc<dyn MutatorMiddleware<Evt>>> {
220                let ($($T,)+) = self;
221                vec![$(Arc::new($T) as Arc<dyn MutatorMiddleware<Evt>>),+]
222            }
223        }
224    };
225}
226
227impl_into_inspectors_tuple!(A);
228impl_into_inspectors_tuple!(A, B);
229impl_into_inspectors_tuple!(A, B, C);
230impl_into_inspectors_tuple!(A, B, C, D);
231impl_into_inspectors_tuple!(A, B, C, D, F);
232impl_into_inspectors_tuple!(A, B, C, D, F, G);
233impl_into_inspectors_tuple!(A, B, C, D, F, G, H);
234impl_into_inspectors_tuple!(A, B, C, D, F, G, H, I);
235impl_into_inspectors_tuple!(A, B, C, D, F, G, H, I, J);
236impl_into_inspectors_tuple!(A, B, C, D, F, G, H, I, J, K);
237impl_into_inspectors_tuple!(A, B, C, D, F, G, H, I, J, K, L);
238impl_into_inspectors_tuple!(A, B, C, D, F, G, H, I, J, K, L, M);
239
240impl_into_mutators_tuple!(A);
241impl_into_mutators_tuple!(A, B);
242impl_into_mutators_tuple!(A, B, C);
243impl_into_mutators_tuple!(A, B, C, D);
244impl_into_mutators_tuple!(A, B, C, D, F);
245impl_into_mutators_tuple!(A, B, C, D, F, G);
246impl_into_mutators_tuple!(A, B, C, D, F, G, H);
247impl_into_mutators_tuple!(A, B, C, D, F, G, H, I);
248impl_into_mutators_tuple!(A, B, C, D, F, G, H, I, J);
249impl_into_mutators_tuple!(A, B, C, D, F, G, H, I, J, K);
250impl_into_mutators_tuple!(A, B, C, D, F, G, H, I, J, K, L);
251impl_into_mutators_tuple!(A, B, C, D, F, G, H, I, J, K, L, M);
252
253// ═══════════════════════════════════════════════════════════════
254// MiddlewareLayer + MiddlewareChain (typestate)
255// ═══════════════════════════════════════════════════════════════
256
257/// 中间件链中的一层。
258///
259/// 每层可以是 inspector(内部并行)或 mutator(内部顺序)。
260pub enum MiddlewareLayer<Evt> {
261    /// Inspector 层——此层内的所有 inspector 通过 `tokio::spawn` 并行执行。
262    Inspector(Vec<Arc<dyn InspectorMiddleware<Evt>>>),
263    /// Mutator 层——此层内的所有 mutator 按注册顺序依次执行。
264    Mutator(Vec<Arc<dyn MutatorMiddleware<Evt>>>),
265}
266
267// ── Typestate markers ─────────────────────────────────────────
268
269/// 错误通道**尚未**启用的 typestate 标记。
270///
271/// 在此状态下,调用 [`MiddlewareChain::activate_error_channel`] 可激活
272/// 错误通道并转换为 [`ErrorsEnabled`] 状态。
273pub struct ErrorsDisabled;
274
275/// 错误通道**已**启用的 typestate 标记。
276///
277/// 在此状态下,`activate_error_channel` 不可用(编译期保证)。
278/// 可以通过 [`MiddlewareChain::error_sender`] 获取已有 sender。
279pub struct ErrorsEnabled;
280
281/// 中间件链——按注册顺序逐层执行。
282///
283/// 链中的每一层可以是 inspector 或 mutator,通过构建方法指定。
284/// 参数 `ErrState` 是 typestate 标记,默认 [`ErrorsDisabled`]。
285///
286/// ## 执行模型
287///
288/// 1. **Inspector 层**:同一层内的 inspector 通过 `tokio::spawn` 并行执行,
289///    不等待其完成。错误通过 error channel 异步报告。
290///    *无 tokio 运行时*:降级为同步执行。
291/// 2. **Mutator 层**:同一层内的 mutator 按注册顺序依次执行。
292///    遇到 [`MutatorAction::Block`] 立即终止整条链。
293///
294/// ## Typestate 错误通道
295///
296/// ```rust,no_run
297/// # use funera_core::middleware::{MiddlewareChain, ErrorsEnabled, InspectorMiddleware, InspectorError};
298/// # struct Insp;
299/// # impl InspectorMiddleware<String> for Insp {
300/// #     fn name(&self) -> &str { "i" }
301/// #     fn inspect(&self, _: &String) -> Result<(), InspectorError> { Ok(()) }
302/// # }
303/// // 默认状态:ErrorsDisabled
304/// let chain = MiddlewareChain::<String>::new()
305///     .with_inspector(Insp);
306///
307/// // 激活错误通道后变为 ErrorsEnabled
308/// let (chain, rx) = chain.activate_error_channel();
309/// // chain:  MiddlewareChain<String, ErrorsEnabled>
310/// ```
311pub struct MiddlewareChain<Evt, ErrState = ErrorsDisabled> {
312    layers: Vec<MiddlewareLayer<Evt>>,
313    error_tx: Option<mpsc::UnboundedSender<(String, InspectorError)>>,
314    _err: PhantomData<ErrState>,
315}
316
317// ── 仅 ErrorsDisabled:new + activate ─────────────────────────
318
319impl<Evt: Clone + Send + 'static> MiddlewareChain<Evt, ErrorsDisabled> {
320    /// 创建一个新的空中间件链(`ErrorsDisabled` 状态)。
321    ///
322    /// 链初始为空,需要通过 `with_inspector`、`with_mutators` 等方法填充。
323    pub fn new() -> Self {
324        Self {
325            layers: Vec::new(),
326            error_tx: None,
327            _err: PhantomData,
328        }
329    }
330
331    /// 启用错误通道并获取 receiver。
332    ///
333    /// 调用后链的状态变为 [`ErrorsEnabled`],inspector 执行中的错误将通过
334    /// 返回的 receiver 异步送达。此方法**仅可调用一次**(编译期由 typestate 保证)。
335    ///
336    /// 如果不需要跟踪 inspector 错误,可以忽略返回值中的 receiver。
337    ///
338    /// # 示例
339    ///
340    /// ```rust,no_run
341    /// # use funera_core::middleware::{MiddlewareChain, InspectorMiddleware, InspectorError};
342    /// # struct Insp;
343    /// # impl InspectorMiddleware<String> for Insp {
344    /// #     fn name(&self) -> &str { "i" }
345    /// #     fn inspect(&self, _: &String) -> Result<(), InspectorError> { Ok(()) }
346    /// # }
347    /// let chain = MiddlewareChain::<String>::new()
348    ///     .with_inspector(Insp);
349    /// let (_chain, mut error_rx) = chain.activate_error_channel();
350    /// ```
351    pub fn activate_error_channel(
352        self,
353    ) -> (
354        MiddlewareChain<Evt, ErrorsEnabled>,
355        mpsc::UnboundedReceiver<(String, InspectorError)>,
356    ) {
357        let (tx, rx) = mpsc::unbounded_channel();
358        let chain = MiddlewareChain::<Evt, ErrorsEnabled> {
359            layers: self.layers,
360            error_tx: Some(tx),
361            _err: PhantomData,
362        };
363        (chain, rx)
364    }
365}
366
367impl<Evt: Clone + Send + 'static> Default for MiddlewareChain<Evt, ErrorsDisabled> {
368    fn default() -> Self {
369        Self::new()
370    }
371}
372
373// ── 构建方法:两种状态均可用 ──────────────────────────────────
374
375impl<Evt: Clone + Send + 'static, S> MiddlewareChain<Evt, S> {
376    /// 添加单个 inspector 作为独立的一层。
377    ///
378    /// 每个 `with_inspector` 调用创建一个新层,与其他层按注册顺序执行。
379    /// 同一层内的 inspector 通过 `tokio::spawn` 后台并行。
380    pub fn with_inspector(mut self, i: impl InspectorMiddleware<Evt> + 'static) -> Self {
381        self.layers
382            .push(MiddlewareLayer::Inspector(vec![Arc::new(i)]));
383        self
384    }
385
386    /// 添加一组 inspector 作为同一层(并行)。
387    ///
388    /// 接受 Bevy 风格的 tuple `(A, B, C)`,所有 inspector 将在同一层内并行执行。
389    ///
390    /// # 示例
391    ///
392    /// ```rust,no_run
393    /// # use funera_core::middleware::{MiddlewareChain, InspectorMiddleware, InspectorError};
394    /// # struct A; impl InspectorMiddleware<String> for A {
395    /// #     fn name(&self) -> &str { "A" }
396    /// #     fn inspect(&self, _: &String) -> Result<(), InspectorError> { Ok(()) }
397    /// # }
398    /// # struct B; impl InspectorMiddleware<String> for B {
399    /// #     fn name(&self) -> &str { "B" }
400    /// #     fn inspect(&self, _: &String) -> Result<(), InspectorError> { Ok(()) }
401    /// # }
402    /// let chain = MiddlewareChain::<String>::new()
403    ///     .with_inspectors((A, B));  // A 和 B 并行执行
404    /// ```
405    pub fn with_inspectors(mut self, i: impl IntoInspectors<Evt>) -> Self {
406        let v = i.into_inspectors();
407        if !v.is_empty() {
408            self.layers.push(MiddlewareLayer::Inspector(v));
409        }
410        self
411    }
412
413    /// 从迭代器批量添加已装箱的 inspector。
414    pub fn with_inspectors_from_iter(
415        mut self,
416        iter: impl IntoIterator<Item = Arc<dyn InspectorMiddleware<Evt>>>,
417    ) -> Self {
418        let v: Vec<_> = iter.into_iter().collect();
419        if !v.is_empty() {
420            self.layers.push(MiddlewareLayer::Inspector(v));
421        }
422        self
423    }
424
425    /// 添加单个 mutator 作为独立的一层。
426    ///
427    /// 每个 `with_mutator` 调用创建一个新层。同一层内的 mutator 按顺序执行。
428    pub fn with_mutator(mut self, m: impl MutatorMiddleware<Evt> + 'static) -> Self {
429        self.layers.push(MiddlewareLayer::Mutator(vec![Arc::new(m)]));
430        self
431    }
432
433    /// 添加一组 mutator 作为同一层(顺序执行)。
434    ///
435    /// 接受 Bevy 风格的 tuple `(A, B, C)`,所有 mutator 按注册顺序依次执行。
436    ///
437    /// # 示例
438    ///
439    /// ```rust,no_run
440    /// # use funera_core::middleware::{MiddlewareChain, MutatorMiddleware, MutatorAction};
441    /// # struct Censor; impl MutatorMiddleware<String> for Censor {
442    /// #     fn name(&self) -> &str { "censor" }
443    /// #     fn process(&self, s: String) -> MutatorAction<String> { MutatorAction::Pass }
444    /// # }
445    /// # struct Blocker; impl MutatorMiddleware<String> for Blocker {
446    /// #     fn name(&self) -> &str { "blocker" }
447    /// #     fn process(&self, s: String) -> MutatorAction<String> { MutatorAction::Pass }
448    /// # }
449    /// let chain = MiddlewareChain::<String>::new()
450    ///     .with_mutators((Censor, Blocker));  // Censor 先,Blocker 后
451    /// ```
452    pub fn with_mutators(mut self, m: impl IntoMutators<Evt>) -> Self {
453        let v = m.into_mutators();
454        if !v.is_empty() {
455            self.layers.push(MiddlewareLayer::Mutator(v));
456        }
457        self
458    }
459
460    /// 从迭代器批量添加已装箱的 mutator。
461    pub fn with_mutators_from_iter(
462        mut self,
463        iter: impl IntoIterator<Item = Arc<dyn MutatorMiddleware<Evt>>>,
464    ) -> Self {
465        let v: Vec<_> = iter.into_iter().collect();
466        if !v.is_empty() {
467            self.layers.push(MiddlewareLayer::Mutator(v));
468        }
469        self
470    }
471
472    /// 链中是否没有任何 middleware 层。
473    pub fn is_empty(&self) -> bool {
474        self.layers.is_empty()
475    }
476
477    /// 返回 middleware 层的数量。
478    pub fn len(&self) -> usize {
479        self.layers.len()
480    }
481
482    /// 按注册顺序逐层执行。
483    ///
484    /// ## 执行流程
485    ///
486    /// - **Inspector 层**:`tokio::spawn` 后台并发执行,不等待,错误进入 error channel。
487    ///   如果当前没有 tokio 运行时,降级为同步执行。
488    /// - **Mutator 层**:同步顺序执行。遇到 `Block` 立即短路,返回 `Err(MiddlewareBlocked)`。
489    ///
490    /// ## 返回值
491    ///
492    /// - `Ok(event)` — 经过所有 layer 处理后的最终事件
493    /// - `Err(MiddlewareBlocked)` — 被 mutator 阻止
494    pub fn process(&self, event: Evt) -> Result<Evt, MiddlewareBlocked> {
495        let mut current = event;
496        for layer in &self.layers {
497            match layer {
498                MiddlewareLayer::Inspector(inspectors) => {
499                    current = self.run_inspectors(inspectors, current);
500                }
501                MiddlewareLayer::Mutator(mutators) => {
502                    current = self.run_mutators(mutators, current)?;
503                }
504            }
505        }
506        Ok(current)
507    }
508
509    fn run_inspectors(
510        &self,
511        inspectors: &[Arc<dyn InspectorMiddleware<Evt>>],
512        event: Evt,
513    ) -> Evt {
514        if let Ok(handle) = tokio::runtime::Handle::try_current() {
515            for insp in inspectors {
516                let name = insp.name().to_string();
517                let evt = event.clone();
518                let tx = self.error_tx.clone();
519                let insp = Arc::clone(insp);
520                handle.spawn(async move {
521                    if let Err(e) = insp.inspect(&evt)
522                        && let Some(tx) = tx
523                    {
524                        let _ = tx.send((name, e));
525                    }
526                });
527            }
528        } else {
529            for insp in inspectors {
530                if let (Some(tx), Err(e)) = (&self.error_tx, insp.inspect(&event)) {
531                    let _ = tx.send((insp.name().to_string(), e));
532                }
533            }
534        }
535        event
536    }
537
538    fn run_mutators(
539        &self,
540        mutators: &[Arc<dyn MutatorMiddleware<Evt>>],
541        event: Evt,
542    ) -> Result<Evt, MiddlewareBlocked> {
543        let mut current = event;
544        for m in mutators {
545            match m.process(current.clone()) {
546                MutatorAction::Pass => {}
547                MutatorAction::Modify(e) => current = e,
548                MutatorAction::Block { reason } => {
549                    return Err(MiddlewareBlocked {
550                        middleware_name: m.name().to_string(),
551                        reason,
552                    });
553                }
554            }
555        }
556        Ok(current)
557    }
558}
559
560// ── ErrorsEnabled: 暴露 error channel ─────────────────────────
561
562impl<Evt: Clone + Send + 'static> MiddlewareChain<Evt, ErrorsEnabled> {
563    /// 返回底层 error channel 的 sender,可用于外部发送错误。
564    ///
565    /// 返回的 sender 是 `Option`——如果 chain 构造时未激活错误通道则为 `None`。
566    pub fn error_sender(&self) -> Option<mpsc::UnboundedSender<(String, InspectorError)>> {
567        self.error_tx.clone()
568    }
569}
570
571// ═══════════════════════════════════════════════════════════════
572// MiddlewareBlocked
573// ═══════════════════════════════════════════════════════════════
574
575/// 事件被 mutator 阻止时的错误信息。
576#[derive(Debug, Clone)]
577pub struct MiddlewareBlocked {
578    /// 阻止事件的 mutator 名称。
579    pub middleware_name: String,
580    /// 阻止原因。
581    pub reason: String,
582}
583
584impl std::fmt::Display for MiddlewareBlocked {
585    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
586        write!(
587            f,
588            "[middleware:{}] event blocked: {}",
589            self.middleware_name, self.reason
590        )
591    }
592}
593
594// ═══════════════════════════════════════════════════════════════
595// MiddlewareEvent — ReAct loop 每轮产出的可过滤事件
596// ═══════════════════════════════════════════════════════════════
597
598/// 用于 `react_loop` 向上层通知事件的可调用对象。
599///
600/// 由 `funera-orchestrate` 提供实现(封装 callbacks + event_tx),
601/// `react_loop` 在每轮聚合数据后调用此函数发出已过滤的事件。
602pub type EventSenderFn<E> = Box<dyn Fn(E) + Send + Sync>;
603
604/// ReAct 循环每轮产出的中间件事件。
605///
606/// `react_loop` 在 `process_token_stream` 和 `handle_turn_finish` 后
607/// 将聚合结果转换为 `MiddlewareEvent`,经过 middleware chain 过滤后:
608/// - 发出到上层(`event_tx` + callbacks)
609/// - 转换为 `FuneraMessage` 存入 session 历史
610///
611/// 由 `AgentEvent`(`funera-orchestrate`)实现此 trait。
612pub trait MiddlewareEvent: Clone + Send + 'static {
613    /// 工具错误类型。
614    type Error: std::fmt::Display + Send + Sync + 'static + From<String>;
615
616    /// Factory:assistant 聚合文本回复。
617    fn assistant_text(content: String, reasoning: Option<String>) -> Self;
618
619    /// Factory:单个工具调用请求。
620    fn tool_call_request(call_id: Arc<str>, name: String, args: JsonValue) -> Self;
621
622    /// Factory:单个工具执行结果。
623    fn tool_response(
624        call_id: Arc<str>,
625        name: String,
626        result: Result<String, Self::Error>,
627    ) -> Self;
628
629    /// Factory:turn 开始。
630    fn turn_start() -> Self;
631
632    /// Factory:turn 结束,携带 finish_reason。
633    fn turn_end(finish_reason: Option<String>) -> Self;
634
635    /// Factory:会话结束。
636    fn done() -> Self;
637
638    /// 转换为 session 历史消息。
639    ///
640    /// 返回 `Some((role, variant))` 用于构造 `FuneraMessage`。
641    /// 不可转换的事件(如 `TurnStart`、`TurnEnd`、`Done`)返回 `None`。
642    fn into_session_message(self) -> Option<(Role, MsgVariant)>;
643}
644
645#[cfg(test)]
646mod tests {
647    use super::*;
648
649    struct NoopInspector;
650
651    impl InspectorMiddleware<String> for NoopInspector {
652        fn name(&self) -> &str {
653            "noop"
654        }
655        fn inspect(&self, _event: &String) -> Result<(), InspectorError> {
656            Ok(())
657        }
658    }
659
660    struct UpperMutator;
661
662    impl MutatorMiddleware<String> for UpperMutator {
663        fn name(&self) -> &str {
664            "upper"
665        }
666        fn process(&self, event: String) -> MutatorAction<String> {
667            MutatorAction::Modify(event.to_uppercase())
668        }
669    }
670
671    struct BlockMutator;
672
673    impl MutatorMiddleware<String> for BlockMutator {
674        fn name(&self) -> &str {
675            "blocker"
676        }
677        fn process(&self, _event: String) -> MutatorAction<String> {
678            MutatorAction::Block {
679                reason: "blocked".into(),
680            }
681        }
682    }
683
684    struct PassMutator;
685
686    impl MutatorMiddleware<String> for PassMutator {
687        fn name(&self) -> &str {
688            "pass"
689        }
690        fn process(&self, _event: String) -> MutatorAction<String> {
691            MutatorAction::Pass
692        }
693    }
694
695    #[test]
696    fn new_chain_is_empty() {
697        let chain = MiddlewareChain::<String>::new();
698        assert!(chain.is_empty());
699    }
700
701    #[test]
702    fn single_mutator_modify() {
703        let chain = MiddlewareChain::<String>::new().with_mutator(UpperMutator);
704        let result = chain.process("hello".into()).unwrap();
705        assert_eq!(result, "HELLO");
706    }
707
708    #[test]
709    fn single_mutator_pass() {
710        let chain = MiddlewareChain::<String>::new().with_mutator(PassMutator);
711        let result = chain.process("hello".into()).unwrap();
712        assert_eq!(result, "hello");
713    }
714
715    #[test]
716    fn single_mutator_block() {
717        let chain = MiddlewareChain::<String>::new().with_mutator(BlockMutator);
718        let err = chain.process("hello".into()).unwrap_err();
719        assert_eq!(err.middleware_name, "blocker");
720        assert_eq!(err.reason, "blocked");
721    }
722
723    #[test]
724    fn pass_then_modify() {
725        let chain = MiddlewareChain::<String>::new()
726            .with_mutators((PassMutator, UpperMutator));
727        let result = chain.process("hello".into()).unwrap();
728        assert_eq!(result, "HELLO");
729    }
730
731    #[test]
732    fn modify_then_block() {
733        let chain = MiddlewareChain::<String>::new()
734            .with_mutators((UpperMutator, BlockMutator));
735        let err = chain.process("hello".into()).unwrap_err();
736        assert_eq!(err.middleware_name, "blocker");
737    }
738
739    #[test]
740    fn tuple_arity_3() {
741        let chain = MiddlewareChain::<String>::new()
742            .with_mutators((UpperMutator, PassMutator, PassMutator));
743        let result = chain.process("hello".into()).unwrap();
744        assert_eq!(result, "HELLO");
745    }
746
747    #[test]
748    fn inspector_without_tokio_is_noop() {
749        let chain = MiddlewareChain::<String>::new()
750            .with_inspector(NoopInspector)
751            .with_mutator(UpperMutator);
752        let result = chain.process("hello".into()).unwrap();
753        assert_eq!(result, "HELLO");
754    }
755
756    #[test]
757    fn activate_error_channel_transitions_state() {
758        let chain = MiddlewareChain::<String>::new();
759        let (_enabled, _rx) = chain.activate_error_channel();
760    }
761
762    #[test]
763    fn with_inspectors_tuple() {
764        let chain = MiddlewareChain::<String>::new()
765            .with_inspectors((NoopInspector, NoopInspector));
766        assert_eq!(chain.len(), 1);
767    }
768
769    #[test]
770    fn single_inspector_tuple() {
771        let chain = MiddlewareChain::<String>::new()
772            .with_inspectors((NoopInspector,));
773        assert_eq!(chain.len(), 1);
774    }
775
776    #[test]
777    fn chain_with_tokio_spawns_inspectors() {
778        let rt = tokio::runtime::Builder::new_current_thread()
779            .build()
780            .unwrap();
781        rt.block_on(async {
782            let chain = MiddlewareChain::<String>::new()
783                .with_inspector(NoopInspector);
784            let result = chain.process("hi".into()).unwrap();
785            assert_eq!(result, "hi");
786        });
787    }
788}