@qx-wz/agent-embed-sdk
v0.4.1
Published
Agent Hub Web 嵌入 SDK(无头)— 基于 @ag-ui/client 封装的 /agui/run 通信层
Readme
@qxwz/agent-embed-sdk
Agent Hub Web 嵌入 SDK(无头)— 基于 @ag-ui/client 封装 /agui/web/send 端点。
公司内网使用。提供两种接入方式:
<script>标签 + npm 模块;只负责通信,不带 UI。 核心 API 继承自@ag-ui/client的HttpAgent,完整支持 AG-UI 协议的消息管理、事件订阅、中断运行等能力。
一、能力概览
- 标准 AG-UI 协议:继承
@ag-ui/client的HttpAgent,完整 SSE 事件解析 - 渠道注入:自动把
channelId/embedCode/pageContext/sessionId注入 POST 请求体 - 认证注入:同域 SSO Cookie(
credentials: 'include')/ 跨域buc-auth-tokenHeader - 页面上下文:
pageContext透传到后端 P0.5 RuntimeLayer,支持模板替换 - 双产物:UMD(
<script>即用,含 rxjs+zod 自包含)+ ESM/CJS(npm 引入,@ag-ui/client 为 peer dep) - 自动初始化:UMD 模式下通过
data-*属性零代码接入 - 完整类型:TypeScript 类型定义 + 重新导出 @ag-ui/core 事件类型
二、安装
方式 A:npm 模块(推荐)
pnpm add @qxwz/agent-embed-sdk
@ag-ui/client和@ag-ui/core作为依赖自动安装。
import { AgentEmbedClient } from '@qxwz/agent-embed-sdk';
const client = new AgentEmbedClient({
baseUrl: 'https://agent-hub.intra.example.com',
channelId: 1,
embedCode: 'oa-pending',
});方式 B:<script> 标签(无需构建工具)
<script src="https://your-cdn/agent-embed.umd.js"
data-agent-embed
data-base-url="https://agent-hub.intra.example.com"
data-channel-id="1"
data-embed-code="oa-pending"
data-debug="true"></script>加载完成后:
window.AgentEmbed.AgentEmbedClient— 客户端类window.AgentEmbed.instance— 用data-*配置自动创建的默认实例agent-embed:ready事件 — 实例就绪通知
三、配置项
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| baseUrl | string | ✅ | 后端地址,例如 https://agent-hub.intra.example.com |
| channelId | number | ✅ | 渠道 ID(数据库 agt_channel.id) |
| embedCode | string | ✅ | 嵌入码(数据库 agt_channel_binding.source_id) |
| authToken | string | 否 | 跨域用 buc-auth-token;同域走 SSO Cookie 可省略 |
| aguiPathPrefix | string | 否 | AG-UI 端点前缀,默认 /api/agent-hub/agui |
| debug | boolean | 否 | 打开调试日志 |
<script> 方式对应 data-* 属性:data-base-url / data-channel-id / data-embed-code / data-auth-token / data-agui-path-prefix / data-debug。
四、API
继承自 @ag-ui/client 的标准 API
AgentEmbedClient 继承 HttpAgent → AbstractAgent,完整支持:
| 方法/属性 | 说明 |
|-----------|------|
| client.messages | 当前消息列表(含 user + assistant) |
| client.threadId | 当前线程 ID |
| client.isRunning | 是否正在运行 |
| client.addMessage(msg) | 添加消息到列表 |
| client.runAgent(params?, subscriber?) | 运行 Agent,返回 Promise<RunAgentResult> |
| client.subscribe(subscriber) | 订阅事件回调,返回 { unsubscribe } |
| client.abortRun() | 中断当前运行 |
| client.use(...middlewares) | 添加中间件 |
SDK 扩展 API
| 方法 | 说明 |
|------|------|
| client.setPageContext(ctx) | 设置默认页面上下文 |
| client.chat(content, pageContext?) | 便捷方法:添加用户消息 + 运行 Agent |
| init(config) | 模块级便捷工厂函数 |
subscribe 回调(AgentSubscriber)
client.subscribe({
onRunStartedEvent: ({ event }) => { /* RUN_STARTED */ },
onTextMessageStartEvent: ({ event }) => { /* TEXT_MESSAGE_START */ },
onTextMessageContentEvent: ({ event, textMessageBuffer }) => {
// event.delta = 文本增量
// textMessageBuffer = 当前消息已累积的完整文本
},
onTextMessageEndEvent: ({ event, textMessageBuffer }) => {
// textMessageBuffer = 本条消息的完整文本
},
onToolCallStartEvent: ({ event }) => { /* TOOL_CALL_START */ },
onToolCallArgsEvent: ({ event, toolCallName, toolCallBuffer }) => {
// event.args = 工具参数增量
},
onToolCallEndEvent: ({ event, toolCallName, toolCallArgs }) => {
// toolCallArgs = 完整参数对象
},
onRunFinishedEvent: ({ event }) => { /* RUN_FINISHED */ },
onRunErrorEvent: ({ event }) => {
// event.message / event.code
},
onMessagesChanged: ({ messages }) => {
// 消息列表变化时触发
},
});五、完整示例
5.1 npm 模块 — chat() 便捷方法
import { AgentEmbedClient } from '@qxwz/agent-embed-sdk';
const client = new AgentEmbedClient({
baseUrl: 'https://agent-hub.intra.example.com',
channelId: 1,
embedCode: 'oa-pending',
debug: true,
});
// 设置默认页面上下文
client.setPageContext({
pageUrl: location.pathname,
module: 'oa',
objectIds: ['user-123'],
});
// 一行发送 + 运行
const newMessages = await client.chat('帮我查一下今天的待办');
console.log('助手回复:', newMessages);5.2 npm 模块 — subscribe 流式回调
import { AgentEmbedClient } from '@qxwz/agent-embed-sdk';
const client = new AgentEmbedClient({
baseUrl: 'https://agent-hub.intra.example.com',
channelId: 1,
embedCode: 'oa-pending',
});
// 订阅流式事件
client.subscribe({
onTextMessageContentEvent: ({ event, textMessageBuffer }) => {
process.stdout.write(event.delta); // 流式输出
},
onToolCallEndEvent: ({ toolCallName, toolCallArgs }) => {
console.log('工具调用:', toolCallName, toolCallArgs);
},
onRunFinishedEvent: ({ event }) => {
console.log('运行结束', event.threadId, event.runId);
},
onRunErrorEvent: ({ event }) => {
if (event.code === 'UNAUTHORIZED') location.href = '/login';
else console.error('运行错误:', event.message);
},
});
// 添加消息并运行
client.addMessage({ id: 'msg-1', role: 'user', content: '你好' });
await client.runAgent();
console.log('完整消息列表:', client.messages);5.3 npm 模块 — 带 pageContext 的运行
// 单次运行传入 pageContext(覆盖默认值)
const result = await client.runAgent({
forwardedProps: {
pageContext: {
pageUrl: '/srm/contract/detail',
module: 'srm',
objectIds: ['contract-456'],
},
},
});5.4 <script> 自动初始化
<!DOCTYPE html>
<html>
<head>
<script src="/static/agent-embed.umd.js"
data-agent-embed
data-base-url="https://agent-hub.intra.example.com"
data-channel-id="1"
data-embed-code="oa-pending"></script>
</head>
<body>
<button id="ask">问我</button>
<pre id="out"></pre>
<script>
window.addEventListener('agent-embed:ready', ({ detail }) => {
const client = detail.client;
// 订阅流式文本
client.subscribe({
onTextMessageContentEvent: ({ event }) => {
document.getElementById('out').textContent += event.delta;
},
onRunErrorEvent: ({ event }) => {
alert('出错: ' + event.message);
},
});
document.getElementById('ask').onclick = async () => {
document.getElementById('out').textContent = '';
client.addMessage({ id: 'msg-' + Date.now(), role: 'user', content: '帮我看下今天的代办' });
await client.runAgent();
};
});
</script>
</body>
</html>5.5 <script> 手动初始化(不用 data-*)
<script src="/static/agent-embed.umd.js"></script>
<script>
const { AgentEmbedClient } = window.AgentEmbed;
const client = new AgentEmbedClient({
baseUrl: 'https://agent-hub.intra.example.com',
channelId: 1,
embedCode: 'oa-pending',
});
// ...同上
</script>5.6 React 中接入
import { useEffect, useRef, useState } from 'react';
import { AgentEmbedClient } from '@qxwz/agent-embed-sdk';
export function useAgent(config: ConstructorParameters<typeof AgentEmbedClient>[0]) {
const clientRef = useRef<AgentEmbedClient>();
if (!clientRef.current) {
clientRef.current = new AgentEmbedClient(config);
}
return clientRef.current;
}
export function Chat() {
const client = useAgent({
baseUrl: 'https://agent-hub.intra.example.com',
channelId: 1,
embedCode: 'oa-pending',
});
const [text, setText] = useState('');
useEffect(() => {
const sub = client.subscribe({
onTextMessageContentEvent: ({ event }) => setText((t) => t + event.delta),
onRunFinishedEvent: () => setText(client.messages.filter(m => m.role === 'assistant').pop()?.content || ''),
});
return () => sub.unsubscribe();
}, [client]);
const send = (prompt: string) => {
setText('');
client.addMessage({ id: 'msg-' + Date.now(), role: 'user', content: prompt });
client.runAgent();
};
return (
<div>
<pre>{text}</pre>
<button onClick={() => send('你好')}>发送</button>
<button onClick={() => client.abortRun()}>取消</button>
</div>
);
}六、错误码
AgentEmbedError.code:
| code | 含义 |
|------|------|
| CONFIG_ERROR | 初始化配置缺失或格式错误 |
| UNAUTHORIZED | 认证失败(401 / RUN_ERROR code=UNAUTHORIZED) |
| RUN_ERROR | 后端发出 RUN_ERROR 事件(业务错误) |
| ABORTED | 调用方主动 abortRun() |
@ag-ui/client 的 runAgent() 内部遇到 HTTP 错误会抛出标准 Error,可通过 try/catch 捕获。
七、与后端约定
- 端点:
POST {baseUrl}{aguiPathPrefix}/agui/web/send - 请求体(JSON):
{ channelId, embedCode, content, sessionId?, pageContext? } - SDK 自动将
RunAgentInput.messages中最后一条 user 消息提取为content - 响应:
text/event-stream,事件序列按 AG-UI 协议 - 认证:
- 同域:浏览器自动带 BUC SSO Cookie(
credentials: 'include') - 跨域:传
authToken→ SDK 自动加buc-auth-tokenHeader
- 同域:浏览器自动带 BUC SSO Cookie(
- 401 处理:后端 AG-UI 端点认证失败时输出
RUN_STARTED → RUN_ERROR(code=UNAUTHORIZED)事件流
八、构建 / 发布
pnpm install
pnpm typecheck # 类型检查
pnpm build:lib # 构建 ESM + CJS(@ag-ui/client 为外部依赖)
pnpm build:umd # 构建 UMD(@ag-ui/client + rxjs + zod 全部打包,自包含)
pnpm build:types # 生成 .d.ts
pnpm build # 上述全部产物:
dist/agent-embed.es.js— ESM(npmimport,~4KB)dist/agent-embed.cjs.js— CJS(require,~4KB)dist/agent-embed.umd.js— UMD(<script>,~199KB 含 rxjs+zod 自包含,带 auto-init,已压缩)dist/*.d.ts— TypeScript 类型
九、版本
当前版本:0.2.0(基于 @ag-ui/client,走 /agui/web/send 端点)。
变更:
0.2.0— 基于@ag-ui/client的HttpAgent重构,覆写requestInit()将 RunAgentInput 转换为 WebChatRequest,走/agui/web/send端点;SSE 解析复用 @ag-ui/client 内置能力0.1.0— 初始版本,自建 fetch+SSE 解析,使用/agui/web/send端点
