Files
dsh_ai1net_server/交付物/IM插件接入完备性审计-20260925.md
admin c1b5e4d966 chore(工作区): 全量入库 + 补齐 .gitignore(以工作区为准)
- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次)
- .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…),
  目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪
- .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/)
- .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*)
- .gitignore 补:备份件(*.bak-*)
- 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
2026-10-10 23:13:22 +08:00

127 lines
9.1 KiB
Markdown
Raw Permalink 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.
# 交付物 · IM 插件接入完备性审计(2026-09-25)
> **工作区**:`E:/ProgramData/AIProject/aliyun-dsh-server`|**代码基线**:`D:/github/dsh_shenxian`
> **审计口径**:用户两问 —— ① 插件调用**用户自己配置的模型** ② IM 是否还需完善 / 插件如何接入 / 接口接入是否已完善
> **方法**:只读取证(grep 实例化点与调用点),⛔ 不猜
---
> ## ⚠️ 本文已被后续落地**推翻**(2026-09-26 加此状态块,正文保留作过程档案)
>
> **本文写于 2026-09-25,当时结论 = "跨进程那一层不存在 ⇒ 插件今天接不进来"。该结论已作废。**
>
> | 本文当时说 | 现在的实情 | 依据 |
> |---|---|---|
> | §0-2 / §4 G1「扩展点注册无跨进程通路」 | ✅ **已通** —— `/api/im/plugins/register` + SDK `ready()` | 真 HTTP e2e |
> | §4 G2「入向回调是进程内函数调用」 | ✅ **已通** —— **反向通道**:`onSpeakRule()`(同步,带 `onTimeout`)+ `onEvent()`(异步,有界队列) | 2026-09-26 落地 · e2e 28 例 fail 0 · 已部署 47 |
> | §4 G3「出向投递无 HTTP 面」 | ✅ **已通** —— `out/frame` + `out/message` | 同上 |
> | §4 G5「`ImDataPort` 按 pluginId 装配未做」 | ✅ 已做(运行时取数口已落地;⚠️ **代码就绪,尚未部署 47/106 做真机验收**) | `交付物/插件数据面-运行时取数口落地-20260925.md` |
> | §6「建议的桥(待拍板)」 | ✅ 已拍板并**已实现** | 「都需要实现完整,才能让插件接入」 |
>
> 🔴 **权威口径 ⇒ `dsh-server-docs/01-规范/09-IM插件SDK与扩展点契约.md`(现为 §1–§16 完整契约)**;
> 上手指南 ⇒ 其 **§12**;可跑示例 ⇒ `poc/business-plugins-im/minimal-callbacks/`。
> ⛔ 本文**只有历史价值**(记录"当时为什么判断缺一层"),⛔ 不得据其设计。
## §0 判定(三句话)
1. **插件本身没问题**:IM 内核、插件分发、数据面、用户自配模型 —— 这四块**都已完善、可用**。
2. 🔴 **但"接口接入"未完善**:插件跑在**用户实例内**,而 IM 扩展点宿主装配在**平台进程** ⇒ 两者**跨进程**,
而跨进程那一层**不存在**。⇒ 需要服务端逻辑的脚本型插件,**今天接不进来**。
3. **缺的不是能力,是桥**。七点扩展点 + 出向端口的**契约与实现都在**(含 2026-09-25 新增),
缺的是"实例内插件 ↔ 平台 IM 宿主"的协议。
---
## §1 你第 1 点的架构含义(关键)
「插件调用**用户自己配置的模型**」这句话,把插件的位置**钉死在用户实例内**:
```
用户配模型 → credential_vault(route / base_url / api / models)
→ spawn 时写进实例的 $DSH_HOME/settings.yaml + .credentials.yaml
→ ✅ 只有**实例内**能拿到(平台进程拿不到,那是别人的模型)
```
(依据:`src/db/schema.ts:261-278` 的 V6 注释 —— 逐字写明"spawn 时按这四样写"。)
⇒ 🔴 **推论**:插件必须跑在实例内。这也与分发链路一致(`08 §5`:`profile` 写 `link:<共享层路径>`
→ `pnpm` 建链接 → **实例进程加载**)。**插件在实例内、IM 内核在平台** —— 这是本审计全部结论的起点。
## §2 完备性矩阵(面 × 状态)
| 面 | 通路形态 | 状态 |
|---|---|---|
| IM 内核(房间 / 成员 / 消息 / 游标 / presence / 扇出 / 两档传输) | 平台进程 | ✅ 完善 |
| 插件分发(上传 → 检测 → 建库 → 发布 → 实例 `link:` 装配) | 平台侧 | ✅ 完善 |
| **插件数据面**(读写自己的库) | 实例内插件 **HTTP** → 平台 `/api/im/data/*`(带 `x-dsh-im-plugin-id`) | ✅ 完善 |
| **用户自配模型** | `credential_vault` → spawn 写实例配置 | ✅ 完善(官方机制) |
| 客户端 UI 接管(会话内 tab) | 实例前端走官方 slot | ✅ 完善(E 单) |
| 面板清单 / 面板动作端点 | 平台侧 HTTP | ✅ 已加(2026-09-25) |
| 🔴 **扩展点注册**(房间类型 / 载荷 / 角色 / 发言规则 / bot / 事件 / 面板 / 出向) | 实例内插件 → 平台宿主 | ❌ **无通路** |
| 🔴 **入向回调**(`checkSpeak` / `onEvent` / `renderPanel`) | 平台 → 实例内插件 | ❌ **无通路**(现为**进程内函数调用**) |
| 🔴 **出向投递**(`frame` / `message`) | 实例内插件 → 平台 | ❌ **无 HTTP 面** |
| 插件清单来源(谁注册、何时、版本) | — | ❌ 未定 |
| `ImDataPort` 按 pluginId 装配 / `approvedRoomTypes` 来源 | — | ❌ 未做(面板 `reads` 依赖前者) |
## §3 插件类型 × 需求 × 现状(「各种类型能不能接」)
| 插件类型 | 例 | 需要 IM 的什么 | 现状 |
|---|---|---|---|
| **纯数据型** | 统计 / 排行榜 / 审核台账 | 数据面读写 | ✅ **能接** |
| **纯 UI 型** | 只读展示面板 | 客户端 slot + 数据面 | ✅ **能接** |
| **机器人助手型** | 团队记忆 / @bot 汇总 | bot + 事件订阅 + **用户模型** | ⚠️ **一半**:模型 ✅、事件订阅 ❌ |
| **聊天增强型** | 任务卡 / 投票 / 公告 | 载荷 + 面板动作 + 落库发言 | ⚠️ **一半**:载荷 ✅、落库发言 ❌ |
| **回合 / 限速型** | 跑团 / MUD 指令流 | 发言规则 hook | ❌ **接不了**(纯入向回调) |
| **实时协同型** | 协作文档 / 白板 | 出向帧广播 + 大对象分片 | ❌ **接不了**(帧出向无通路) |
| **外部集成型** | Email / CRM 同步 | 外部凭据通路 | ❌ 未立项(对接单 §2-3-3) |
⇒ **分界线很清楚**:**「插件单向发起」的能接,「平台要调插件」的接不了**。
## §4 缺口(按阻塞程度)
| # | 缺口 | 后果 | 归属 |
|---|---|---|---|
| **G1** | **扩展点注册无跨进程通路** —— 插件在实例内,`apply(host)` 拿不到平台 `ImSdkHost` | 房间类型 / 发言规则 / bot / 事件 / 面板**全注册不上** | 平台侧(新面) |
| **G2** | **入向回调是进程内函数调用** —— `rule.contract.check(input)` 跨不了进程 | 回合制 / 限速 / 事件订阅 / 面板渲染**做不了** | 平台侧(新面) |
| **G3** | **出向投递无 HTTP 面** —— `frame` / `message` 只在平台侧端口 | 实时协同 / 插件主动发言**做不了** | 平台侧(新面) |
| G4 | 插件清单来源未定 | 装好了插座没人插 | 投放线 |
| G5 | `ImDataPort` 按 pluginId 装配未做 | 面板 `reads` 取不到数 | 平台侧 |
> 🔴 **对 2026-09-25 上一棒结论的自我修正**:上一棒做的 `createImPluginBinding()` 与出向端口
> 是**平台侧装配**的 —— 它只在「插件与宿主**同进程**」时有效。本审计查实真实部署形态是**跨进程**
> ⇒ **那一层还不够,必须再加一层 HTTP 协议**。契约(扩展点 8 / 面板动作 / 分片)**可原样复用**,
> ⛔ 不推翻;缺的是**传输层**。
## §5 插件接入的完整姿势(现在 / 补桥后)
**现在能做的(无需新平台能力)**:
1. 声明数据面(`package.json#dsh.data.schema`)→ 建库 → 用 HTTP 取数 SDK 读写自己的表。
2. 声明客户端 UI(`lib/client.js`)→ 走官方 slot 接管会话区 → 做面板交互。
3. 调模型:在实例内直接用用户配置的模型(`settings.yaml` 的 provider 已在实例里)。
4. 分发:打包 → admin 上传 → 检测 → 建库 → 发布 → 用户在「功能管理」启用。
**补桥后新增(G1/G2/G3 落地后)**:
5. 启动时向平台**登记**自己声明的扩展点(房间类型 / 发言规则 / bot / 面板 / 出向)。
6. 平台在这些时机**回调实例内插件**:发言前判定 / 事件发生 / 面板渲染。
7. 插件**主动投递**:`frame`(高频广播,不落库)/ `message`(落库发言,以 bot 身份)。
## §6 建议的桥(待拍板)
两条候选,各有优劣(⛔ 我不替拍):
- **甲案 · 登记 + 回调(推荐倾向)**:实例内插件启动时 HTTP 登记 manifest;平台需要回调时,
经**实例既有可寻址通道**调进实例(复用实例已有的 web 面,⛔ 不要求插件自己开端口 —— 那条被
`09 §2-6` 明令禁止)。
优点:与既有纪律不冲突、契约可原样复用、断连可退化(插件不可达 ⇒ 回落自由并发,与现设计同向)。
缺点:要新增"平台 → 实例"的反向调用面(含鉴权与超时),有真实工作量。
- **乙案 · 宿主下沉**:把 IM 的插件宿主从平台搬进每个实例。
优点:同进程、零跨进程复杂度,回调天然同步。
缺点:🔴 房间是**跨用户公共资源**(成员表、消息、presence 都在平台库)⇒ 每个实例各持一份宿主
会**直接造成状态分叉**(同一房间在不同实例里看到不同的发言规则与在线态)—— 我认为**这条不成立**。
## §7 未做 / 边界
⛔ 本件**只做审计**,未改任何代码、未部署、未 commit/push、未动 47/106、未改对接单(别的工作区)。
上一棒的代码落地件见 `交付物/IM插件接入面-20260925.md`(本件是其**续集**,结论更前一层)。