# Pi → DSH 架构模型 这是可扩展的 Markdown 知识树,不是接口总表,也不是 `Pi × DSH` 的机械矩阵。每个稳定 标题代表一条架构分支;接口、模块和 seam 是可以继续增长的叶子。 当前盘点快照:**2026-08-20,Pi 0.84.1,DSH 0.1.0-rc.8**。最初从 Pi 声明和运行时 规则中盘到 111 条上游形状规则,从 DSH 官方 subsystem 索引中看到 45 个模块。111 尚未 把所有嵌套对象拆成 callable,45 也不包含以后发现的全部 service、waterfall、event 和 client seam;两个数字都不表示“已经完整”。 ## 生命周期语义模型:两种世界形状(2026-08-22 审计) 一切全局/会话归属判断的理论地基。对照真 Pi 源码钉死(坐标见各条), 不是印象派。 **Pi 是"单活跃会话的进程",运行时没有跨会话全局层。** 三层: 1. **磁盘持久**:auth.json、models.json、models-store.json、trust.json、 settings、session JSONL。跨会话延续只靠这些文件。 2. **会话共享**:ModelRuntime、SettingsManager、ResourceLoader、事件总线 (loader.ts:550 单条 bus 发给该会话全部扩展)、工具注册表、TUI 主题、 按加载顺序串行分发的 ExtensionRunner。每次 `/new`、resume、fork、 `ctx.reload` 都整套重建(agent-session-runtime.ts:226-260 teardown 后 `createRuntime` → agent-session-services.ts:140 连 ModelRuntime 都新建) 并**重跑扩展工厂**(loader 只缓存工厂函数不缓存实例,loader.ts:508 每次 `await factory(api)`)。`session_start` 对一个实例恰好发一次 (agent-session.ts:2258)。 3. **扩展私有**:各扩展自己的 tools/commands/handlers/renderers/flags/ shortcuts 收集器。 **DSH 是"多会话共存的系统"**:llm 目录、凭证、设置、web 服务器是系统级 服务,会话(agent)只是系统里的一种资源。Pi 的"进程启动"与"会话启动" 是同一瞬间;DSH 把这一个瞬间拆成两个(进程可以先于任何会话存在)。 **归属翻译判据**(死规则,按 API 面名字判定,无骑墙面): | Pi 层 | DSH 落点 | | --- | --- | | 磁盘持久 | host 存储 / DSH 官方服务(credentials、settings) | | 会话共享 | **agent 级共享**(同一 agent 的所有包共享一条事件总线、一个主题;不是包私有) | | 扩展私有 | 包 × 会话实例(`agent/created` 驱动,dispose unwind) | | 宿主消费的注册面 | 只有 provider 一族(registerProvider / registerNativeProvider,含 OAuth 定义);沉淀进 host 共享账本,随插件卸载退场而非会话结束退场 | **已拍板(2026-08-22):零会话时刻的世界形状 = 路线 B(锚),维持现状。** 工厂是不透明代码、Pi 无声明清单,宿主想知道插件里有什么只有跑工厂一条路。 候选两条路线: - **路线 A:完整模拟单会话世界 + 产品调整。** 工厂只在会话里跑(次数与 Pi 完全一致),host 账本由第一个会话沉淀。代价:每次进程启动到第一个 会话之间,已安装插件的 provider/登录入口在系统面(模型目录、登录面板、 设置)不可见——TUI 无感(启动即建会话),web 首页可见空窗,且引擎启动 期的存量凭证恢复拿不到包定义的 transport、native 路由要等第一个会话。 产品上需要把"插件能力在会话里才存在"变成 DSH 用户可理解的体验。 - **路线 B(现状实现):锚。** 引擎启动时完整跑一遍工厂承担"启动即加载" 半边:只取 provider 半边、会话半边只记账不挂、永不接收会话事件;每会话 再跑取会话半边、provider 半边进共享账本去重。代价:工厂运行次数 = 会话数 + 1(重跑的副作用与非确定性本是 Pi 契约属性——Pi 每次换会话同样 重跑,清理责任在插件的 session_shutdown;锚唯一新颖处是那次运行永远没有 后续 session_start,遵守契约的插件观察不到)。 - 两条路线都**禁止磁盘影子清单**(持久化上次运行的注册回放):第二份权威 store,插件更新后必然过期。 - 判断依据不是机制数字的整齐,而是产品语义:`dsh plugin add` 是系统级 动作,装完之后零会话时系统面就该看得见它——这是 DSH 语义;路线 A 的 "产品调整"实质是让 DSH 用户理解 Pi 的"会话即世界"哲学,构成用户面 Pi 泄漏(用户面界线铁律)。裁决理由还有两条:① "提前建会话抹空窗" 绕不开死结——首页时刻用户尚未选工作区,插件建出的只能是挂宿主 cwd 的 幽灵会话,即"对插件谎称在会话里"的不诚实版锚,语义污染比多跑一次 工厂严重;② 路线 A 的成立前提是宿主产品形态变化(web 打开即进 工作区,TUI 形状)——命运不在仓外插件手里。若宿主未来真变成该形态, 切换到 A 是纯减法(删锚即可,沉淀账本与会话实例不动)。 - **Pi 本家佐证:Pi 没有零会话状态,"会话之外要知道插件内容"时 Pi 的 官方做法就是造一个幽灵会话。** `pi --list-models` 和 `pi --help` 都 不跳过会话,而是 `SessionManager.inMemory(cwd)` 造一个内存会话 (main.ts:366-368),走完整 createRuntime——工厂全跑、扩展 provider 全注册——再从中取数据(--help 要列出扩展注册的 flags,main.ts:858; --list-models 从该会话的 modelRuntime 列模型,main.ts:866); `--no-session` 的含义是"不落盘",不是"没有会话"。pi-server(web 形态地基,实验包)把无会话的 `listModels` 留作嵌入方接口、仓内无 实现者。锚 = 同一思路在长驻进程上的适配:Pi 的短命进程用完即弃的 内存幽灵会话,在 DSH 长驻进程里变成常驻锚,且锚把"我不是会话"做 诚实了(不发会话事件、会话面只记账)。 相关叶子:[扩展实例作用域](#pi-extension-instance-scope)、 [模型注册](#pi-model-registry)。工作准则里的操作判据见 CLAUDE.md 第三节 (指路,不复写理论)。 ## Pi 能力树 ### 工具与执行 #### 工具注册与可见性 - 当前接口叶子:`registerTool`、`getActiveTools`、`getAllTools`、`setActiveTools`; `unregisterTool` 是桥扩展,不计入上游快照。 - 理论对应:[DSH / 工具、执行与隔离](#dsh-execution)。 - 需要的公开 seam:`ctx.tools` 注册表与按 Agent 控制可见性。 - 理论判断:直接承接。 #### 工具执行边界 - 当前接口叶子:`tool_execution_start`、`tool_execution_end`。 - 理论对应:[DSH / 工具、执行与隔离](#dsh-execution)与 [DSH / 会话与持久化](#dsh-session)。 - 需要的公开 seam:工具执行生命周期与可持久化工具事件。 - 理论判断:组合承接。 #### 工具部分结果更新 - 当前接口叶子:`tool_execution_update`。 - 理论对应:[DSH / 工具、执行与隔离](#dsh-execution)与 [DSH / 会话与持久化](#dsh-session)。 - 需要的公开 seam:对原生与迁移工具都生效的 partial-result 通道。 - 理论判断:尚待确认公开 seam 是否完整。 #### 工具调用与结果策略 - 当前接口叶子:`tool_call`、`tool_result`。 - 理论对应:[DSH / 工具、执行与隔离](#dsh-execution)与 [DSH / 插件组合](#dsh-composition)。 - 需要的公开 seam:执行前参数策略与结果提交前策略。 - 理论判断:组合承接。 #### 进程执行 - 当前接口叶子:`exec`、`user_bash`。 - 理论对应:[DSH / 工具、执行与隔离](#dsh-execution)。 - 需要的公开 seam:`ctx.exec`、subprocess provider。 - 理论判断:直接承接。 非交互 `pi -p` 是额外的 CLI 协议叶子:本地 POSIX subprocess 的临时入口把参数交给 既有 `ctx.agents.create` 子会话桥,模型、工具、权限和会话仍归 DSH。执行器保留原包的 watchdog;超时或连接断开取消原生 child。只选择已经安装的扩展,不在运行时装包。 远端执行 provider 不注入本机 PATH/socket。`--no-session` 的 Pi 文件与索引可抑制, 但 DSH 原生审计仍存在,这一保留语义差异归 `DSH-ARCH-007`,不能声明真正不落盘。 ### 命令与输入 #### 命令注册 - 当前接口叶子:`registerCommand`、`getCommands`。 - 理论对应:[DSH / 命令与人机交互](#dsh-interaction)。 - 需要的公开 seam:`ctx.commands`。 - 当前投影:命令先进入同一个 DSH commands registry;活跃终端公开声明的 native command 拥有原名,Pi 插件撞名时使用 `pi-` 来源前缀,两个普通 Pi 来源撞名时使用编号别名。 pi2dsh 自带的兼容性兜底命令(例如 `/login`)在宿主已有同名命令且消费相同 DSH authorization 权威时不重复注册。所有权在注册前确定,不依赖插件加载顺序。 - `getCommands()` 的文件型 skill 描述符由 `ctx.skills.list/get` 取得:使用实际文件路径, 在会话启动和命令边界刷新,不复制另一个 skill registry。无文件的 opaque skill 不造路径。 - 理论判断:直接承接。 #### Flag 与快捷键 - 当前接口叶子:`registerShortcut`、`registerFlag`、`getFlag`。 - 理论对应:[DSH / 命令与人机交互](#dsh-interaction)与 [DSH / 客户端与 Web](#dsh-client)。 - 需要的公开 seam:命令描述符与客户端输入绑定。 - 理论判断:组合承接。 #### 用户输入预处理 - 当前接口叶子:`input` 事件。 - 理论对应:[DSH / 插件组合](#dsh-composition)与 [DSH / 会话与持久化](#dsh-session)。 - 需要的公开 seam:用户输入成为持久 step 前的 `agent/pre-step`。 - 理论判断:直接承接;当前桥接仍待完成。 ### 消息与 Agent #### 消息注入 - 当前接口叶子:`sendMessage`、`sendUserMessage`。 - 理论对应:[DSH / 会话与持久化](#dsh-session)与 [DSH / 插件组合](#dsh-composition)。 - 需要的公开 seam:`agent/pre-step` 与原生 session message append。 - 理论判断:组合承接。 #### 消息流事件 - 当前接口叶子:`message_start`、`message_update`、`message_end`。 - 理论对应:[DSH / 会话与持久化](#dsh-session)与 [DSH / 模型运行时](#dsh-model-runtime)。 - 需要的公开 seam:LLM stream、提交前与持久化后的消息生命周期。 - 理论判断:组合承接;`message_end` replacement 仍待验证。 #### 模型上下文变换 - 当前接口叶子:`context`。 - 理论对应:[DSH / 会话与持久化](#dsh-session)与 [DSH / 插件组合](#dsh-composition)。 - 需要的公开 seam:权威模型请求发出前的 context projection。 - 理论判断:组合承接。 #### Agent 与轮次生命周期 - 当前接口叶子:`before_agent_start`、`agent_start`、`agent_settled`、`agent_end`、 `turn_start`、`turn_end`。 - 理论对应:[DSH / 插件组合](#dsh-composition)与 [DSH / 会话与持久化](#dsh-session)。 - 需要的公开 seam:Agent waterfalls 与持久 turn/step 事件。 - 理论判断:组合承接。 #### 扩展实例作用域(每会话一份) - 当前接口叶子:`ExtensionFactory` 每 session 实例化一次;`session_start` 异步 handlers 在第一轮前完成;session 结束时实例随之销毁。 - 理论对应:[DSH / 插件组合](#dsh-composition)与 [DSH / Agent 编排](#dsh-orchestration)。 - 需要的公开 seam:`agent/created`(每条发布路径必触发、loop 启动前)、 `agent.ctx`(公开契约:注册 agent-local、dispose 自动 unwind)、 `system-prompt/assemble` 与 `tools/pre-execute` awaited waterfalls (首轮就绪门;`assembly.tools` 在 waterfall 前快照,门内用官方 `tools.schemas(agent)` 补齐)。 - 理论判断:组合承接。Pi 的保证是"第一轮前就绪"而非"发布前就绪", 所以发布后挂载 + awaited 门恰好等价;已在 stock rc.8 npm 包上实证 (tests/agent-scoped-mount.spec.ts + scripts/verify-tui-singlepath-e2e.mjs)。 注:DSH 的发布前组合 seam(`setup(agentCtx)`)是创建者独占参数、root 插件不可达且 config 声明式 Agent 不经过——对生态插件这是真实缺口,正解 形状是 AgentRegistry 级的 serial `agent/setup` contributor(留作上游提案, 非本桥依赖)。 #### Agent 控制与空闲状态 - 当前接口叶子:`isIdle`、`hasPendingMessages`、`waitForIdle`、`abort`、`signal`。 - 理论对应:[DSH / 插件组合](#dsh-composition)与 [DSH / Agent 编排](#dsh-orchestration)。 - 需要的公开 seam:队列、取消信号与 Agent 生命周期。 - 理论判断:组合承接。 #### 上下文用量检查 - 当前接口叶子:`getContextUsage`。 - 理论对应:[DSH / 模型运行时](#dsh-model-runtime)与 [DSH / 会话与持久化](#dsh-session)。 - 需要的公开 seam:token-meter、模型窗口与 session projection。 - 理论判断:组合承接;当前桥接仍待完成。 #### 系统提示词检查 - 当前接口叶子:`getSystemPrompt`、`getSystemPromptOptions`。 - 理论对应:[DSH / 模型运行时](#dsh-model-runtime)。 - 需要的公开 seam:`system-prompt/assemble` 与当前提示词投影。 - 理论判断:组合承接。 ### 会话 #### 自定义持久事实 - 当前接口叶子:`appendEntry`、`setLabel`。 - 理论对应:[DSH / 会话与持久化](#dsh-session)与 [DSH / 客户端与 Web](#dsh-client)。 - 理论需要:namespaced durable session fact,能安全恢复、分支、压缩和回放。 - 当前公开 seam:没有完整入口;仓外插件不能安全注册并追加自定义持久事件。 - 理论判断:缺公开 seam。 #### 会话命名 - 当前接口叶子:`setSessionName`、`getSessionName`。 - 理论对应:[DSH / 会话与持久化](#dsh-session)与 [DSH / 客户端与 Web](#dsh-client)。 - 需要的公开 seam:原生 session title 状态与客户端投影。 - 理论判断:直接承接。 #### 会话生命周期 - 当前接口叶子:`session_start`、`session_shutdown`、`session_info_changed`。 - 理论对应:[DSH / 会话与持久化](#dsh-session)与 [DSH / 插件组合](#dsh-composition)。 - 需要的公开 seam:会话生命周期事实与插件 disposal。 - 理论判断:组合承接。 #### 会话创建、分支与导航操作 - 当前接口叶子:`newSession`、`fork`、`navigateTree`、`switchSession`。 - 理论对应:[DSH / 会话与持久化](#dsh-session)与 [DSH / Agent 编排](#dsh-orchestration)。 - 需要的公开 seam:`ctx.sessions` create/fork/navigation。 - 理论判断:组合承接。 #### 会话导航策略与事件 - 当前接口叶子:`session_before_switch`、`session_before_fork`、 `session_before_tree`、`session_tree`。 - 理论对应:[DSH / 会话与持久化](#dsh-session)与 [DSH / 插件组合](#dsh-composition)。 - 需要的公开 seam:宿主所有入口共用的 session navigation pre/post 生命周期。 - 理论判断:组合承接;宿主 UI 发起的操作仍待桥接验证。 #### 会话压缩操作与结果 - 当前接口叶子:`compact`、`session_compact`。 - 理论对应:[DSH / 会话与持久化](#dsh-session)。 - 需要的公开 seam:compaction operation 与持久完成事件。 - 理论判断:直接承接。 #### 压缩前决策 - 当前接口叶子:`session_before_compact`。 - 理论对应:[DSH / 会话与持久化](#dsh-session)与 [DSH / 插件组合](#dsh-composition)。 - 理论需要:压缩执行前可取消或替换摘要的 waterfall。 - 当前公开 seam:只有压缩发生后的事实事件,没有完整的事前决策入口。 - 理论判断:缺公开 seam。 #### 会话宿主上下文与重载 - 当前接口叶子:`sessionManager`、`cwd`、`mode`、`shutdown`、`reload`。 - 理论对应:[DSH / 会话与持久化](#dsh-session)与 [DSH / 插件组合](#dsh-composition)。 - 需要的公开 seam:session service、workspace scope 与 Cordis reload。 - 理论判断:组合承接。 `getSessionFile()` 的文件消费者需要单独验证,不能拿 `getEntries()` 的实时投影替代。 2026-09-10 的 pi-hermes-memory 消费者证明:只提供身份头不满足文件读取契约。修复后, API 读取使用公开 `snapshotEvents()`(旧代回退 `events`),文件消费者获得原生记录的 完整 Pi 格式导出,历史通过公开 persistence `inspect` / read handle 回填。导出不是 恢复权威,修改它不改变原生历史;但它仍是磁盘 sidecar,按本标准属于 **3 级适配**。 这个文件契约问题是桥欠账,不是 DSH 缺会话数据。 ### 模型 #### Provider 注册 - 当前接口叶子:`createProvider`、`envApiKeyAuth`、各协议的 lazy API factory、 `registerProvider`、`unregisterProvider`、动态 `refreshModels`。 - 理论对应:[DSH / 模型运行时](#dsh-model-runtime)与 [DSH / 插件组合](#dsh-composition)。 - 需要的公开 seam:`llm.registerAdapter`、configurable provider schema、credentials、settings。 - 理论判断:组合承接。带 transport 的 provider 保留自己的协议 factory,经 `llm.registerAdapter` 成为原生路由;首次使用动态目录里尚未出现在启动快照的模型时, 中间层必须等待并合并 provider 的 catalog refresh,再把完整 Pi Model 交给 transport。 只声明目录的 provider 仍翻译给官方 configurable-provider schema,不能借动态刷新之名 偷建第二条传输。 #### Provider OAuth 登录面 - 当前接口叶子:provider 配置的 `oauth.login`(含 device-code、浏览器回调、短链)、 Pi 凭证链的 stored-credential 优先与双检锁刷新。 - 理论对应:[DSH / 模型运行时](#dsh-model-runtime);0.1.1 线新增的官方 `dsh-authorization` 服务(`registerFlow`/`begin`/record 见证/`authorization/settled`)。 - 需要的公开 seam:`ctx.authorization`(0.1.1 线)、`credentials/record-updated`、 credentials record 一族(readRecord/modifyRecord/deleteRecord)。 - 理论判断:组合承接,且按代分支。两代共有的用户入口是引擎的 `/login `(Pi 包 自己的 login 实现跑在中间层的 UI 适配上)。0.1.1 线上每个 OAuth provider 另投影为 官方 authorization flow(key `pi2dsh/`,label 带 "(pi2dsh)"):flow 的 run 与 /login 同一条 spine,凭证仍落中间层 Pi 格式存储,DSH credential record 只作 seam 要求的 commit 见证;官方 `deleteRecord` 通过 `credentials/record-updated` 镜像回 Pi 存储(无 transport 的登录占位路由随之退场)。挂钩用官方 `ctx.inject(['authorization','credentials'], …)` 模式(llm-pi-ai 同款):stock 组合只带包不组合服务、也没有任何 stock 面调用 `begin()`(2026-08-22 对 0.1.1-rc.2 组合 dump 实证:93 项无 authorization),服务何时组合进来都能挂上。 同 id 不同 scope 与官方目录 flow 并存(scope 即命名空间;官方 flow 的凭证只有 llm-pi-ai 路由能消费,我们的 flow 授权的才是中间层实际服务的路由)。 真机证据:`community/authorization-seam-e2e.json`(stock rc2 CLI 双 surface)。 - **0.1.2-alpha.1 分支(2026-08-29)**:官方笔记明写 pi-ai catalog 登录因 ToS 移交 out-of-tree 插件(主动腾位),并为此开出两个新公开 client seam—— `settings.models.provider-card`(keyed slot,entryKey = 行的 settingsNs)与 `settings.models.footer`(list slot)。中间层的登录卡落座于此:引擎侧 `/pi2dsh/login-state` + `/pi2dsh/login-action` 两路由把 `/login` 同一条 spine 暴露为 poll/answer 表面(begin/answer/cancel/dismiss/signout),client 侧 footer 挂全量签入目录、provider-card 键 `llm-pi-ai` 做已登录行原位扩展。 两个真机实证的约束:① **Models 页只渲染 configured 行**(未声明 configurable 的 bridge transport 路由没有行,per-row 卡挂不上——签出态入口必须走 footer); ② `OAuthUiSurface.deviceCode` 的契约是 **resolve 即视为用户取消** (oauthInteraction 在其 then 里 cancel 整个 flow),任何适配器实现必须挂到 flow signal 的 abort 才 resolve——立即 resolve 的写法会把设备码流当场掐死 (契约测试 tests/login-card-routes.spec.ts 抓获,authorization-seam 适配器 存量同款已一并修)。真机证据:`community/seam-evidence/54-logincard-directory.png`、 `55-logincard-device-flow.png`(alpha web + 真 pi-provider-kimi-code 包 + 真 Kimi 设备码端点)。 #### 模型目录视图 - 当前接口叶子:`model`、`scopedModels`、`modelRegistry`、`hasConfiguredAuth`。 - 理论对应:[DSH / 模型运行时](#dsh-model-runtime)。 - 需要的公开 seam:DSH 权威模型目录与凭证可用性。 - 理论判断:直接承接。 #### 目录模型的指定调用 - 当前接口叶子:`modelRegistry.complete`、`modelRegistry.getProvider()`、 `Provider.stream`、`Provider.streamSimple`、`getApiKeyAndHeaders`、 `pi-ai/compat.completeSimple`、`pi-ai/compat.streamSimple`。 - 理论对应:[DSH / 模型运行时](#dsh-model-runtime)与 [DSH / 资源与附件](#dsh-resources)。 - 需要的公开 seam:`llm.stream`、credentials、attachments,以及 Pi 内联图片与 DSH attachment ref 的双向转换。 - 理论判断:组合承接。模型能在目录里被找到,只证明“可发现”;只有指定调用真的带着 文本、图片、凭证和取消信号到达该 route,才证明“可调用”。 #### 模型与推理档位选择 - 当前接口叶子:`setModel`、`getThinkingLevel`、`setThinkingLevel`、`thinkingLevel`、 `model_select`、`thinking_level_select`。 - 理论对应:[DSH / 模型运行时](#dsh-model-runtime)与 [DSH / 客户端与 Web](#dsh-client)。 - 需要的公开 seam:权威模型目录与 request-level reasoning options。 - 理论判断:组合承接。 子代理的创建参数须在子代理自己的 `agent.ctx.on("agent/request", ...)` 公开 waterfall 应用;新版 scope 不把子代理事件送给父作用域。`thinkingLevel=off` 是显式配置, 不能当作缺省值丢弃。原包后台 `pi -p --thinking off` 已通过真实 request/header 验证。 #### Provider 网络请求生命周期 - 当前接口叶子:`before_provider_request`、`before_provider_headers`、 `after_provider_response`。 - 理论对应:[DSH / 模型运行时](#dsh-model-runtime)与 [DSH / 插件组合](#dsh-composition)。 - 理论需要:已有 adapter 最终 request/response 周围的 transport middleware。 - 当前公开 seam:插件拥有整条 transport 时,Pi 标准 stream helper 的 `onPayload` 可把 最终请求体交给 pi2dsh waterfall,再由 DSH `llm.registerAdapter` 承载;增强 DSH 原生 adapter 时没有通用入口。 - 理论判断:分支承接。package-owned transport 的 `before_provider_request` 可做可靠翻译; `before_provider_headers`、`after_provider_response` 以及 DSH-native transport 的同类增强 仍缺公开 seam,不能伪装成已经支持。 ### UI 与宿主呈现 #### 阻塞式用户提问 - 当前接口叶子:`select`、`confirm`、UI `input`、`editor`。 - 理论对应:[DSH / 命令与人机交互](#dsh-interaction)与 [DSH / 客户端与 Web](#dsh-client)。 - 需要的公开 seam:`ctx.userQuestions` 与原生客户端渲染。 - 当前投影:Pi 把终端的一整块多行文案放在 dialog title;DSH 把它拆成纯文本 `question` 与原生 `detail`。pi2dsh 以首行为标题、其余为正文;Web detail 使用 Markdown 链接,dsh-TUI detail 保留 OSC 8,两个 surface 都去掉重复裸 URL,且 不把控制序列显示给用户;`ExtensionUIDialogOptions` 的 `signal`/`timeout` 透传到 DSH 问题撤销语义,所以浏览器自动回调赢得 OAuth 竞速时,TUI 与 Web 都立即撤掉手工粘贴框。 - 理论判断:组合承接。 #### 自定义终端组件 - 当前接口叶子:`custom`(Pi component 的 `render(width)`、`handleInput(raw)`、 `requestRender`、`dispose`、`done(value)`)。 - 理论对应:[DSH / 客户端与 Web](#dsh-client)。 - 当前公开 seam:dsh-TUI `tuiScenes`、dsh-pi-tui `piTuiExtensions` 的 `UNSTABLE_API_LEVEL=1` / `unstable.surface.handle.mountComponent`。 - **web 一律不承接(2026-08-29 用户拍板,"web 零 TUI 投影")**:浏览器只渲染 产品 UI,`ui.custom` 在 web 与 headless 同走 Pi 官方 rpc 降级(resolve undefined),`mode` 在 web 报 'rpc'。旧的 web scene 座位(终端帧投 modal) 已整体删除;scene 会承载的内容由产品面接(side conversation→侧聊浮窗、 MCP 管理→MCP 标签页),逐个核对无缺席消费者。 - 当前投影(终端席):Pi component 留在 Host。中间 relay 只交换可序列化的 `width / lines / input / close`;当前 dsh-pi-tui Direct 模式用 本地 transport 包装该 relay,未来 Server/Client 分离只需替换 transport,不能把 callback 或 component object 跨边界。表面选择按公开 service/capability,不按消费插件名。 - 理论判断:宿主语义翻译;raw input/focus/surface lifecycle 受 dsh-pi-tui Unstable 层级 约束,必须按 capability/API level 探测并在缺失时降级。 #### 通知与工作状态 - 当前接口叶子:`notify`、`setStatus`、`setWidget`、`setWorkingMessage`、 `setWorkingVisible`、`setWorkingIndicator`、`setHiddenThinkingLabel`。 - 理论对应:[DSH / 客户端与 Web](#dsh-client)。 - 需要的公开 seam:client module 与 shell slots。 - 理论判断:组合承接。 #### 宿主框架与工具展开状态 - 当前接口叶子:`setFooter`、`setHeader`、`setTitle`、`getToolsExpanded`、 `setToolsExpanded`。 - 理论对应:[DSH / 客户端与 Web](#dsh-client)。 - 需要的公开 seam:client slot registry 与宿主持有的呈现状态。 - 理论判断:组合承接。 #### 编辑器交互 - 当前接口叶子:`onTerminalInput`、`pasteToEditor`、`setEditorText`、`getEditorText`、 `addAutocompleteProvider`、`setEditorComponent`、`getEditorComponent`。 - 理论对应:[DSH / 客户端与 Web](#dsh-client)与 [DSH / 命令与人机交互](#dsh-interaction)。 - 需要的公开 seam:client editor slots 与 command/input bridge。 - 理论判断:宿主语义翻译。 #### 消息渲染与主题 - 当前接口叶子:`registerMessageRenderer`、`registerEntryRenderer`、 `registerMarkdownTransformer`、`hasUI`、`theme`、`getAllThemes`、`getTheme`、`setTheme`。 - 理论对应:[DSH / 客户端与 Web](#dsh-client)。 - 需要的公开 seam:Web-native client modules 与 slots。 - 理论判断:宿主语义翻译;便携呈现意图与 Pi 终端组件仍需继续拆分。 ### 项目环境与资源 #### 项目信任 - 当前接口叶子:`isProjectTrusted`、`project_trust`。 - 理论对应:[DSH / 插件组合](#dsh-composition)与 [DSH / 工作区资源](#dsh-resources)。 - 理论需要:早于项目资源加载的宿主持有 trust policy。 - 当前公开 seam:普通仓外插件挂载得太晚。 - 理论判断:缺公开 seam。 #### 动态资源发现 - 当前接口叶子:`resources_discover`。 - 理论对应:[DSH / 工作区资源](#dsh-resources)与 [DSH / 插件组合](#dsh-composition)。 - 需要的公开 seam:具有生命周期的 skill/MCP/resource providers。 - 理论判断:组合承接。当前仓库实现已把目录形式的 `skillPaths` 注册为官方 filesystem provider;pi-hermes-memory 的全局/项目 skill 创建后跨进程发现和原生 `skill` 工具加载 已在 `52f7841` 本地构建上通过。npm `pi2dsh@0.24.0` 尚未包含此实现,不能混用结论。 #### 包内事件总线 - 当前接口叶子:`events`。 - 理论对应:[DSH / 插件组合](#dsh-composition)。 - 需要的公开 seam:随插件 fiber 销毁的 package-scoped event bus。 - 理论判断:直接承接。 ### DSH 0.1.5 的同契约承载(2026-09-10) 仍对齐 Pi 0.84.1 的既有契约,不引入 Pi V2,也不新造架构分类。 | 既有能力分支 | 0.1.5 的承载机制与公开 seam | 翻译与权威边界 | |---|---|---| | 模型调用、逐轮系统提示词 | LLM 消息序列中的 system message;一次性调用仍可用 GenerateOptions.system | Pi transport 只得到单个 systemPrompt;桥不声明其未实现的 in-history 能力,由 DSH 决定兼容的系统头表示 | | 会话读取与上下文 | Session.snapshotEvents / eventAt / seq | 读原生事件日志,不缓存另一份会话;旧宿主保留 events 数组/方法路径 | | 消息流 | agent/assistant-stream 的 start/chunk/end;完成态在原生日志 | 按 Agent/attempt 区分增量,重试重置,丢弃重复/过期片段;旧宿主继续消费 assistant/chunk。流式内容仍是已有的部分 Pi 消息投影 | | 子代理创建与生命周期 | setup(agentCtx, agent)、create/resume 的 parentAgent | 创建中的 Agent 显式传递;元数据 parentSession 与实时所有权分别保留,工具和委托策略进入子作用域 | | Agent 队列 | agent.inbox.nextStep / nextTurn | 从公开队列判断 pending;claim 留在驱动器,不复制队列 | | 文件上下文 | attachments.fileHostPath、fs.processPathFromHostPath、llm.fileHandleText | Pi 侧看宿主生成的文件定位文本;未改写的定位文本回译成原文件引用,保留 DSH 的存储、展示和访问判断 | | 工具图片呈现 | tool.call.toolview 的 owner 提供 loadImage | 使用宿主授权加载器取得图片,不释放宿主持有的 URL;旧宿主保留 session.attachment 路径。附件存储与访问控制继续由 DSH 持有 | 浏览器产品通过既有 `browserPresentation` 配置声明自行承载呈现时,`ui.custom` 沿用 Pi RPC 的 `undefined` 返回,避免把已有产品面完成的操作误报为终端组件错误。 仅有原生问答、没有声明产品呈现的 Web 组合仍抛出可捕获的能力错误,供原包执行其 非终端 fallback。侧聊投影遵守 Pi 消息的 `display: false`,隐藏宿主上下文而不删改 模型输入或原生日志;显式可见的自定义消息仍保留。 版本分支由公开能力与回调参数识别,不依赖包名特判或 DSH 内部对象。 用户已明确排除跨版本旧数据迁移;本轮验证新建数据及同版本重启,不实现旧 seq 引用重映射。 ### 当前尚未归类 / 待继续审计 - `sessionManager`、`modelRegistry` 等嵌套对象尚需继续拆 callable; - 动态注册、不同 Pi 版本及插件私下依赖的运行时约定继续按真实消费者补充; - 新发现的能力如果不能合理放入上述分支,先调整树,不强塞进旧分类。 ## DSH 的工作机制,用人话说 DSH 像一块运行中还能换件的 Agent 主板:profile 是装机单,service definition 是插座, provider 是可以替换的零件,agent 是发动机,session log 是飞行记录仪,waterfall 是决定 真正落地前的检查站,client module/slot 是浏览器半边;Cordis fiber/effect 负责依赖、 启停和拆卸清理。 它的核心目的不是把所有能力写死在 Agent 里,而是让模型、工具、存储、执行器、资源、 交互和客户端都能按公开 seam 组合;已经发生的事实进入持久日志,尚未决定的策略通过 provider 或 waterfall 参与。DSH 官方引用的 Cordis 论文 [_A Programming Paradigm for Spatiotemporal Composability_](https://github.com/cordiverse/paper) 解释运行时替换、清理、重绑和回滚;相关的 harness 研究索引 [_Agent Systems with Harness Engineering_](https://github.com/RUCAIBox/awesome-agent-harness) 解释模型之外为什么还需要循环、工具、记忆、workspace、skills、多 Agent、安全和评估。 ## DSH 承载机制树 ### 插件组合与策略 - 当前模块叶子:`core`、`extensions`、`settings`、`scope`、`invariants`、 `permission-presets`。 - 当前公开 seam:Cordis service/provider、`ctx.effect`、`ctx.inject`、waterfall、 scope/isolate/intercept。 - 负责:插件依赖、启停清理、策略组合、配置与权限。引擎拥有的 host 级 service 不能以“发现到社区插件”为生存条件:零个 Pi 包时也要挂 provider 目录、`/login`、 凭证恢复等宿主能力;发现清单只决定包级 extension 是否挂载。 ### 会话与持久化 - 当前模块叶子:`compaction`、`persistence`、`session-projection`、`session-query`、 `session-reference`、`session-telemetry`、`session-title`、`session`、`spill`、`storage`。 - 当前公开 seam:`ctx.sessions`、`Session.append`、durable session events、compaction、 session projection;rc.8 的 LLM 完成包可携带 `ReplayEnvelope`,被取消的部分 assistant 输出可用 `assistant/message.interrupted` 留作持久事实。 - 负责:权威会话事实、恢复、分支、压缩、查询和展示投影。物理存储格式不是逻辑事件 ABI:选择 SQLite persistence 时 rc.8 schema 17 与旧库不兼容,属于 provider 迁移边界, 不改变默认 session log 的理论映射。 ### 模型运行时 - 当前模块叶子:`credentials`、`llm-streaming`、`token-meter`、`system-prompt`。 - 当前公开 seam:`llm.registerAdapter`、`llm/stream`、credentials provider、 `system-prompt/assemble`、`agent/request`;rc.8 的官方 `llm-pi-ai` profile 可声明模型 输入模态、推理档位,以及按协议开放的 provider compat。 - 负责:模型目录、路由、凭证、调用、token 与提示词装配。配置型 Pi provider 应翻译 到官方 profile;只有插件自带 transport 时才注册 adapter。catalog 厂商专属 compat 仍由其已安装目录掌管,不能当通用网关开关透传。 ### 工具、执行与隔离 - 当前模块叶子:`approval`、`code-runtime`、`filesystem`、`sandbox`、`shell`、 `subprocess`、`terminal`、`tools`。 - 当前公开 seam:`ctx.tools`、`ctx.exec`、subprocess provider、sandbox provider、 approval policy。 - 负责:工具目录、执行、权限与隔离;插件直接调用 Node 不自动继承这些能力。 ### 工作区资源 - 当前模块叶子:`attachment`、`skills`、`web`、`workspace`、`lsp`。 - 当前公开 seam:attachment/skill/web/workspace/LSP providers。 - 负责:项目输入、技能、联网资源、工作区与语言服务。 ### Agent 编排 - 当前模块叶子:`goal`、`jobs`、`plan`、`schedule`、`subagent`、`workflow`。 - 当前公开 seam:`ctx.agents`、subagent provider、goal/plan/jobs/workflow providers。 - 负责:Agent 创建、任务分解、计划、后台工作与工作流。 ### 命令与人机交互 - 当前模块叶子:`commands`、`feedback`、`user-questions`。 - 当前公开 seam:`ctx.commands`、`ctx.userQuestions`、feedback provider。rc.8 的命令 执行 ABI 是 `execute(agent, line, images, signal)`;命令可以声明接收图片,handler 从 attachments 读取,而不是把取消信号错当图片数组。 - 负责:文本/图片命令入口、阻塞提问和用户反馈。 ### 客户端、Web 与终端表面 - 当前模块叶子:`client-modules`、`typert`、`web-server`。 - 当前公开 seam:client module、slot registry、web route、typert remote surface、 dsh-TUI `tuiScenes`/`tuiStatus`,以及 dsh-pi-tui 的版本化 `piTuiExtensions` surface; 0.1.2 线新增 `settings.models.provider-card`(keyed)与 `settings.models.footer` (list)两个 Models 页扩展座位(见「Provider OAuth 登录面」的 alpha 分支)。 - 跨代注册姿势:`slots.inject('<座位名>', () => slots.register(...))` 是官方推荐 形状,座位名在该代宿主上从未被声明时回调永不触发——旧代优雅缺席天然成立, 不需要版本探针(直接裸 `register` 未声明座位会 throw,别用)。 - **"台上是谁"不能只信 `current`(2026-08-29)**:0.1.2 线的 New Session 草稿 视图把主栏换成空态但不改 `current`(rc 线会清),按 `current` 键显示的 frame 级浮动件会跨会话残留。诚实信号=会话作用域 conversation 座位的挂载 寿命:中间层在 `conversation.session.header.utilities` 放一枚不可见 stage beacon,浮动件只在"current 且其对话真挂在主栏"时显示(`useOnStage`)。 该草稿行为与宿主 session store 自己的注释("the window opens ⟺ the session is on stage")矛盾,列上游候选报告。 - 负责:浏览器/终端呈现、插件客户端代码和宿主界面扩展。展示层不得另建模型、工具或 session 权威;未来 Server/Client 模式以 data/identity/method/event relay 相连,不传 callback。 `dsh.client.inject` 声明的是客户 端**包依赖**,客户端源码导出的 `inject` 才声明 `slots` 等 Cordis 运行时 service; `dsh.client.external` 只用于动态模块图中的外部包,不能拿 service 名来填。 ### DSH 0.1.5 的同契约承载(2026-09-10) 仍对齐 Pi 0.84.1 的既有契约,不引入 Pi V2,也不新造架构分类。 | 既有能力分支 | 0.1.5 的承载机制与公开 seam | 翻译与权威边界 | |---|---|---| | 模型调用、逐轮系统提示词 | LLM 消息序列中的 system message;一次性调用仍可用 GenerateOptions.system | Pi transport 只得到单个 systemPrompt;桥不声明其未实现的 in-history 能力,由 DSH 决定兼容的系统头表示 | | 会话读取与上下文 | Session.snapshotEvents / eventAt / seq | 读原生事件日志,不缓存另一份会话;旧宿主保留 events 数组/方法路径 | | 消息流 | agent/assistant-stream 的 start/chunk/end;完成态在原生日志 | 按 Agent/attempt 区分增量,重试重置,丢弃重复/过期片段;旧宿主继续消费 assistant/chunk。流式内容仍是已有的部分 Pi 消息投影 | | 子代理创建与生命周期 | setup(agentCtx, agent)、create/resume 的 parentAgent | 创建中的 Agent 显式传递;元数据 parentSession 与实时所有权分别保留,工具和委托策略进入子作用域 | | Agent 队列 | agent.inbox.nextStep / nextTurn | 从公开队列判断 pending;claim 留在驱动器,不复制队列 | | 文件上下文 | attachments.fileHostPath、fs.processPathFromHostPath、llm.fileHandleText | Pi 侧看宿主生成的文件定位文本;未改写的定位文本回译成原文件引用,保留 DSH 的存储、展示和访问判断 | 版本分支由公开能力与回调参数识别,不依赖包名特判或 DSH 内部对象。 用户已明确排除跨版本旧数据迁移;本轮验证新建数据及同版本重启,不实现旧 seq 引用重映射。 ### 当前尚未归类 / 待继续审计 - 后续 DSH 版本加入的 subsystem、service、waterfall、event 和 client slot; - Cordis 卸载、provider replacement、隔离、重绑和失败回滚等生命周期语义; - 只在源码中出现但尚未证明能被仓外插件调用的入口。 ## 怎样继续维护 新增接口或模块时,直接挂到最合适的稳定标题下面;若语义放不进去,调整知识树并说明 原因。理论模型只说“应该由谁承载、需要什么公开 seam”,不在这里声称真实插件已经 跑通;实践证据统一进入 [`plugin-validation-matrix.md`](plugin-validation-matrix.md)。