docs(sdk): 补 1.3.0 的新增能力与发版口径;main 路牌推到 1.4.0

用户指出:两个仓库的文档都没跟着更新。本仓的缺口:

1. `README.md` / `README_EN.md` 头部仍写「当前:SDK 1.2.0(需内核 1.2.0+)」,
   版本表停在 1.2.0 —— 1.3.0 的两项新增能力(`InjectOptions.Priority`/`PriorityL1`–`PriorityL4`、
   `UnregisterOutputChannel` 一族)在 README 里**一个字都没有**,而它们正是这一版
   插件作者最需要知道的东西。
2. 发版口径没写清"**SDK 仓不发 patch tag**":核心 1.3.x 的后续 patch 不伴随 SDK 发版,
   patch 位恒为 `.0`(§七.1)。这条以前只在规范里,README 没提,结果我自己在
   2026-09-13 误发了 `v1.3.1`(已撤回);`v1.2.1` 是同一类历史遗留。
3. `meta/meta.go` 的版本语义注释还停在「现为 1.2.0:核心的 1.2.x 线正在发布中」,
   与事实相反。1.3.0 既已随核心正式 tag 定版,该号归发布线所有 ⇒ main 推进到 **1.4.0**。

补写内容:1.3.0 能力小节(四级中断优先级、动态输出通道、通道名约束与那起
`device/<id>` 生产事故)、发版口径两段、版本表补 1.3.0 行、meta 注释与路牌。
This commit is contained in:
JianFeeeee
2026-09-13 14:40:21 +08:00
parent 21221f20c5
commit 63b6eafaf0
3 changed files with 69 additions and 13 deletions

View File

