mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-06 17:27:31 +00:00
feat(agent/core): 中断向量表 —— 三个 L4 源统一登记,行为零变化
用户原话:「需要添加中断向量系统,独立成中断子模块就是为了方便添加这个
中断向量系统」。本次落地该目的。
## 为什么需要向量表
拆分前"有哪些内核中断、各自什么语义"散落在三个裸调用点上:
raiseKernelInterrupt("kernel", "kernel", "任务 #N panic…")
raiseKernelInterrupt("kernel/overflow", "kernel", "上下文超页…")
raiseKernelInterrupt("child/"+rc.id, "kernel", "驻留子已满…")
三者差异**只在 source 字符串**上,语义契约全靠注释与调用方自律。
最能说明问题的是 panic 的递归保护:
if t.Class == TaskInterrupt && t.Level >= LevelCritical { return }
// 否则同一个 panic 会自我放大成中断风暴
这条规则只属于"panic 中断",却硬编码在 reportTaskPanic 里。
**新增一种内核中断时,没人会记得要不要也加递归保护**。
## 设计
interruptVector 声明一条中断源的完整契约:
ID / Level / Source / Guard / Build
- Level 由条目自己声明(不再写死 L4)
- Guard 收容前置判定 —— panic 的递归保护落在这里
- Build 构造正文(模型唯一可见内容)
- 未登记 ID **panic**,不静默降级(打错 ID 会变成"中断发了但没人认领")
## 改动
新增 interrupt_vectors.go + interrupt_vectors_test.go(7 条判据)
三个调用点全部改为 raiseVector(id, args)
新增 raiseKernelInterruptAt / newKernelInterruptTaskAt 以表达条目声明的级别
## 行为零变化(刻意)
- 三个源的 source/正文/级别与改动前逐字一致
- ExpectsReply 字段**未实现**:按计划 §7.5/§7.6,它属于行为变更
(内核提示不再引起模型整轮回复),必须单独提交、单独验证
## 变异验证
- 去掉 panic 递归保护 ⇒ TestVectors_PanicGuardBlocksRecursiveL4 红
- 调用点绕过向量表 ⇒ TestVectors_PanicSourceComesFromTable 红
(source="kernel-direct",期望 "kernel")
## 验证
go build ./... / go test ./internal/agent/core/ / go test -race 全通过
This commit is contained in:
@ -1181,7 +1181,17 @@ func newSelfTask(msg selfInputMsg) *Task {
|
||||
// 这是 L4 的唯一来源:panic 中断、内核事件中断(selfip)。
|
||||
// 插件永远拿不到这个入口——它不经 InjectOptions,也不经 proc 桥。
|
||||
func newKernelInterruptTask(evt *agentIO.InputEvent) *Task {
|
||||
return &Task{Class: TaskInterrupt, Kind: TaskKindInput, Level: LevelCritical, Event: evt, EnqueuedAt: time.Now()}
|
||||
return newKernelInterruptTaskAt(evt, LevelCritical)
|
||||
}
|
||||
|
||||
// newKernelInterruptTaskAt 按指定级别构造内核中断任务。
|
||||
//
|
||||
// 内核源不夹取级别(与插件源不同):向量表里登记的级别就是最终级别。
|
||||
func newKernelInterruptTaskAt(evt *agentIO.InputEvent, level Level) *Task {
|
||||
if level < LevelBackground || level > LevelCritical {
|
||||
level = LevelCritical
|
||||
}
|
||||
return &Task{Class: TaskInterrupt, Kind: TaskKindInput, Level: level, Event: evt, EnqueuedAt: time.Now()}
|
||||
}
|
||||
|
||||
// DumpScheduler 返回调度器的原子快照(供状态页/测试断言)。
|
||||
@ -1350,8 +1360,20 @@ func (a *Agent) pumpInbox() {
|
||||
// 能否抢占由调度器按统一判据决定;若会抢占,则顺手取消可取消的 LLM 流式步骤
|
||||
// (与 interceptLoop 对插件中断的处理完全一致)。
|
||||
func (a *Agent) raiseKernelInterrupt(source, channel, text string) {
|
||||
a.raiseKernelInterruptAt(source, channel, text, LevelCritical)
|
||||
}
|
||||
|
||||
// raiseKernelInterruptAt 是 raiseKernelInterrupt 的**带级别**版本。
|
||||
//
|
||||
// 级别由调用方给出(中断向量表里登记的那个),而不是在这里写死 L4:
|
||||
// 向量表的每条都声明了自己的 Level,这条通道必须能表达它,
|
||||
// 否则"级别由向量声明"就成了一句空话。
|
||||
//
|
||||
// 注意:外部插件走的不是这条路(它们经 interruptLevel 解析 + clampPluginLevel
|
||||
// 夹取),这里只服务内核自己登记的中断源。
|
||||
func (a *Agent) raiseKernelInterruptAt(source, channel, text string, level Level) bool {
|
||||
if a.sched == nil {
|
||||
return
|
||||
return false
|
||||
}
|
||||
evt := &agentIO.InputEvent{
|
||||
Source: source,
|
||||
@ -1365,9 +1387,11 @@ func (a *Agent) raiseKernelInterrupt(source, channel, text string) {
|
||||
"kernel": true,
|
||||
},
|
||||
}
|
||||
if a.sched.requestKernelPreempt(evt) {
|
||||
armed := a.sched.registerInterrupt(newKernelInterruptTaskAt(evt, level))
|
||||
if armed {
|
||||
a.cancelCurrentLLM()
|
||||
}
|
||||
return armed
|
||||
}
|
||||
|
||||
// reportTaskPanic 把一个任务 panic 报告成内核 L4 中断。
|
||||
@ -1375,11 +1399,9 @@ func (a *Agent) raiseKernelInterrupt(source, channel, text string) {
|
||||
// 递归保护是**结构性**的:若 panic 的任务本身就是 L4 内核中断,则不再产生新的
|
||||
// L4——否则同一个 panic 会自我放大成中断风暴,与“内核事件”应有的语义相反。
|
||||
func (a *Agent) reportTaskPanic(t *Task, r interface{}) {
|
||||
if t.Class == TaskInterrupt && t.Level >= LevelCritical {
|
||||
return
|
||||
}
|
||||
a.raiseKernelInterrupt("kernel", "kernel",
|
||||
fmt.Sprintf("内核事件:任务 #%d 发生 panic:%v(该任务已被丢弃,调度器存活)", t.ID, r))
|
||||
// 递归保护("L4 panic 不再产生 L4")已收进向量表的 Guard,
|
||||
// 不再硬编码在这里——新增中断源时不会漏掉这条规则。
|
||||
a.raiseVector(VectorTaskPanic, vectorArgs{Task: t, Panic: r})
|
||||
}
|
||||
|
||||
func (a *Agent) executeTask(t *Task) {
|
||||
|
||||
Reference in New Issue
Block a user