feat(sdk): InjectOptions.Priority —— 插件声明自己中断的级别(L1-L3)

内核的输入调度器区分两类别:中断输入(可抢占)与排队输入(可被任何中断打断)。
中断的级别是“这项工作有多不能等”的声明,由插件在注入时给出:

    p.sdk.InjectInterruptTextOpts(src, ch, text, sdk.InjectOptions{
        NoMemory: true,
        Priority: sdk.PriorityL2,   // L1 完全可等 / L2 一般提醒 / L3 需及时
    })

- 新增 `InjectOptions.Priority string` 与 `PriorityL1/L2/L3` 常量(纯追加)。
- 空/非法值一律降级为 L1(默认级)——拼写错误不会被静默当成别的级别。
- **L4 由内核独占**(panic 中断、内核事件中断 selfip),插件声明 L4 会被内核
  夹到 L3,远端常量的取值域里也不提供 L4。
- 排队注入(InjectText*/InjectInputSync*)没有级别:它们本就是“不需及时处理”
  的那一类,可被任何中断打断;传了 Priority 也不会生效。
- 贯通链路:sdk.InjectOptions -> proc RPC 参数(priority)-> 内核 payload;
  tools/hmapdev 模板同步透传(三个注入的 6 个 Opts 变体共用 applyInjectOpts)。
- example/qq 显式声明 L1:QQ 消息既不是时钟那样的实时工作,也不是紧急工作。

兼容性:零值等价于旧行为(L1),既有插件无需改动。
This commit is contained in:
JianFeeeee
2026-09-13 07:00:59 +08:00
parent 4482235312
commit 4f4a03d368
3 changed files with 28 additions and 2 deletions

View File

@ -1435,7 +1435,12 @@ func (p *Plugin) handleWebhook(w http.ResponseWriter, r *http.Request) {
if p.sdk != nil {
// NoMemoryHTTP 侧来的中断提示,不是对话内容。
p.sdk.InjectInterruptTextOpts(p.name, p.name, interrupt, sdk.InjectOptions{NoMemory: true})
// PriorityQQ 消息是**低级别中断**——既不是时钟那样的实时工作,
// 也不是紧急工作,所以声明 L1完全可等
p.sdk.InjectInterruptTextOpts(p.name, p.name, interrupt, sdk.InjectOptions{
NoMemory: true,
Priority: sdk.PriorityL1,
})
}
w.WriteHeader(http.StatusOK)
}
@ -2531,9 +2536,10 @@ func (p *Plugin) handleDownloadFile(args map[string]interface{}) (interface{}, e
log.Printf("[qq] 文件下载完成: %s", savePath)
if p.sdk != nil {
// NoMemory下载完成的状态通知不是记忆内容。
// Priority同上QQ 侧一律低级别中断L1
p.sdk.InjectInterruptTextOpts(p.name, p.name,
fmt.Sprintf("文件下载完成: %s保存在 %s", filepath.Base(savePath), savePath),
sdk.InjectOptions{NoMemory: true})
sdk.InjectOptions{NoMemory: true, Priority: sdk.PriorityL1})
}
} else {
errMsg = "下载失败,文件可能已过期"