@ -4,7 +4,7 @@ HomeAgent 插件开发 SDK,用于构建与 HomeAgent 平台交互的智能插
## 版本与兼容性 ## 版本与兼容性
当前:**SDK 1.2.0**(需内核 **1.2.0+**)。 当前:**SDK 1.3.0**(需内核 **1.3.0+**)。
**版本号跟随内核的中版本,patch 位恒为 `.0`**: **版本号跟随内核的中版本,patch 位恒为 `.0`**:
@ -12,11 +12,15 @@ HomeAgent 插件开发 SDK,用于构建与 HomeAgent 平台交互的智能插
|---|---| |---|---|
| 1.0.0 / 1.0.1 / … / 1.0.4 | 1.0.0 | | 1.0.0 / 1.0.1 / … / 1.0.4 | 1.0.0 |
| 1.1.0 / 1.1.1 / … / 1.1.N | **1.1.0** | | 1.1.0 / 1.1.1 / … / 1.1.N | **1.1.0** |
| 1.2.0 起 | 1.2.0 | | 1.2.0 / 1.2.1 / … / 1.2.N | **1.2.0** |
| 1.3.0 起 | **1.3.0** |
内核的 patch 位专用于 bugfix 与漏洞修复,不碰公开接口,所以 SDK 版本号不跟着动—— 内核的 patch 位专用于 bugfix 与漏洞修复,不碰公开接口,所以 SDK 版本号不跟着动——
否则你要么被迫跟版、要么怀疑自己版本过时,而接口其实一个字都没变。 否则你要么被迫跟版、要么怀疑自己版本过时,而接口其实一个字都没变。
因此 **SDK 仓在一个中版本里只发一次**(`vX.Y.0`),核心的 `v1.3.1`/`v1.3.2`/… 不伴随 SDK 发版。
(2026-09-13 曾误发过 `v1.3.1`,已撤回 —— patch 位带非零数字的 SDK tag 都是错误的。)
**1.0.x 插件升到 1.1.x:不需要改代码,也不需要重编。** 1.1.0 的新增全部是 **1.0.x 插件升到 1.1.x:不需要改代码,也不需要重编。** 1.1.0 的新增全部是
「插件调用、内核实现」方向,不调就不受影响(已用 SDK 0.9.2 编的旧 `plugin.bin` 「插件调用、内核实现」方向,不调就不受影响(已用 SDK 0.9.2 编的旧 `plugin.bin`
实测验证:在新内核上直接建链通过,因为握手校验的是 `ProtocolVersion`、不是 SDK 版本)。 实测验证:在新内核上直接建链通过,因为握手校验的是 `ProtocolVersion`、不是 SDK 版本)。
@ -28,6 +32,40 @@ HomeAgent 插件开发 SDK,用于构建与 HomeAgent 平台交互的智能插
所以 `plugin.bin` 必须用配套的 `hmapdev` 重编后与内核**同批**安装——否则握手时协议版本 所以 `plugin.bin` 必须用配套的 `hmapdev` 重编后与内核**同批**安装——否则握手时协议版本
不匹配会被拒绝(错误信息会明确提示用配套 hmapdev 重编,不会静默降级)。 不匹配会被拒绝(错误信息会明确提示用配套 hmapdev 重编,不会静默降级)。
## 1.3.0 新增:注入优先级与动态输出通道
### 注入优先级(`InjectOptions.Priority`)
插件可以声明**自己这次注入的中断级别**,内核按四级阶梯调度:
| 级别 | 常量 | 谁用 |
|---|---|---|
| L1–L3 | `PriorityL1` / `PriorityL2` / `PriorityL3` | 插件按紧急程度自选(L1 最低) |
| L4 | `PriorityL4` | **保留给内核与内核级插件**(内核自身事件、内核级通道) |
- 零值(不声明)与旧的注入调用**完全等价**:按排队处理,不抢占任何正在执行的回合
⇒ 存量插件不需要改一行、也不需要重编。
- 高优先级中断可以**抢占**低优先级正在跑的回合;被抢占的回合挂起、之后恢复继续
(现场保存/恢复对插件透明)。
- 排队输入**没有级别**:排队就是排队,任何中断都能插到它前面。
### 动态输出通道(`UnregisterOutputChannel`)
`RegisterOutputChannel` 注册的通道此前只增不减。对**随资源生灭**的通道(典型:远程设备
一台设备一个输出通道),设备掉线后通道还在,模型会继续对一个死通道发消息并以为发成功了。
1.3.0 起成对提供:
| API | 用途 |
|---|---|
| `UnregisterOutputChannel(name)` | 注销输出通道(含能力表与工具) |
| `OutputChannelUnregistrar` / `SetOutputChannelUnregistrar` | 插件侧拿到注销句柄(内核注入) |
⚠️ 通道名要**由插件派生得又合法又唯一**(外部 id 不能直接当通道名)——
设备 id 这类外部输入可能带 `/` 等字符,而通道名会拼进 LLM 函数名 `output_send__<name>`,
违规会让**整条 LLM 请求**被上游拒绝(2026-09-13 生产事故:`device/<id>` 导致全量对话 403)。
派生规则与约束见下方「输出通道」一节。
## 注入行为与上下文裁剪(1.2.0) ## 注入行为与上下文裁剪(1.2.0)
「记不记入记忆」与「要不要据此裁剪上下文」这两件事,原先只有 `ToolDef` 能声明; 「记不记入记忆」与「要不要据此裁剪上下文」这两件事,原先只有 `ToolDef` 能声明;

View File

