@qfei-design/make-ai-assistant
v0.2.6
Published
Platform-wide Make AI Assistant contracts, React shell, and context-aware artifact templates.
Downloads
1,934
Keywords
Readme
@qfei-design/make-ai-assistant
面向 Make Console 与所有 Make App 的 AI 助手前端包。它提供统一的右侧居中浮动入口、右侧抽屉、流式会话状态、版本化 Artifact 协议、平台默认结果模板和 App 扩展机制。
Install
pnpm add @qfei-design/make-ai-assistant@^0.2.0Quick start
import { MakeAiAssistant } from "@qfei-design/make-ai-assistant/react";
import "@qfei-design/make-ai-assistant/styles.css";
export function AppAssistant() {
return (
<MakeAiAssistant
brandName="销售管理"
theme={{ primary: "#0f8277" }}
context={{
app: { id: "sales-app", name: "销售管理" },
location: { pathname: window.location.pathname },
locale: "zh-CN",
timezone: "Asia/Shanghai",
}}
transport={assistantTransport}
suggestions={["总结当前页面", "找出需要关注的记录"]}
onAction={(action) => hostActionAdapter.execute(action)}
onActionError={(error, action) => hostActionAdapter.reportFailure(error, action)}
/>
);
}MakeAiAssistant 默认渲染右侧居中的动效入口和右侧抽屉。宿主可以使用 open / onOpenChange
受控管理开关,也可以用 AssistantPanel 嵌入自己的容器;浮动入口位置可通过
--make-ai-launcher-top、--make-ai-launcher-right 和 --make-ai-launcher-mobile-right
覆盖。浮动入口首次打开后,关闭抽屉只隐藏 Drawer,不卸载 AssistantPanel,因此不会中断
正在进行的生成;重新打开时会按用户关闭前的滚动意图恢复消息位置,空闲时聚焦输入框,生成中
聚焦停止按钮。只有点击“停止生成”、新建对话、切换 App/reinitialize 或宿主卸载根组件时才会取消当前请求。
默认会话会显示“AI 助手”身份;用户侧默认不显示名称,宿主传入 userName 或
userAvatarUrl 后才会在用户气泡上方展示当前登录人的名称或头像。宿主可通过 brandName
覆盖默认的 Make 品牌,面板会显示为“{品牌名} AI 助手”;传入 title 时则使用完整标题覆盖。
assistantName 可覆盖 AI 消息显示名称。这些显示配置只用于 React UI,不会随会话上下文发送到
AI transport;进度和可重试错误会显示在对应的 AI 回合中。
subtitle 用于展示宿主传入的当前对象;未传入时回退为当前 App 名称,并兼容移除旧接入中的“只读分析 ·”前缀。宿主传入
privacyNotice 时,面板会在当前对象右侧显示可聚焦的问号图标,鼠标悬浮或键盘聚焦后会根据图标与可用视口选择相邻方向展示该提示;
不传入或传入空白内容时不显示图标。标题右侧紧随标题展示“只读”状态标签,长标题会省略显示并保留原文
title 属性。头栏默认高度为 50px,可通过 headerHeight 属性或 --make-ai-header-height 主题变量覆盖。
Theme integration
MakeAiAssistant、AssistantPanel 和 ArtifactRenderer 都支持同一个 theme 属性。传入宿主主色后,
入口、图标、只读标签、焦点、主操作、进度点、结构化结果、边框、浅色表面、浮层阴影及抽屉拖拽线会从该主色派生,
避免与宿主应用主题割裂;成功、告警和错误仍使用独立语义色。
import type { MakeAiTheme } from "@qfei-design/make-ai-assistant/react";
const hostTheme: MakeAiTheme = {
primary: "#0f8277",
primaryHover: "#09685f",
onPrimary: "#f7fffc",
background: "#f5fbf8",
surface: "#eef8f4",
surfaceStrong: "#dff2eb",
text: "#173f38",
textSecondary: "#3c685f",
border: "#b8d8cf",
overlay: "#123f37",
onOverlay: "#f7fffc",
};
<MakeAiAssistant theme={hostTheme} {...assistantProps} />;primary 为必填项;其余字段可省略并直接由主色派生,因此传入 theme 后不会再混入宿主已有的其他颜色变量。
若主色偏浅,请传入具有足够对比度的
onPrimary。优先级为 theme 属性 > --make-ai-theme-* 变量 > 其他 --make-ai-* 变量 >
宿主 --make-color-* 变量 > 包内默认值。
不使用 React 属性时,也可在组件外层设置 --make-ai-theme-primary、--make-ai-theme-primary-hover、
--make-ai-theme-on-primary、--make-ai-theme-bg、--make-ai-theme-surface、--make-ai-theme-text 和
--make-ai-theme-surface-strong、--make-ai-theme-text-secondary、--make-ai-theme-border、
--make-ai-theme-overlay、--make-ai-theme-on-overlay;这些变量只在 AI 包的命名空间内生效。
平台内置 Artifact 会把主题变量直接写入原有根节点,不增加布局或 DOM 层级;自定义模板如返回自定义组件或
Fragment,可从 renderContext.themeStyle 取到同一组变量并应用到自身根节点。
桌面端抽屉默认宽度为 432px,且该初始宽度是用户拖拽时的最小宽度。最大宽度默认是 min(1024px, 72vw),宿主可通过 maxDrawerWidth 传入像素值覆盖;小于最小宽度的配置会回退至最小宽度。鼠标移至抽屉左边缘的 12px 热区时才会显示 2px 主题色拖拽提示线(可通过 --make-ai-drawer-resize-line 覆盖),可向左拖宽;获得焦点后也可用左、右方向键以 16px 调整宽度。小于 560px 的视口保持全宽展示,不显示拖拽手柄。
面板使用容器查询而非页面视口响应宽度:回答区、结构化结果、代码块和 Markdown 表格会随抽屉可用宽度扩展;达到 760px 时,表格优先按可用宽度分列并换行,长段落和列表仍限制在 96ch 内以保障阅读性。窄容器中的 Markdown 表格保留横向滚动保护,并使用细窄、跟随主题色的滚动条。宿主可通过 --make-ai-panel-gutter-wide 覆盖扩展抽屉的内边距。
成功的 AI 回答会显示仅含图标的复制按钮,鼠标悬浮或键盘聚焦时显示“复制”提示,按钮保留
“复制回答”的无障碍名称;复制只处理该回答的文本内容,失败时会在本地 UI 内提示,不会把回答正文写入日志。AI 回答正文会按标题、
段落、列表、强调、代码片段和 Markdown 表格行做轻量结构化展示,不执行 HTML,也不引入 Markdown
运行时依赖。默认内容字号为 12px,Markdown-like 回答正文默认字号为 11px,宿主可通过
--make-ai-font-size-body 与 --make-ai-font-size-markdown 覆盖。只有当宿主 transport
实现可安全替换旧回答的 regenerate() 时,UI 才显示仅含图标的“重新生成”按钮,悬浮或聚焦时
显示“重新生成”提示,并复用该回答前一条用户问题
替换旧回答,不额外插入重复的用户气泡。用户滚离底部后,面板会显示仅含图标的“回到最新消息”
按钮,避免在阅读历史时强制跳到底部。
run.progress 会累积为可折叠的处理步骤。流式生成中步骤默认展开,完成后默认折叠并保留在
对应 AI 回合下;这些过程文本不进入最终回答正文。单次处理步骤最多 50 条且累计 20,000 字符,
超限会进入可重试错误状态。suggestions 省略时使用包内默认推荐问题,传入自定义数组时使用
宿主内容,传入 [] 时隐藏推荐问题。
默认头部右侧会展示“新建对话”图标按钮;宿主将 transport.features.newConversation 显式设为
false 时隐藏该按钮。点击新建对话会取消当前生成、清空本地会话,并调用可选的
onNewConversation 回调。
Package provides
- Artifact V1 类型、运行时校验与 JSON Schema;
- Artifact 模板注册、能力协商和稳定降级;
- 纯会话 reducer 与
AssistantTransport合同; /sse入口提供可直接配置 endpoint 的createSseAssistantTransport;/make-app入口提供现有 Make App AI 会话、历史消息和 SSE 事件的协议适配器;/make-console入口提供 Console Agent、Session、持久事件和 Run SSE 的协议适配器;MakeAiAssistant、AssistantPanel和ArtifactRenderer;- metric、comparison、trend、ranking、record-list、notice 六类默认模板;
- Mock transport 与 Gallery fixtures;
- 可由宿主覆盖的
--make-ai-*CSS 主题变量。
Host app provides
- 当前 App、路径、Entity/Record/View 等最小上下文;
- 实现
AssistantTransport,或向/make-app、/make-console适配器注入已认证的语义请求和事件订阅能力; - Artifact 动作到宿主路由、命令与权限检查的映射;
- Service
/api、认证、数据查询、模型运行和服务端权限校验; - 可选的 App 领域模板和主题变量。
包自身不导入 Make 认证 SDK、不持有或透传 Make token,也不执行服务端生成的 HTML、JSX、CSS 或 JavaScript。/make-app 与 /make-console 只负责协议归一化,所有网络 I/O 均由宿主注入。
React/ReactDOM 是 UI 入口的可选 peer dependency;只使用根入口、/sse、/make-app、/make-console 或 /testing
的 Service/Node 工具不需要安装 React。
只使用 AssistantPanel 做嵌入式接入,或单独使用 ArtifactRenderer 时,同一个
styles.css 入口仍会提供默认主题变量、盒模型、可见焦点和 reduced-motion 处理。
Artifact template extension
import {
createPlatformArtifactRegistry,
platformArtifactTemplates,
type ReactArtifactTemplate,
} from "@qfei-design/make-ai-assistant/react";
const appTemplate: ReactArtifactTemplate = {
id: "sales.metric.target-progress",
kinds: ["metric"],
priority: 50,
canRender: (artifact, context) =>
context.app.id === "sales-app" && artifact.meta?.semantic === "target-progress",
render: (artifact) => <SalesTargetProgress artifact={artifact} />,
};
const registry = createPlatformArtifactRegistry([
...platformArtifactTemplates,
appTemplate,
]);后端可以通过 presentation.template 请求某个已协商模板;若不匹配,前端会按优先级和 canRender 选择其他安全模板。
模板注册时会校验 kind、priority 和回调类型,并保存只读快照。
Transport
AssistantTransport.run() 接收消息、上下文和前端能力目录,返回 AsyncIterable<AssistantEvent>。
如后端支持“替换已有回答”语义,可额外实现 AssistantTransport.regenerate();UI 只在该能力存在时
显示“重新生成”。Mock、原生 SSE 和 AG-UI 都应适配到同一合同,因此更换后端不会改 UI。
标准 SSE 后端可直接使用:
import { createSseAssistantTransport } from "@qfei-design/make-ai-assistant/sse";
const assistantTransport = createSseAssistantTransport({
endpoint: "/api/assistant/runs",
credentials: "include",
maxEventCharacters: 1_000_000,
});已有 Make App AI Browser API 可使用专用 adapter:
import { createMakeAppAssistantTransport } from "@qfei-design/make-ai-assistant/make-app";
const assistantTransport = createMakeAppAssistantTransport({
locateChat: (context, options) =>
makeAppAiClient.locateChat(context, options),
loadHistory: (request, options) =>
makeAppAiClient.loadHistory(request, options),
sendMessage: (request, options) =>
makeAppAiClient.sendMessage(request, options),
eventSourceFactory: (subscription, init) =>
makeAppAiClient.subscribeResponse(subscription, init),
maxEventCharacters: 1_000_000,
});该 adapter 会按 App 定位持久会话、加载最近历史、提交消息,并把
response.delta/progress/message/completed/failed 归一化为包内事件。当前后端不提供
新建会话与远程取消,因此 UI 会隐藏“新建对话”,停止操作只关闭本地 EventSource。
当前 adapter 也不提供 regenerate(),避免用普通 sendMessage 伪装重新生成后在持久历史中
产生重复用户消息。
具体 URL、认证方式、租户和当前用户解析全部由宿主实现;adapter 不缓存跨调用会话定位结果。
Make App 历史恢复同样受包级预算保护:最多 200 条历史消息、1,000,000 字符历史正文和
500 个历史 Artifact;单个 EventSource data 默认不能超过 1,000,000 字符,超限会在
JSON 解析前被拒绝。
Make Console 可以使用独立 adapter:
import { createMakeConsoleAssistantTransport } from "@qfei-design/make-ai-assistant/make-console";
const assistantTransport = createMakeConsoleAssistantTransport({
listAgents: (request, options) =>
makeConsoleAiClient.listAgents(request, options),
getOrCreateSession: (request, options) =>
makeConsoleAiClient.getOrCreateSession(request, options),
loadEvents: (request, options) =>
makeConsoleAiClient.loadEvents(request, options),
sendMessage: (request, options) =>
makeConsoleAiClient.sendMessage(request, options),
eventSourceFactory: (subscription, init) =>
makeConsoleAiClient.subscribeRun(subscription, init),
});该 adapter 默认选择第一个 status=enabled 的 Agent;多个 Agent 场景可通过 selectAgent
按宿主上下文选择。它会幂等定位当前用户 Session、从持久事件恢复历史、把
output_text.delta 归一化为文本增量,并在 response.completed 后读取持久事件完成最终
对账。收到 fallback 或发送结果没有可订阅 Run 时,会从用户消息 seq + 1 开始轮询持久
事件。Console 输入按后端合同限制为 4000 个 Unicode 字符。当前 Console adapter 不提供
regenerate(),避免用普通 sendMessage 伪装重新生成后在持久历史中产生重复用户消息。
Console 宿主负责把这些语义回调映射到 /api/make/console/v1,并通过现有登录体系使用
credentials: "include" / withCredentials: true。包不会读取、写入或复制 zs_session。
Console BFF 与 Make App Browser API 是两个独立宿主协议,不应只替换 URL 强行复用。
需要兼容已有事件协议时,在宿主内实现薄 adapter;不要修改聊天组件或复制 Artifact 模板。
流必须以 run.complete、run.cancelled 或 error 终止;异常断流会进入可重试错误状态。
停止生成按钮悬浮或键盘聚焦时会显示“停止生成”提示;点击后会立即解除输入锁定并丢弃迟到事件,
标准 SSE transport 会同步取消底层 reader。关闭抽屉只隐藏 UI,不会触发该取消流程。
/sse 的公开类型不依赖 TypeScript DOM lib,现代 Node 宿主也可直接消费。
调用前已经取消的 AbortSignal 不会触发网络请求。
助手只发送宿主提供的上下文,实际数据权限始终由宿主 Service 在服务端重新校验。
生产接口建议和 SSE 事件定义见仓库 docs/backend-contract.md。AG-UI 在这里是可选的前后端事件协议,不是生成 React 组件的 UI 库。
Validation
pnpm test
pnpm typecheck
pnpm build发布统一走 GitLab CI;不要从功能分支本地执行 npm publish。
