两层,扩展点完全不同——先想清楚要"任何界面都有"还是"内置 Web 界面里的卡片"再动手:
| 层 | 是什么 | 扩展点 |
|---|---|---|
| 通用 UI 层 | 任何界面(终端、自建前端)都能做的渲染 | 监听 session/event 渲染 + agent.followup() 回传输入(L05 见过骨架) |
| Web Client 层 | 内置 Web 界面里的业务组件 | 注册 ConversationNodeDefinition + 键控渲染器 / 设置卡片 |
import type { Context } from '@deepseek-ai/cordis'
import { createUserMessage } from '@deepseek-ai/dsh-llm'
import { SessionId } from '@deepseek-ai/dsh-session'
export const name = 'my-ui'
export const inject = ['agents']
export function apply(ctx: Context) {
// 出:渲染账本事件(模型流式文本 = assistant/chunk 事件流)
ctx.on('session/event', (_session, event) => {
if (event.type === 'assistant/chunk' && event.data.chunk.type === 'text-delta') {
render(event.data.chunk.text) // 你的渲染函数(终端/UI/任何东西)
}
})
// 进:用户输入 → followup 送回收件箱
onUserInput(text => ctx.agents.get(SessionId('client-session'))?.followup(
createUserMessage({ content: [{ type: 'text', text }], source: { kind: 'user' } })
))
}
UI 只是账本的又一个读者(L07 的"一本账处处用"):数据来自事件流,输入走标准收件箱。协议驱动(ACP 等)用同一套机制——UI 和自动化客户端在架构上是同类。
ConversationNodeDefinition 让你在聊天流里插入自己的业务块(图表、审批单、工单卡片、数据预览),配键控渲染器决定样式。
ConversationNodeDefinition + conversation.chat.node 键控渲染器;适用于"对话里该出现一块结构化业务内容"的场景(审批流、监控图、表单)。设置卡片给插件配设置面板——用户在 Settings 页点点点就能改配置,不用打开 YAML。它渲染/编辑的就是 L14 的 Config(schema 驱动表单),配置体验和校验天然一致。
session/event(唯一事实源);自己另存"当前显示什么",迟早和账本打架。docs/cookbook/adding-a-conversation-node.md,抄下注册一个节点需要的三样东西。docs/cookbook/adding-a-settings-card.md,确认设置卡片和 Config schema 的关系。