@ -4,7 +4,7 @@ Plugin development SDK for building intelligent plugins that interact with the H
## Version and Compatibility ## Version and Compatibility
Current: **SDK 1.2.0** (requires kernel **1.2.0+**). Current: **SDK 1.3.0** (requires kernel **1.3.0+**).
**The version tracks the kernel's minor version, with the patch position pinned at `.0`**: **The version tracks the kernel's minor version, with the patch position pinned at `.0`**:
@ -12,13 +12,33 @@ Current: **SDK 1.2.0** (requires kernel **1.2.0+**).
|---|---| |---|---|
| 1.0.0 / 1.0.1 / … / 1.0.4 | 1.0.0 | | 1.0.0 / 1.0.1 / … / 1.0.4 | 1.0.0 |
| 1.1.0 / 1.1.1 / … / 1.1.N | **1.1.0** | | 1.1.0 / 1.1.1 / … / 1.1.N | **1.1.0** |
| 1.2.0 onward | 1.2.0 | | 1.2.0 / 1.2.1 / … / 1.2.N | **1.2.0** |
| 1.3.0 onward | **1.3.0** |
The kernel's patch position is reserved for bugfixes and vulnerability fixes, which never touch the The kernel's patch position is reserved for bugfixes and vulnerability fixes, which never touch the
public interface, so the SDK version has no reason to move with it — otherwise you would either be public interface, so the SDK version has no reason to move with it — otherwise you would either be
forced to chase releases or suspect your version is stale, when not one character of the interface forced to chase releases or suspect your version is stale, when not one character of the interface
has changed. has changed.
The SDK repository therefore publishes **exactly once per minor version** (`vX.Y.0`); kernel patches
such as `v1.3.1` do not trigger an SDK release. (A `v1.3.1` tag was mistakenly cut on 2026-09-13 and
has been withdrawn — any SDK tag with a non-zero patch position is wrong.)
## New in 1.3.0: Injection Priority and Dynamic Output Channels
- **`InjectOptions.Priority` / `PriorityL1`–`PriorityL4`** — a plugin declares the interrupt level of
its own injection; the kernel schedules L1–L4, where **L4 is reserved for the kernel and
kernel-level plugins**. The zero value is fully equivalent to the old three-argument call
(queued, never preempting), so existing plugins need neither a code change nor a rebuild.
Queued input has no level: anything can jump ahead of it.
- **`UnregisterOutputChannel` / `OutputChannelUnregistrar` / `SetOutputChannelUnregistrar`** —
channels that die with their resource (one channel per remote device) can now be unregistered;
previously they lingered and the model kept "successfully" sending into a dead channel.
- **Channel names must be legal and unique.** The name is spliced into the LLM function name
`output_send__<name>`, so it may only contain `[A-Za-z0-9_-]`. A real production incident
(2026-09-13): `device/<id>` made every LLM request fail with 403. Derive channel names from
external IDs — never use the raw ID.
**Upgrading a 1.0.x plugin to 1.1.x: no code changes, no rebuild.** Everything added in 1.1.0 is **Upgrading a 1.0.x plugin to 1.1.x: no code changes, no rebuild.** Everything added in 1.1.0 is
in the "plugin calls, kernel implements" direction, so not calling it means not being affected in the "plugin calls, kernel implements" direction, so not calling it means not being affected
(verified with an old `plugin.bin` built against SDK 0.9.2: it handshakes fine on the new kernel, (verified with an old `plugin.bin` built against SDK 0.9.2: it handshakes fine on the new kernel,

View File

@ -41,16 +41,14 @@ var (
// ❗main 分支上此值是**下一个未发布中版本**;已发布的值看对应的 // ❗main 分支上此值是**下一个未发布中版本**;已发布的值看对应的
// release/vX.Y.x 分支与 tag(见 核心仓 docs/git-branching.md §2.1 与 §七.1)。 // release/vX.Y.x 分支与 tag(见 核心仓 docs/git-branching.md §2.1 与 §七.1)。
// //
// 现为 1.2.0:核心的 1.2.x 线正在发布中(release/v1.2.x 承载 1.2.0), // 现为 1.4.0:1.3.0 已随核心的正式 tag `v1.3.0` 定版并发版(本仓 tag v1.3.0、
// 但 **SDK 不跟 beta 发版**(§七.2)——SDK 1.2.0 的定版与 tag 随核心的 // release/v1.3.x 承载它),该号从此归发布线所有,main 遂推进到下一个未发布中版本。
// **正式** tag 一起做(§七.3)。在那之前 1.2.0 仍是 SDK 尚未发布的中版本,
// 所以 main 就停在 1.2.0。
// //
// 注意:这里与核心 main **故意不对称**。核心一旦切出 release/v1.2.x, // ❗本仓**不发 patch tag**(§七.1):一个中版本只发一次 `vX.Y.0`,核心的 1.3.x
// 1.2.0 就归发布线所有,main 立刻推进到 1.3.0;而 SDK 因为要等正式 tag, // 后续 patch **不伴随 SDK 发版** —— patch 位恒为 `.0`,带非零 patch 的 SDK tag
// 它的 main 在 v1.2.0 打出来之前不得越过 1.2.0。 // 都是错的。(2026-09-13 曾误发 `v1.3.1`,已撤回;`v1.2.1` 是同一类历史遗留。)
// (曾误按 §七.4 把这里推到 1.3.0,等于宣称 1.2.0 已发布。) //
Version = "1.3.0" Version = "1.4.0"
// Commit 是构建时的 Git commit hash。 // Commit 是构建时的 Git commit hash。
Commit = "unknown" Commit = "unknown"