177 lines
5.1 KiB
Go
177 lines
5.1 KiB
Go
// 织忆 MemoryWeave — 触发器执行器
|
|
package selfoptimize
|
|
|
|
import (
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// ─── 触发器执行器 ──────────────────────────────────────
|
|
|
|
// TriggerExecutor 8 类触发器自动执行循环
|
|
type TriggerExecutor struct {
|
|
mu sync.RWMutex
|
|
triggers []*TriggerDef
|
|
checkInterval time.Duration
|
|
eventBus TriggerEventBus
|
|
}
|
|
|
|
// TriggerDef 触发器定义
|
|
type TriggerDef struct {
|
|
ID string `json:"id"`
|
|
Type TriggerExType `json:"type"`
|
|
Condition interface{} `json:"condition"`
|
|
Action string `json:"action"` // 触发的流水线任务类型
|
|
LastFired time.Time `json:"last_fired"`
|
|
Cooldown time.Duration `json:"cooldown"` // 冷却时间
|
|
Enabled bool `json:"enabled"`
|
|
FireCount int `json:"fire_count"`
|
|
}
|
|
|
|
type TriggerExType string
|
|
|
|
const (
|
|
TCommitCount TriggerExType = "commit_count" // 新增 N 条
|
|
TTimeSince TriggerExType = "time_since" // 距上次 N 小时
|
|
TRecallMiss TriggerExType = "recall_miss" // 连续 N 次 miss
|
|
TQualityDrop TriggerExType = "quality_drop" // quality < threshold
|
|
TGapDetected TriggerExType = "gap_detected" // 新缺口
|
|
TConflict TriggerExType = "conflict_pending" // 待解决冲突
|
|
TVValueLow TriggerExType = "v_value_low" // V 值过低
|
|
TDecayCritical TriggerExType = "decay_critical" // 衰减临界
|
|
)
|
|
|
|
type TriggerEventBus interface {
|
|
OnTrigger(trigger *TriggerDef)
|
|
}
|
|
|
|
// 全局触发器状态
|
|
var Executor = &TriggerExecutor{
|
|
triggers: makeTriggers(),
|
|
checkInterval: 5 * time.Minute,
|
|
}
|
|
|
|
func makeTriggers() []*TriggerDef {
|
|
return []*TriggerDef{
|
|
{ID: "t1", Type: TCommitCount, Condition: 50, Action: "consolidate", Cooldown: 24 * time.Hour, Enabled: true},
|
|
{ID: "t2", Type: TTimeSince, Condition: 48.0, Action: "consolidate", Cooldown: 24 * time.Hour, Enabled: true},
|
|
{ID: "t3", Type: TRecallMiss, Condition: 3, Action: "gap_classify", Cooldown: 30 * time.Minute, Enabled: true},
|
|
{ID: "t4", Type: TQualityDrop, Condition: 0.3, Action: "deprecate_review", Cooldown: 1 * time.Hour, Enabled: true},
|
|
{ID: "t5", Type: TGapDetected, Condition: true, Action: "gap_fill", Cooldown: 5 * time.Minute, Enabled: true},
|
|
{ID: "t6", Type: TConflict, Condition: 3, Action: "conflict_muchen", Cooldown: 10 * time.Minute, Enabled: true},
|
|
{ID: "t7", Type: TVValueLow, Condition: 0.2, Action: "mem_review", Cooldown: 12 * time.Hour, Enabled: true},
|
|
{ID: "t8", Type: TDecayCritical, Condition: 0.1, Action: "archive_or_boost", Cooldown: 6 * time.Hour, Enabled: true},
|
|
}
|
|
}
|
|
|
|
// Start 启动触发器检查循环
|
|
func (te *TriggerExecutor) Start(flow *Pipeline) {
|
|
if te.eventBus == nil {
|
|
te.eventBus = &defaultEventBus{flow: flow}
|
|
}
|
|
go te.loop()
|
|
log.Println("[executor] 触发器执行器启动 (8 triggers)")
|
|
}
|
|
|
|
func (te *TriggerExecutor) loop() {
|
|
ticker := time.NewTicker(te.checkInterval)
|
|
defer ticker.Stop()
|
|
|
|
for range ticker.C {
|
|
te.checkAll()
|
|
}
|
|
}
|
|
|
|
func (te *TriggerExecutor) checkAll() {
|
|
te.mu.RLock()
|
|
triggers := make([]*TriggerDef, len(te.triggers))
|
|
copy(triggers, te.triggers)
|
|
te.mu.RUnlock()
|
|
|
|
metrics := Dash.Metrics()
|
|
|
|
for _, t := range triggers {
|
|
if !t.Enabled {
|
|
continue
|
|
}
|
|
if time.Since(t.LastFired) < t.Cooldown {
|
|
continue
|
|
}
|
|
if te.evaluate(t, metrics) {
|
|
t.LastFired = time.Now()
|
|
t.FireCount++
|
|
te.eventBus.OnTrigger(t)
|
|
log.Printf("[executor] trigger %s fired (count=%d)", t.ID, t.FireCount)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (te *TriggerExecutor) evaluate(t *TriggerDef, metrics map[string]float64) bool {
|
|
switch t.Type {
|
|
case TCommitCount:
|
|
// 需要 commit 计数(从 LanceDB stats 获取)
|
|
return false // 待集成
|
|
case TTimeSince:
|
|
hours := time.Since(t.LastFired).Hours()
|
|
threshold, _ := t.Condition.(float64)
|
|
return hours >= threshold
|
|
case TRecallMiss:
|
|
// 检查最近的 miss 计数
|
|
rate, ok := metrics["recall_hit_rate"]
|
|
return ok && rate > 0 && t.LastFired.IsZero()
|
|
case TQualityDrop:
|
|
threshold, _ := t.Condition.(float64)
|
|
return metrics["recall_usefulness_rate"] < threshold
|
|
case TGapDetected:
|
|
return metrics["gap_closure_rate"] < 0.5
|
|
case TConflict:
|
|
return metrics["auto_resolve_rate"] < 0.5
|
|
case TVValueLow:
|
|
threshold, _ := t.Condition.(float64)
|
|
return metrics["recall_usefulness_rate"] < threshold
|
|
case TDecayCritical:
|
|
return metrics["deprecated_per_day"] > 5
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Fire 手动触发
|
|
func (te *TriggerExecutor) Fire(triggerID string) bool {
|
|
te.mu.RLock()
|
|
defer te.mu.RUnlock()
|
|
|
|
for _, t := range te.triggers {
|
|
if t.ID == triggerID {
|
|
t.LastFired = time.Now()
|
|
t.FireCount++
|
|
te.eventBus.OnTrigger(t)
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// List 返回所有触发器状态
|
|
func (te *TriggerExecutor) List() []*TriggerDef {
|
|
te.mu.RLock()
|
|
defer te.mu.RUnlock()
|
|
result := make([]*TriggerDef, len(te.triggers))
|
|
copy(result, te.triggers)
|
|
return result
|
|
}
|
|
|
|
// defaultEventBus 默认实现:触发 → 入队到流水线
|
|
type defaultEventBus struct {
|
|
flow *Pipeline
|
|
}
|
|
|
|
func (eb *defaultEventBus) OnTrigger(t *TriggerDef) {
|
|
if eb.flow != nil {
|
|
eb.flow.Enqueue(t.Action, map[string]string{
|
|
"trigger_id": t.ID,
|
|
"action": t.Action,
|
|
})
|
|
}
|
|
}
|