Files
homeagent-sdk/sdk/kernel.go
JianFeeeee 4387e12ca8 fix(commondev): 投递任务改成真异步,不再同步等 pi 跑完
## 缺陷(用户质疑"投递不就是发一条消息"后实测确认)

`deliverToPi` 的注释写着"把给 pi 发消息包装一下",但实际是:

	await s.prompt(text)   // 同步等 pi 把**整个任务**跑完

而 pi/zcode 开工程线干活(克隆/改代码/跑测试)要几十秒到 20 分钟。
生产日志实测两次:

	23:04:03  executing tool: output_send__commondev_br-...
	23:05:03  ★ timed out after 60s

通道的语义是"**投递**任务"(见 outputch 描述),不是"等完成"。
把它实现成同步等待,就必然撞上内核的 60s 工具超时。

★ 我一开始的诊断是错的:以为"超时值太小",给 output_send 声明了 3m
  —— 那是掩盖症状。投递本该瞬时返回,慢是 bug 不是需求。已撤回。

## 改动

	投递 → 立即回 status=accepted(瞬时)
	     → pi 在后台跑
	     → 跑完推**主动通知**(id=0)
	     → Go 侧 onNotify 经 inputch 注入回 agent

`sidecar.go` 的 readLoop 里早就留好了这个扩展位:
    if resp.ID == 0 { // 主动通知(暂未使用,保留扩展位)
现在接上了 `makePromptNotifier`。

pi 与 zcode 两份 sidecar.mjs 都改了(rawfile/ 里那两份同步更新)。

## 判据抓到我三次(都是真问题)

1. `TestSidecarScriptShipsWithPackage`:rawfile/ 与工程根不一致
   —— 我只改了根那份
2. `TestZcodeMissingCLIErrorIsActionable`:`inflight is not defined`
   —— zcode 版用了未声明变量
3. 同一条判据随后**卡死 2 分钟**:CLI 不存在本该立刻报,异步后错误
   被吞进后台通知 ⇒ 用户先收到"已受理"、几秒后才知道配置错。
   改成**受理阶段就校验 CLI**(配置错是立刻可判定的,不该推迟)。

判据还逼我保住语义:原 `TestZcodeSidecarArgvBehavior` 断言首轮拿到
真实 `sess_` id,异步后要到完成通知里才有 —— 断言保留、改从通知取,
没有削弱。

## 真机 e2e(三条全过,都要求真改工程文件)

	TestZcodeFullPipeline              42.1s
	TestZcodeOverSSH                   72.4s
	TestZcodeOverSSHWithPerHostEndpoints 75.1s

受理现在是瞬时的 ⇒ 内核工具不会再 60s 超时。
2026-10-18 06:39:24 +08:00

37 lines
1.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package sdk
// KernelControlAPI:插件请求**内核本身**重启或关机。
//
// ## 为什么需要它
//
// 有些状态变更只能靠重启内核生效(典型:改了 LLM 源、换了主密钥、
// 升级了要重新装配的配置)。没有这条通道时,用户只能自己去 ssh 上敲
// systemctl —— 而 WebUI 是大多数人唯一会用的界面。
//
// ## 语义边界(重要,别指望它做更多)
//
// 这两个方法都是**异步**的:它们只把请求投递给内核,立刻返回。
// 调用方(WebUI)应当先给用户一个明确回应("正在重启,页面稍后自动重连"),
// 而不是等待返回 —— 内核真的会在这几秒内消失。
//
// 进程会怎么走:
//
// RequestKernelRestart ⇒ 内核清理(停插件、flush、CloseAll)→ exit 42
// → guard 用**当前二进制**重拉,不经过 systemd、
// 不计失败轮次(这就是"热更新"那条路)
// RequestKernelShutdown ⇒ 内核清理 → 通知 guard 主动停机 → systemd 不再拉起
//
// ★ 关机为什么不能用"guard 退出"实现:systemd 是 Restart=always,
// guard 退出会被它无条件重新拉起。必须显式 `systemctl stop`)
//
// ## 失败语义
//
// 返回错误只表示**请求没被接受**(例如内核未装配控制通道、或该功能被禁用),
// 不表示"没重启成功"——成功投递后本进程就会退出,返回值本身没有后续。
type KernelControlAPI interface {
// RequestKernelRestart 请求重启内核(热重启,guard 重拉)。
RequestKernelRestart(reason string) error
// RequestKernelShutdown 请求关闭内核(systemd 不再拉起)。
RequestKernelShutdown(reason string) error
}