mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 09:28:14 +00:00
设计依据 docs/zh/input-scheduler-design.md §11.5(O1/O2)、§11.6(E1/E2)。
- 可观测性:KernelStatus 新增 Scheduler 段(running/三集合深度/计数/
深度上限),由 GetKernelStatus 从 DumpScheduler 原子快照填充;
新增 events.EventScheduler,挂起/恢复各发一条(action/task/level)
- TaskKind.String() 便于日志与状态输出
- 新增 scheduler_e2e_test.go 3 项:
· 压力:200 排队输入 + 50 中断全部经真实 loop 执行,结束时三集合排空、
LLM 调用数精确等于输入数、无 Rejected
· 可观测性:挂起/恢复事件齐备,状态快照计数一致
· 端到端:完整启动 schedulerLoop+interceptLoop,经真实 channel 投递
L1 任务与 L4 中断,验证「LLM 流式中断 → 挂起 → 中断先完成 → 原任务恢复」
整条链路(LLM 调用数 = 丢弃1+中断1+恢复1+常规1)
- 验收:agent 全量 + -race;全仓 build/vet 通过
101 lines
2.7 KiB
Go
101 lines
2.7 KiB
Go
package events
|
||
|
||
import (
|
||
"fmt"
|
||
"log"
|
||
"sync"
|
||
)
|
||
|
||
type EventType string
|
||
|
||
const (
|
||
EventRawInput EventType = "raw_input"
|
||
EventAgentOutput EventType = "agent_output"
|
||
EventAgentLLMChain EventType = "agent_llm_chain"
|
||
EventToolCall EventType = "tool_call"
|
||
EventReasoning EventType = "reasoning"
|
||
EventStage EventType = "stage"
|
||
// EventScheduler 是输入调度器的状态变更事件(抢占/挂起/恢复),
|
||
// 供状态页与诊断订阅(设计文档 §11 O2)。
|
||
EventScheduler EventType = "scheduler"
|
||
EventSystem EventType = "system"
|
||
EventTerminalOutput EventType = "terminal_output"
|
||
|
||
// 流式增量事件(LLM token 级):核心改为流式后每收到一个增量块发布。
|
||
// 订阅者可选订;不认识的旧订阅者自然忽略(Bus 按 EventType 精确匹配分发)。
|
||
// 聚合事件 EventReasoning / EventAgentLLMChain 仍照常在每轮结束时全文发布,
|
||
// 插件体系行为不变。
|
||
EventReasoningDelta EventType = "reasoning_delta"
|
||
EventContentDelta EventType = "content_delta"
|
||
|
||
// skill_detected:clawhubadapter(OpenClaw 兼容层)扫描 skills 目录时
|
||
// 发现纯 SKILL 类型插件后发布,由原生 skillmgr 插件订阅并接管注册。
|
||
// 职责链:发现者(兼容层)→ 移交事件 → 归属者(skillmgr)加载管理。
|
||
EventSkillDetected EventType = "skill_detected"
|
||
|
||
EventAll EventType = "*"
|
||
)
|
||
|
||
type Event struct {
|
||
Type EventType `json:"type"`
|
||
Source string `json:"source"`
|
||
Payload map[string]interface{} `json:"payload"`
|
||
Timestamp int64 `json:"timestamp"`
|
||
}
|
||
|
||
type Handler func(event *Event)
|
||
|
||
type Bus struct {
|
||
mu sync.RWMutex
|
||
subs map[EventType][]Handler
|
||
}
|
||
|
||
func NewBus() *Bus {
|
||
return &Bus{
|
||
subs: make(map[EventType][]Handler),
|
||
}
|
||
}
|
||
|
||
func (b *Bus) Publish(evt *Event) {
|
||
b.mu.RLock()
|
||
allHandlers := make([]Handler, len(b.subs[EventAll]))
|
||
copy(allHandlers, b.subs[EventAll])
|
||
typeHandlers := make([]Handler, len(b.subs[evt.Type]))
|
||
copy(typeHandlers, b.subs[evt.Type])
|
||
b.mu.RUnlock()
|
||
|
||
for _, h := range allHandlers {
|
||
b.safeCall(h, evt)
|
||
}
|
||
for _, h := range typeHandlers {
|
||
b.safeCall(h, evt)
|
||
}
|
||
}
|
||
|
||
func (b *Bus) safeCall(h Handler, evt *Event) {
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
log.Printf("[bus] handler panic: %v", r)
|
||
}
|
||
}()
|
||
h(evt)
|
||
}
|
||
|
||
func (b *Bus) Subscribe(eventType EventType, handler Handler) func() {
|
||
b.mu.Lock()
|
||
b.subs[eventType] = append(b.subs[eventType], handler)
|
||
b.mu.Unlock()
|
||
|
||
return func() {
|
||
b.mu.Lock()
|
||
defer b.mu.Unlock()
|
||
list := b.subs[eventType]
|
||
for i, h := range list {
|
||
if fmt.Sprintf("%p", h) == fmt.Sprintf("%p", handler) {
|
||
b.subs[eventType] = append(list[:i], list[i+1:]...)
|
||
break
|
||
}
|
||
}
|
||
}
|
||
}
|