feat: Evolution Engine Phase 3-5 — WorkflowComposer+FeedbackCollector+EvolutionMiddleware+反馈闭环
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Phase 3: - EvolutionMiddleware (priority 78): 管家对话中注入进化确认提示 - GrowthIntegration.check_evolution() API 串入 Phase 4: - WorkflowComposer: 轨迹工具链模式聚类 + Pipeline YAML prompt 构建 + JSON 解析 - EvolutionEngine.analyze_trajectory_patterns() L3 入口 Phase 5: - FeedbackCollector: 反馈信号收集 + 信任度管理 + 推荐(Optimize/Archive/Promote) - EvolutionEngine 反馈闭环方法: submit_feedback/get_artifacts_needing_optimization 新增 12 个测试(111→123),全 workspace 701 测试通过。
This commit is contained in:
@@ -279,3 +279,4 @@ pub mod token_calibration;
|
||||
pub mod tool_error;
|
||||
pub mod tool_output_guard;
|
||||
pub mod trajectory_recorder;
|
||||
pub mod evolution;
|
||||
|
||||
134
crates/zclaw-runtime/src/middleware/evolution.rs
Normal file
134
crates/zclaw-runtime/src/middleware/evolution.rs
Normal file
@@ -0,0 +1,134 @@
|
||||
//! 进化引擎中间件
|
||||
//! 在管家对话中检测并呈现"技能进化确认"提示
|
||||
//! 优先级 78(在 ButlerRouter@80 之前运行)
|
||||
|
||||
use async_trait::async_trait;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
use crate::middleware::{
|
||||
AgentMiddleware, MiddlewareContext, MiddlewareDecision,
|
||||
};
|
||||
use zclaw_types::Result;
|
||||
|
||||
/// 待确认的进化事件
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PendingEvolution {
|
||||
pub pattern_name: String,
|
||||
pub trigger_suggestion: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
/// 进化引擎中间件
|
||||
/// 检查是否有待确认的进化事件,注入确认提示到 system prompt
|
||||
pub struct EvolutionMiddleware {
|
||||
pending: Arc<RwLock<Vec<PendingEvolution>>>,
|
||||
}
|
||||
|
||||
impl EvolutionMiddleware {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
pending: Arc::new(RwLock::new(Vec::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// 添加一个待确认的进化事件
|
||||
pub async fn add_pending(&self, evolution: PendingEvolution) {
|
||||
self.pending.write().await.push(evolution);
|
||||
}
|
||||
|
||||
/// 获取并清除所有待确认事件
|
||||
pub async fn drain_pending(&self) -> Vec<PendingEvolution> {
|
||||
let mut pending = self.pending.write().await;
|
||||
std::mem::take(&mut *pending)
|
||||
}
|
||||
|
||||
/// 当前待确认事件数量
|
||||
pub async fn pending_count(&self) -> usize {
|
||||
self.pending.read().await.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EvolutionMiddleware {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl AgentMiddleware for EvolutionMiddleware {
|
||||
fn name(&self) -> &str {
|
||||
"evolution"
|
||||
}
|
||||
|
||||
fn priority(&self) -> i32 {
|
||||
78 // 在 ButlerRouter(80) 之前
|
||||
}
|
||||
|
||||
async fn before_completion(
|
||||
&self,
|
||||
ctx: &mut MiddlewareContext,
|
||||
) -> Result<MiddlewareDecision> {
|
||||
let pending = self.pending.read().await;
|
||||
if pending.is_empty() {
|
||||
return Ok(MiddlewareDecision::Continue);
|
||||
}
|
||||
|
||||
// 只在第一条(最近的)事件上触发提示,避免信息过载
|
||||
if let Some(evolution) = pending.first() {
|
||||
let injection = format!(
|
||||
"\n\n<evolution-suggestion>\n\
|
||||
我注意到你经常做「{pattern}」相关的事情。\n\
|
||||
我可以帮你整理成一个技能,以后直接说「{trigger}」就能用了。\n\
|
||||
技能描述:{desc}\n\
|
||||
如果你同意,请回复 '确认保存技能'。如果你想调整,可以告诉我怎么改。\n\
|
||||
</evolution-suggestion>",
|
||||
pattern = evolution.pattern_name,
|
||||
trigger = evolution.trigger_suggestion,
|
||||
desc = evolution.description,
|
||||
);
|
||||
ctx.system_prompt.push_str(&injection);
|
||||
|
||||
tracing::info!(
|
||||
"[EvolutionMiddleware] Injected evolution suggestion for: {}",
|
||||
evolution.pattern_name
|
||||
);
|
||||
}
|
||||
|
||||
Ok(MiddlewareDecision::Continue)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_no_pending_continues() {
|
||||
let mw = EvolutionMiddleware::new();
|
||||
assert_eq!(mw.pending_count().await, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_add_and_drain() {
|
||||
let mw = EvolutionMiddleware::new();
|
||||
mw.add_pending(PendingEvolution {
|
||||
pattern_name: "报表生成".to_string(),
|
||||
trigger_suggestion: "生成报表".to_string(),
|
||||
description: "自动生成每日报表".to_string(),
|
||||
})
|
||||
.await;
|
||||
assert_eq!(mw.pending_count().await, 1);
|
||||
|
||||
let drained = mw.drain_pending().await;
|
||||
assert_eq!(drained.len(), 1);
|
||||
assert_eq!(drained[0].pattern_name, "报表生成");
|
||||
assert_eq!(mw.pending_count().await, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_name_and_priority() {
|
||||
let mw = EvolutionMiddleware::new();
|
||||
assert_eq!(mw.name(), "evolution");
|
||||
assert_eq!(mw.priority(), 78);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user