medix-agent-sdk
v2.1.1
Published
医疗智能体集成SDK — 基于 postMessage 的 Host/Agent 双端通信解决方案
Maintainers
Readme
MedixAgentSDK
医疗智能体集成 SDK — 基于 postMessage 的 Host/Agent 双端通信解决方案。
将 AI 智能体以 iframe 方式嵌入 HIS、EMR、护理系统等医疗平台,双端通过标准化消息协议完成握手、上下文同步、动作调用、内容读取与 @提及 交互。
目录
特性
- 双端架构 — Host(宿主)与 Agent(智能体)职责分离,通过 postMessage 安全通信
- 提及系统 — 支持
@提及内容、动作、表单等多种类型,带分页与关键词搜索 - 动作执行 — XML 格式动作定义,便于大模型解析与调用
- 上下文管理 — Host 主动推送,Agent 实时获取页面上下文
- 结构化错误 —
SDKError+SDKErrorCode枚举,告别中文字符串判断 - 调试日志 —
debug开关控制,生产环境零噪音 - 类型完备 — 完整 TypeScript 类型定义,IDE 自动补全
- 安全通信 —
agentOrigin配置确保 postMessage 不使用通配符*
安装
npm install medix-agent-sdk业务项目中建议使用范围版本,不要长期写死精确版本。示例:
{
"dependencies": {
"medix-agent-sdk": "^2.1.0"
}
}这样在同一主版本内发布 patch / minor 后,业务项目可直接执行 npm update medix-agent-sdk 升级。
架构概览
┌──────────────────────────────────────────────────────┐
│ 宿主页面(Host) │
│ │
│ HostManager │
│ ├── 创建并管理 iframe │
│ ├── 注册 Action / Content / Mention 处理器 │
│ └── 权限控制(按 Permission 枚举校验每条请求) │
│ │ postMessage(targetOrigin) │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ iframe │ │
│ │ 智能体页面(Agent) │ │
│ │ │ │
│ │ AgentManager │ │
│ │ ├── 握手 & 就绪 │ │
│ │ ├── 获取上下文 │ │
│ │ ├── 调用 Action │ │
│ │ ├── 读取 Content │ │
│ │ └── @ 提及项解析 │ │
│ └──────────────────────┘ │
└──────────────────────────────────────────────────────┘通信流程
- Agent 加载后自动发起
HANDSHAKE - Host 响应并返回权限列表、可用资源
- 双方触发
READY事件,业务逻辑开始执行 - 每条请求携带唯一
id,响应回传同一id完成匹配,默认超时 10 秒
快速开始
Host 端(宿主应用)
import MedixAgentSDK, { Permission, MentionableType, SDKEventType } from 'medix-agent-sdk';
const host = MedixAgentSDK.Host.init({
// ── 必填 ──────────────────────────────────────
agentUrl: 'https://your-agent-app.com',
permissions: [
Permission.READ_CONTENT,
Permission.EXECUTE_ACTIONS,
Permission.ACCESS_CONTEXT,
Permission.EMIT_EVENTS,
Permission.USE_MENTIONS,
],
// ── 安全(生产环境务必填写) ───────────────────
agentOrigin: 'https://your-agent-app.com',
// ── 调试(生产环境设为 false 或不传) ──────────
debug: false,
// ── 容器 ──────────────────────────────────────
containerId: 'agent-container',
// ── 初始上下文 ────────────────────────────────
context: {
patientId: 'P001',
department: '内科',
},
// ── 提及项声明(处理器需单独注册) ───────────
mentions: [
{
id: 'patient-info',
type: MentionableType.CONTENT,
name: '患者信息',
category: '临床数据',
description: '获取当前就诊患者的完整信息',
},
],
// ── 动作声明(处理器需单独注册) ─────────────
actions: [
{
id: 'create-record',
name: 'create_nursing_record',
description: '创建护理记录,记录患者当前状态与护理措施',
xmlDefinition: `
<action>
<name>create_nursing_record</name>
<parameters>
<parameter name="content" type="string" required="true">
<description>记录内容</description>
</parameter>
<parameter name="type" type="string" required="false">
<description>记录类型:观察记录 | 护理措施 | 用药记录</description>
</parameter>
</parameters>
</action>
`,
},
],
// ── iframe 样式 ───────────────────────────────
styles: {
width: '100%',
height: '600px',
borderRadius: '8px',
boxShadow: '0 2px 12px rgba(0,0,0,0.1)',
},
});
// 注册提及项解析器
host.onMentionResolved('patient-info', async (mentionData) => {
return await patientService.getFullInfo(mentionData.metadata?.patientId);
});
// 注册动作处理器
host.registerAction('create-record', async (params) => {
const result = await nursingService.createRecord(params);
return { success: true, recordId: result.id };
});
// 注册内容处理器
host.registerContent('lab-report', async (params) => {
return await labService.getReport(params.reportId);
});
// 监听 SDK 就绪
host.addEventListener(SDKEventType.READY, () => {
console.log('Agent 已就绪');
});
// 监听 Agent 自定义事件
host.onAgentEvent('diagnosis-submitted', (data) => {
console.log('诊断已提交:', data);
});
// 患者切换时更新上下文
function onPatientChange(patient) {
host.updateContext({ patientId: patient.id, patientName: patient.name });
}Agent 端(智能体应用)
import MedixAgentSDK, { SDKEventType, SDKError, SDKErrorCode } from 'medix-agent-sdk';
const agent = MedixAgentSDK.Agent.init({
autoConnect: true,
debug: false,
});
// 等待握手完成(建议所有业务逻辑在此之后执行)
await agent.waitForReady();
// 获取宿主注入的上下文
const context = await agent.getContext();
console.log('当前患者:', context.patientId);
// 读取宿主注册的内容
const report = await agent.getContent('lab-report', { reportId: 'R001' });
// 获取 @ 提及项列表(支持筛选)
const mentions = await agent.getMentions({ category: '临床数据' });
// 解析用户选择的提及项
const patientData = await agent.resolveMention({
id: 'patient-info',
name: '患者信息',
type: 'content',
// position 为可选字段,非输入框场景可不传
});
// 一次性获取所有动作定义(单次请求,无性能问题)
const actions = await agent.getActions();
// 执行动作
const result = await agent.executeAction('create-record', {
content: '患者体温 37.2°C,精神状态良好',
type: '观察记录',
});
// 监听宿主直接发送的消息
agent.onMessage(({ message, metadata }) => {
console.log('收到宿主消息:', message);
});
// 监听宿主插入输入框的内容
agent.onInsertMessage(({ message }) => {
insertIntoInputBox(message);
});
// 监听宿主自定义事件
agent.onHostEvent('patient-changed', (data) => {
console.log('患者已切换:', data);
});调试模式
SDK 默认静默,生产环境控制台零输出。开发时有两种开启方式:
方式一:初始化时配置(推荐)
// Host 端
MedixAgentSDK.Host.init({ debug: true, ... });
// Agent 端
MedixAgentSDK.Agent.init({ debug: true, ... });方式二:运行时动态开关
import { enableDebug, disableDebug } from 'medix-agent-sdk';
enableDebug(); // 开启
disableDebug(); // 关闭
warn和error级别的日志无论是否开启 debug 都会输出,不会被静默。
错误处理
所有异步方法均通过 Promise 抛出结构化的 SDKError,通过 error.code 精准判断:
import { SDKError, SDKErrorCode } from 'medix-agent-sdk';
try {
const result = await agent.executeAction('create-record', params);
} catch (error) {
if (error instanceof SDKError) {
switch (error.code) {
case SDKErrorCode.UNAUTHORIZED:
console.error('权限不足,请检查 Host 初始化时的 permissions 配置');
break;
case SDKErrorCode.NOT_FOUND:
console.error('动作不存在,请检查 actionId 是否已在 Host 端注册');
break;
case SDKErrorCode.REQUEST_TIMEOUT:
console.error('请求超时,Handler 执行时间过长');
break;
case SDKErrorCode.NOT_READY:
console.error('SDK 尚未就绪,请先 await waitForReady()');
break;
default:
console.error('未知错误:', error.message, error.details);
}
}
}SDKErrorCode 速查
| 错误码 | 说明 |
|---|---|
| UNAUTHORIZED | 权限不足(对应 HTTP 401) |
| NOT_FOUND | Action / Content / Mention 不存在(404) |
| INVALID_REQUEST | 请求参数格式错误(400) |
| INTERNAL_ERROR | Handler 内部执行异常(500) |
| REQUEST_TIMEOUT | 请求超时(默认 10s) |
| NOT_READY | waitForReady 超时(默认 15s) |
| SDK_DESTROYED | 实例已销毁,pending 请求被取消 |
| NOT_INITIALIZED | SDK 未初始化 |
配置项参考
HostConfig
interface HostConfig {
// ── 必填 ──────────────────────────────────────────────
agentUrl: string; // 智能体页面 URL
permissions: Permission[]; // 授予智能体的权限列表
// ── 安全(生产环境必填) ───────────────────────────────
agentOrigin?: string; // Agent 页面的 origin,不填则使用 '*' 并打警告
// 示例:'https://agent.your-domain.com'
// ── 调试 ──────────────────────────────────────────────
debug?: boolean; // 是否开启调试日志,默认 false
// ── 容器 ──────────────────────────────────────────────
containerId?: string; // 挂载容器的 DOM id,不填则自动生成
autoCreate?: boolean; // 是否自动创建 iframe,默认 true
// ── 数据预声明(处理器需单独注册) ────────────────────
context?: any;
contents?: ContentDefinition[];
actions?: ActionDefinition[];
mentions?: Mentionable[];
// ── iframe 样式 ────────────────────────────────────────
styles?: {
width?: string; height?: string; border?: string;
borderRadius?: string; boxShadow?: string; zIndex?: string;
position?: 'fixed' | 'relative' | 'absolute';
top?: string; right?: string; bottom?: string; left?: string;
};
// ── 回调(向后兼容) ───────────────────────────────────
onReady?: () => void;
onError?: (error: any) => void;
}AgentConfig
interface AgentConfig {
autoConnect?: boolean; // 是否自动发起握手,默认 true
debug?: boolean; // 是否开启调试日志,默认 false
// ── 回调(向后兼容) ───────────────────────────────────
onReady?: () => void;
onError?: (error: any) => void;
}⚠️ 注意:旧版
AgentConfig中的registerContents / registerActions / registerMentions已在 v2.1.0 中移除。如需在全局缓存中注册,请直接调用SDKManager.register*()方法。
API 参考
Host SDK
| 方法 | 说明 |
|---|---|
| Host.init(config) | 初始化并返回 HostManager 实例 |
| host.updateContext(data) | 更新上下文并推送给 Agent |
| host.registerContent(id, handler) | 注册内容处理器 |
| host.registerAction(id, handler) | 注册动作处理器 |
| host.registerMention(mention, resolver) | 注册单个提及项及其解析器 |
| host.registerMentions(mentions, resolvers) | 批量注册提及项 |
| host.onMentionResolved(id, resolver) | 仅注册解析器(提及项不存在时自动创建) |
| host.removeMention(id) | 移除提及项 |
| host.registerActionDefinition(def) | 注册动作 XML 定义 |
| host.registerActionDefinitions(defs) | 批量注册动作 XML 定义 |
| host.registerPlugin(name, plugin) | 注册插件 |
| host.sendMessageToAgent(msg, meta?) | 直接发送消息给 Agent |
| host.insertMessageToAgent(msg, meta?) | 插入消息到 Agent 输入框 |
| host.emitToAgent(eventName, data) | 向 Agent 发送自定义事件 |
| host.onAgentEvent(eventName, cb) | 监听 Agent 发来的自定义事件 |
| host.addEventListener(event, handler) | 监听 SDK 内置事件 |
| host.show() | 显示 iframe 容器 |
| host.hide() | 隐藏 iframe 容器 |
| host.destroy() | 销毁实例,移除 DOM,清理监听器 |
Agent SDK
| 方法 | 说明 |
|---|---|
| Agent.init(config) | 初始化并返回 AgentManager 实例 |
| agent.waitForReady(timeout?) | 等待握手完成,默认超时 15s |
| agent.connect() | 手动发起握手(autoConnect: false 时使用) |
| agent.getContext() | 获取宿主注入的上下文 |
| agent.getContent(id, params?) | 读取宿主注册的内容 |
| agent.executeAction(id, params) | 调用宿主注册的动作 |
| agent.getMentions(query?) | 获取提及项列表(支持筛选与分页) |
| agent.resolveMention(mentionData) | 解析提及项获取具体数据 |
| agent.getActions() | 一次性获取所有动作定义(单次请求) |
| agent.onMessage(cb) | 监听宿主直接发送的消息 |
| agent.onInsertMessage(cb) | 监听宿主插入输入框的消息 |
| agent.onHostEvent(eventName, cb) | 监听宿主自定义事件 |
| agent.addEventListener(event, handler) | 监听 SDK 内置事件 |
| agent.destroy() | 销毁实例,清理所有处理器 |
提及系统
提及项类型
enum MentionableType {
CONTENT = 'content', // 内容型:患者信息、检查结果、病历等
ACTION = 'action', // 动作型:查询、下单、创建记录等
FORM = 'form', // 表单型:问诊表单、康复计划等
CUSTOM = 'custom', // 自定义类型
}注册与解析
// Host 端注册
host.registerMention(
{
id: 'diagnosis-result',
type: MentionableType.CONTENT,
name: '诊断结果',
category: '临床数据',
description: '获取当前患者的最新诊断结果',
},
async (mentionData) => {
return await clinicService.getDiagnosis(mentionData.metadata?.patientId);
}
);
// Agent 端使用
const mentions = await agent.getMentions({
query: '诊断', // 关键词搜索
category: '临床数据', // 按分类筛选
type: 'content', // 按类型筛选
limit: 20, // 分页大小
offset: 0, // 偏移量
});
// 用户选择提及项后解析
const result = await agent.resolveMention({
id: 'diagnosis-result',
name: '诊断结果',
type: MentionableType.CONTENT,
// position 为可选,输入框场景传实际位置,其他场景可省略
position: { start: 5, end: 10 },
});动作系统
XML 格式定义
// Host 端注册动作定义(供 Agent 端 getActions() 获取)
host.registerActionDefinition({
id: 'create-record',
name: 'create_nursing_record',
description: '创建护理记录,记录患者当前状态与护理措施',
displayName: '创建护理记录',
category: '护理操作',
xmlDefinition: `
<action>
<name>create_nursing_record</name>
<description>创建护理记录</description>
<parameters>
<parameter name="content" type="string" required="true">
<description>记录内容</description>
</parameter>
<parameter name="type" type="string" required="false">
<description>记录类型</description>
<options>
<option>观察记录</option>
<option>护理措施</option>
<option>用药记录</option>
</options>
</parameter>
</parameters>
</action>
`,
});
// Host 端注册执行处理器
host.registerAction('create-record', async (params) => {
const { content, type } = params;
const record = await nursingService.create({ content, type });
return { success: true, recordId: record.id };
});
// Agent 端获取所有动作(一次请求)
const actions = await agent.getActions();
// Agent 端执行动作
const result = await agent.executeAction('create-record', {
content: '患者体温 37.2°C,精神状态良好',
type: '观察记录',
});权限管理
Host 初始化时声明权限,Agent 的每条请求都会在 Host 侧校验,未授权返回 UNAUTHORIZED 错误。
import { Permission } from 'medix-agent-sdk';
MedixAgentSDK.Host.init({
permissions: [
Permission.READ_CONTENT, // 允许 Agent 读取内容(getContent)
Permission.EXECUTE_ACTIONS, // 允许 Agent 执行动作(executeAction / getActions)
Permission.ACCESS_CONTEXT, // 允许 Agent 访问上下文(getContext)
Permission.EMIT_EVENTS, // 允许 Agent 向 Host 发送自定义事件
Permission.USE_MENTIONS, // 允许 Agent 使用 @ 提及功能
],
...
});Vue 集成示例
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import MedixAgentSDK, { SDKEventType, type Mentionable } from 'medix-agent-sdk';
const isReady = ref(false);
const mentions = ref<Mentionable[]>([]);
let agent: ReturnType<typeof MedixAgentSDK.Agent.init>;
onMounted(async () => {
agent = MedixAgentSDK.Agent.init({ autoConnect: true, debug: false });
await agent.waitForReady();
isReady.value = true;
mentions.value = await agent.getMentions();
agent.onInsertMessage(({ message }) => {
insertTextAtCursor(message);
});
agent.addEventListener(SDKEventType.CONTEXT_UPDATED, (ctx) => {
console.log('上下文已更新:', ctx);
});
});
onUnmounted(() => {
agent?.destroy();
});
</script>React 集成示例
import { useEffect, useRef, useState } from 'react';
import MedixAgentSDK, { SDKEventType, type Mentionable } from 'medix-agent-sdk';
export function AgentPanel() {
const hostRef = useRef<ReturnType<typeof MedixAgentSDK.Host.init> | null>(null);
const [agentReady, setAgentReady] = useState(false);
useEffect(() => {
hostRef.current = MedixAgentSDK.Host.init({
agentUrl: 'https://your-agent-app.com',
agentOrigin: 'https://your-agent-app.com',
containerId: 'agent-panel',
permissions: [/* ... */],
debug: process.env.NODE_ENV === 'development',
});
hostRef.current.addEventListener(SDKEventType.READY, () => {
setAgentReady(true);
});
hostRef.current.registerAction('create-record', async (params) => {
return await nursingService.create(params);
});
return () => {
hostRef.current?.destroy();
};
}, []);
return (
<div>
{agentReady && <span>Agent 已就绪</span>}
<div id="agent-panel" style={{ height: 600 }} />
</div>
);
}开发指南
环境要求
- Node.js >= 16
- TypeScript >= 5.0
- 现代浏览器(支持 postMessage API)
本地开发
# 克隆项目
git clone https://github.com/your-org/medix-agent-sdk.git
cd medix-agent-sdk
# 安装依赖
npm install
# 开发模式(监听文件变化,自动重新构建)
npm run dev
# 类型检查
npm run typecheck
# 构建生产产物
npm run build发布到 npm
SDK 修改后发布步骤
1. 完成代码修改
- 完成 SDK 功能、类型或构建相关修改
- 如果对外 API、接入方式、示例代码有变化,同步更新
README.md - 如果有版本变更说明,同步更新
CHANGELOG.md
2. 安装依赖并登录 npm
npm install
npm login3. 发布前校验
npm run typecheck
npm run clean
npm run build
npm pack --dry-run4. 执行发布命令
# patch:修复问题、兼容性调整
bash publish.sh patch
# minor:新增向后兼容功能
bash publish.sh minor
# major:存在破坏性变更
bash publish.sh major5. Windows 环境执行说明
- 如果本机安装了 Git Bash,优先在 Git Bash 中执行
bash publish.sh patch - 如果使用的是 PowerShell 且不能直接跑
bash publish.sh,可以手动按下面步骤执行
# 以 patch 发布为例
npm version patch --no-git-tag-version
npm run typecheck
npm run clean
npm run build
npm pack --dry-run
npm publish --access public6. 业务项目升级 SDK
# 安装最新版本
npm install medix-agent-sdk@latest
# 或更新到当前 package.json 范围内允许的最新版本
npm update medix-agent-sdk如果业务项目依赖写成
"medix-agent-sdk": "^2.1.0",通常执行npm update medix-agent-sdk即可。
一键发布命令
# 发 patch 版本(默认):2.1.0 → 2.1.1
bash publish.sh
# 发 minor 版本:2.1.0 → 2.2.0
bash publish.sh minor
# 发 major 版本:2.1.0 → 3.0.0
bash publish.sh major
# 演习模式(不实际发布,仅预览流程)
bash publish.sh --dry-run脚本会自动完成:环境检查 → Git 状态校验 → 类型检查 → 构建 → 版本升级 → 发布 → Git Tag。
更新日志
详细变更记录见 CHANGELOG.md。
v2.1.0 主要变更
新增
HostConfig.agentOrigin— postMessage 安全目标 origin,生产环境必填HostConfig.debug/AgentConfig.debug— 日志开关,默认 falseenableDebug()/disableDebug()— 运行时动态切换日志SDKError+SDKErrorCode— 结构化错误,替代裸字符串agent.getActions()改用批量接口,从 N 次串行请求降为 1 次MessageType.GET_ACTION_DEFINITIONS— 新增批量获取动作定义协议
修复
- Host + Agent 同页时消息被重复处理的 Bug
plugin.initialize()未传sdk实例参数destroy()时未拒绝 pending 请求导致的内存泄漏
破坏性变更
AgentConfig移除registerContents / registerActions / registerMentions(原本无效)MentionData.position改为可选字段- 错误判断需改用
error instanceof SDKError && error.code === SDKErrorCode.xxx
许可证
ISC License © your-org
