component-genie-mcp
Version:
A simplified Model Context Protocol server for querying React components with complete content access
296 lines (268 loc) • 11.2 kB
JavaScript
/**
* 向Agent聊天SSE接口发起请求
* @param {Object} config - 配置参数
* @param {string} config.baseUrl - 基础URL,例如 'https://gateway-boss.zacz.cn'
* @param {string} config.query - 用户问句
* @param {string} config.agentInstanceId - agent编码
* @param {string} config.tenantId - 租户ID
* @param {string} config.userId - 用户ID
* @param {string} config.bizInvokeFrom - 业务调用来源,默认"ROBOT"
*/
async function sendAgentChatRequest(config) {
const {
baseUrl = "https://gateway-boss.zacz.cn",
query,
agentInstanceId,
tenantId,
userId,
bizInvokeFrom = "ROBOT",
isStream = true,
confirm = false,
deep_plan = false,
} = config;
// 构建请求数据
const requestData = {
query,
agentInstanceId,
tenantId,
userId,
bizInvokeFrom,
isStream,
confirm,
deep_plan,
};
const url = `${baseUrl}/quick/agent/chat/sse`;
// 添加调试信息
console.log("发起请求:");
console.log(`URL: ${url}`);
console.log(`Method: POST`);
console.log(`请求数据:`, JSON.stringify(requestData, null, 2));
console.log(`请求体长度:`, JSON.stringify(requestData).length);
console.log(`请求体内容:`, JSON.stringify(requestData));
try {
const response = await fetch(url, {
method: "POST",
headers: {
Accept: "text/event-stream",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Accept-Language": "zh-CN,zh;q=0.9",
Authorization:
"Basic T3dnWEJWMU44WDJDY1ViN21qbTMycG5MeE4wZ2cxaWpXQVJzcEw5eE0xODpieTZvaEhqVG4xMjZ5Nkh2bnltTHpEYjNsMWQ1bjZqbg==",
Connection: "keep-alive",
"Content-Type": "application/json",
"User-Agent":
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
"sec-ch-ua":
'"Not;A=Brand";v="99", "Google Chrome";v="139", "Chromium";v="139"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"macOS"',
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "none",
"Sec-Fetch-Storage-Access": "active",
// 如果需要的话,可以添加Cookie
// "Cookie": "cna=wRorIfwBTVUCAYzNZlBEXjsl; xlly_s=1; ..."
},
body: JSON.stringify(requestData),
});
console.log(`状态码: ${response.status}`);
console.log(`响应头:`, Object.fromEntries(response.headers.entries()));
if (!response.ok) {
console.log(`====== 请求失败 =====`);
console.log(`状态码: ${response.status} ${response.statusText}`);
console.log(`URL: ${url}`);
console.log(`请求数据:`, JSON.stringify(requestData, null, 2));
// 尝试读取错误响应体
try {
const errorText = await response.text();
console.log(`错误响应体:`, errorText);
} catch (err) {
console.log(`无法读取错误响应体:`, err.message);
}
throw new Error(
`请求失败,状态码: ${response.status} ${response.statusText}`
);
}
if (!response.body) {
throw new Error("响应体为空");
}
// 获取ReadableStream读取器
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
console.log("SSE连接结束");
break;
}
// 解码数据块
const chunk = decoder.decode(value, { stream: true });
buffer += chunk;
// 处理SSE数据流
const lines = buffer.split("\n");
buffer = lines.pop() || ""; // 保留最后一个不完整的行
lines.forEach((line) => {
if (line.startsWith("data: ")) {
const data = line.slice(6); // 移除 'data: ' 前缀
if (data === "[DONE]") {
console.log("流式输出结束");
return;
}
if (data.trim() === "") {
return; // 跳过空数据行
}
try {
const jsonData = JSON.parse(data);
handleSSEMessage(jsonData);
} catch (error) {
console.error("解析JSON数据失败:", error.message);
console.error("原始数据:", data);
}
}
});
}
} finally {
reader.releaseLock();
}
} catch (error) {
console.error("请求错误:", error);
throw error;
}
}
/**
* 处理SSE消息
* @param {Object} data - 解析后的JSON数据
*/
function handleSSEMessage(data) {
console.log("\n=== 收到新消息 ===");
console.log(`消息ID: ${data.msgId}`);
console.log(`消息类型: ${data.msgType}`);
console.log(`对话ID: ${data.chatId}`);
console.log(`会话ID: ${data.conversationId}`);
console.log(`是否结束: ${data.isEnd}`);
console.log(`是否首次消息: ${data.firstMessageFlag}`);
console.log(`消耗Token: ${data.totalTokens}`);
console.log(`耗时: ${data.spendTime}ms`);
if (data.content) {
console.log(`消息完结: ${data.content.messageEnd}`);
console.log(`内容: ${data.content.docAskContent || data.content.sentence}`);
console.log(`内容类型: ${data.content.type}`);
// 处理文档引用信息
if (data.content.docInfoList && data.content.docInfoList.length > 0) {
console.log("引用文档:");
data.content.docInfoList.forEach((doc, index) => {
console.log(` ${index + 1}. ${doc.docName} (ID: ${doc.docId})`);
console.log(` 摘要: ${doc.summary}`);
console.log(` URL: ${doc.docUrl}`);
});
}
// 处理分片信息
if (
data.content.segmentInfoList &&
data.content.segmentInfoList.length > 0
) {
console.log("相关分片:");
data.content.segmentInfoList.forEach((segment, index) => {
console.log(
` ${index + 1}. 文档ID: ${segment.documentId}, 分片ID: ${
segment.segmentId
}, 分数: ${segment.score}`
);
});
}
}
// 处理思维链信息
if (
data.thoughtChainContentInfo &&
data.thoughtChainContentInfo.thoughtChainList
) {
console.log("思维链信息:");
data.thoughtChainContentInfo.thoughtChainList.forEach((chain, index) => {
console.log(` ${index + 1}. ${chain.title} (${chain.thoughtChainType})`);
console.log(` 状态: ${chain.status}`);
if (chain.failMessage) {
console.log(` 失败原因: ${chain.failMessage}`);
}
});
}
console.log("==================\n");
}
// 使用示例
async function main() {
const query = `# 智能生成任务列表
**1** **标题**:*~智能生成~*
* 标题后展示提示文案:*~保留最近90天的智能生成任务记录~*
**2** **搜索**:支持按任务名称模糊搜索,大小写不敏感
**3** **筛选**:
* ~资产类型~:本期仅支持表、指标;指标是否展示取决于当前 user 是否支持指标资产管理
* ~创建人~:下拉多选搜索框,可选范围为当前租户下“正常”状态的用户;可快捷筛选“我创建的”
* ~生成进度~:多选 CheckBox,支持:*~已完成、生成中、已终止、执行异常~*
**4** **列表项**:列表高度根据当前行的明细行动态调整高度,展示 2 行或 3 行
* ~任务名称/资产类型~:第一行展示任务名称,超长...hover 展示全部;第二行展示资产类型
* ~生成属性~:按“资产类型”分开展示,仅展示配置了的类型对应的属性,最多 3 行
* 所有属性名称平铺展示,无需缩进为等 n 个
* 自动识别指标的配置无需在此处展示
* ~资产总数~:展示按照当前任务配置,真正需要进行智能生成的资产数@扶至钦(扶犁)
* 暂未返回结果的时候展示为-;拿到全部数值后再返回
* 标题后展示 info icon,hover 提示:*~表资产仅统计表个数,不统计指标个数~*
* ~生成进度~:第一行展示总体状态、第二行起展示明细状态
* ~全部完成~:无继续生成中、待生成的资产,可能包含“成功”和“失败”
1 第一行灰色文字展示
2 第二行起展示“成功、失败”的个数,仅展示有对应资产的状态行;失败的数值红色 highlight,如果为 0 则展示为黑色无需标红[2025-06-10 更新]
3 “已终止”的算"失败"
* ~生成中~:存在“生成中、待生成”的资产
1 第一行灰色文字:*~生成中~*;
2 第二行起展示“已完成、生成中”的个数,其中
* 已完成:包含“成功”和“失败”
* 生成中:包含“生成中”和“待生成”
* ~已终止~:手动终止过的生成任务
1 第一行红色文字展示
2 第二行起展示“已完成、待生成”的个数
* 其中正在生成中被手动终止的,视为“待生成”;继续生成/重新生成时,该部分也需要继续生成/重新生成
* ~执行异常~:失败 icon+“执行异常”文案,以及“查看执行日志”的 icon
1 整体执行异常视为该状态
2 点击 icon 右侧呼出异常日志的抽屉,支持复制和全屏展示,样式参见下图
* ~审核状态~:仅展示有对应资产的状态行,仅”全部成功、已终止”生成状态的展示,其余展示为-
* ~已应用~:手动确认“应用”过的资产;如果应用后重新生成,视为待审核
* ~已弃用~:手动确认“启用”过的资产;如果启用后重新生成,视为待审核
* ~待审核~:其余视为“待审核”
* ~创建人/创建时间~:
* 第一行展示创建人名称
* 第二行展示创建时间
* ~操作~:
* ~查看详情~:点击当前页面跳转至该任务的详情页;更多其他操作本期仅在在任务详情页支持
* [2025-06-04 新增]~删除~:
1 除“生成中”状态不展示该操作 icon,其他均展示
2 点击弹出二次确认弹框:
* 标题:*~删除智能生成任务:{任务名}~*
* 提示:*~删除后,已生成的内容将被清理,删除操作不可恢复~*
* 操作校验:
* 是否有【上架管理-管理】权限
* 如果在确定前该任务已经被删除,无需报错,提示操作成功即可
* 排序:按照创建时间倒序
* 分页:支持分页;底部分页条不展示批量操作入口(本期不支持批量操作)[2025-05-14 更新]
`;
try {
// 配置请求参数
const config = {
baseUrl: "https://gateway-boss.zacz.cn",
agentInstanceId: "5be564ab-2b61-4aed-93c4-12729e4034d6",
bizInvokeFrom: "ROBOT",
query,
tenantId: "25073022381050",
userId: 283360,
confirm: false,
deep_plan: false,
isStream: true,
};
console.log("开始发送请求...");
await sendAgentChatRequest(config);
console.log("请求完成");
} catch (error) {
console.error("执行失败:", error.message);
}
}
// 如果直接运行此文件,则执行main函数
main();