Skip to content

Commit f6b6663

Browse files
committed
feat: support mcp
1 parent b520964 commit f6b6663

File tree

9 files changed

+193
-21
lines changed

9 files changed

+193
-21
lines changed

apps/miniprogram-agent-ui/miniprogram/components/agent-ui/collapse/index.wxml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<!--components/agent-ui/collapsibleCard/index.wxml-->
22
<view class="collapse" style="{{collapsedStatus&&showBgColor?'background-color: #f5f5f5;':''}}">
33
<view class="collapse-header" bind:tap="changeCollapsedStatus">
4+
<image src="../imgs/arrow.svg" mode="aspectFill" style="width: 16px;height: 16px;transform: rotate({{collapsedStatus?360:270}}deg);" />
45
<slot name="title"></slot>
5-
<image src="../imgs/arrow.svg" mode="aspectFill" style="width: 16px;height: 16px;transform: rotate({{collapsedStatus?0:180}}deg);" />
66
</view>
77
<block wx:if="{{collapsedStatus}}">
88
<slot name="content"></slot>
Lines changed: 2 additions & 0 deletions
Loading
Lines changed: 2 additions & 0 deletions
Loading

apps/miniprogram-agent-ui/miniprogram/components/agent-ui/index.js

Lines changed: 153 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ Component({
112112

113113
// 初始化第一条记录为welcomeMessage
114114
const record = {
115-
content: bot.welcomeMessage || "您好,有什么需要帮助您的?",
115+
content: bot.welcomeMessage || "你好,有什么我可以帮到你?",
116116
record_id: "record_id" + String(+new Date() + 10),
117117
role: "assistant",
118118
hiddenBtnGround: true,
@@ -145,13 +145,62 @@ Component({
145145
},
146146
methods: {
147147
showErrorMsg: function (e) {
148-
const { content } = e.currentTarget.dataset;
148+
const { content, reqid } = e.currentTarget.dataset;
149149
console.log("content", content);
150+
const transformContent =
151+
typeof content === "string"
152+
? reqid
153+
? `${content}|reqId:${reqid}`
154+
: content
155+
: JSON.stringify({ content, reqid });
150156
wx.showModal({
151157
title: "错误原因",
152-
content: typeof content === "string" ? content : JSON.stringify({ content }),
158+
content: transformContent,
159+
success() {
160+
wx.setClipboardData({
161+
data: transformContent,
162+
success: function (res) {
163+
wx.showToast({
164+
title: "复制错误完成",
165+
icon: "success",
166+
});
167+
},
168+
});
169+
},
153170
});
154171
},
172+
transformToolCallHistoryList: function (toolCallList) {
173+
const callParamsList = toolCallList.filter((item) => item.type === "tool-call");
174+
// const callResultList = toolCallList.filter(item => item.type === 'tool-result')
175+
const callContentList = toolCallList.filter((item) => item.type === "text");
176+
const transformToolCallList = [];
177+
for (let i = 0; i < callParamsList.length; i++) {
178+
const curParam = callParamsList[i];
179+
const curResult = toolCallList.find(
180+
(item) => item.type === "tool-result" && item.toolCallId === curParam.tool_call.id
181+
);
182+
const curContent = callContentList[i];
183+
const curError = toolCallList.find(
184+
// (item) => item.finish_reason === "error" && item.error.message.toolCallId === curParam.tool_call.id
185+
(item) => item.finish_reason === "error"
186+
);
187+
const transformToolCallObj = {
188+
id: curParam.tool_call.id,
189+
name: curParam.tool_call.function.name,
190+
callParams: "```json\n\n" + JSON.stringify(curParam.tool_call.function.arguments, null, 2) + "\n```",
191+
content: ((curContent && curContent.content) || "").replaceAll("\t", "").replaceAll("\n", "\n\n"),
192+
};
193+
if (curResult) {
194+
transformToolCallObj.callResult = "```json\n\n" + JSON.stringify(curResult.result, null, 2) + "\n```";
195+
}
196+
if (curError) {
197+
transformToolCallObj.error = curError;
198+
}
199+
200+
transformToolCallList.push(transformToolCallObj);
201+
}
202+
return transformToolCallList;
203+
},
155204
handleLineChange: function (e) {
156205
console.log("linechange", e.detail.lineCount);
157206
// 查foot-function height
@@ -349,8 +398,26 @@ Component({
349398
if (item.role === "assistant" && item.content === "") {
350399
transformItem.content = this.data.defaultErrorMsg;
351400
}
401+
if (item.role === "assistant" && item.origin_msg) {
402+
console.log("toolcall origin_msg", JSON.parse(item.origin_msg));
403+
const origin_msg_obj = JSON.parse(item.origin_msg);
404+
if (origin_msg_obj.aiResHistory) {
405+
const transformToolCallList = this.transformToolCallHistoryList(origin_msg_obj.aiResHistory);
406+
transformItem.toolCallList = transformToolCallList;
407+
const toolCallErr = transformToolCallList.find((item) => item.error)?.error;
408+
console.log("toolCallErr", toolCallErr);
409+
if (toolCallErr?.error?.message) {
410+
transformItem.error = toolCallErr.error.message;
411+
transformItem.reqId = item.trace_id || "";
412+
}
413+
} else {
414+
// 之前异常的返回
415+
// return null
416+
}
417+
}
352418
return transformItem;
353-
});
419+
})
420+
.filter((item) => item);
354421
this.setData({
355422
chatRecords: [...freshChatRecords, ...this.data.chatRecords],
356423
});
@@ -380,7 +447,7 @@ Component({
380447
return;
381448
}
382449
const record = {
383-
content: bot.welcomeMessage || "您好,有什么需要帮助您的?",
450+
content: bot.welcomeMessage || "你好,有什么我可以帮到你?",
384451
record_id: "record_id" + String(+new Date() + 10),
385452
role: "assistant",
386453
hiddenBtnGround: true,
@@ -699,7 +766,6 @@ Component({
699766

700767
// 新增一轮对话记录时 自动往下滚底
701768
this.autoToBottom();
702-
703769
if (chatMode === "bot") {
704770
const ai = wx.cloud.extend.AI;
705771
const res = await ai.bot.sendMessage({
@@ -762,6 +828,23 @@ Component({
762828
this.setData({
763829
[`chatRecords[${lastValueIndex}].error`]: lastValue.error,
764830
});
831+
if (lastValue.toolCallList && lastValue.toolCallList.length) {
832+
let errToolCallObj = null;
833+
if (typeof error.message === "string") {
834+
errToolCallObj = lastValue.toolCallList[lastValue.toolCallList.length - 1];
835+
} else {
836+
if (error.message?.toolCallId) {
837+
errToolCallObj = lastValue.toolCallList.find((item) => item.id === error.message.toolCallId);
838+
}
839+
}
840+
if (errToolCallObj && !errToolCallObj.callResult) {
841+
errToolCallObj.error = error;
842+
this.setData({
843+
[`chatRecords[${lastValueIndex}].toolCallList`]: lastValue.toolCallList,
844+
});
845+
this.autoToBottom();
846+
}
847+
}
765848
}
766849
this.setData({
767850
[`chatRecords[${lastValueIndex}].search_info`]: lastValue.search_info,
@@ -770,6 +853,12 @@ Component({
770853
[`chatRecords[${lastValueIndex}].content`]: lastValue.content,
771854
[`chatRecords[${lastValueIndex}].record_id`]: lastValue.record_id,
772855
});
856+
// if (error) {
857+
// lastValue.error = error;
858+
// this.setData({
859+
// [`chatRecords[${lastValueIndex}].error`]: lastValue.error,
860+
// });
861+
// }
773862
break;
774863
}
775864
// 下面根据type来确定输出的内容
@@ -802,13 +891,31 @@ Component({
802891
}
803892
// 内容
804893
if (type === "text") {
805-
contentText += content;
806-
lastValue.content = contentText;
807-
this.setData({
808-
[`chatRecords[${lastValueIndex}].content`]: lastValue.content,
809-
[`chatRecords[${lastValueIndex}].record_id`]: lastValue.record_id,
810-
chatStatus: 3,
811-
}); // 聊天状态切换为输出content中
894+
// 区分是 toolCall 的content 还是普通的 content
895+
let isToolCallContent = false;
896+
const toolCallList = lastValue.toolCallList;
897+
if (toolCallList && toolCallList.length) {
898+
const lastToolCallObj = toolCallList[toolCallList.length - 1];
899+
if (lastToolCallObj.callParams && !lastToolCallObj.callResult) {
900+
isToolCallContent = true;
901+
lastToolCallObj.content += content.replaceAll("\t", "");
902+
this.setData({
903+
[`chatRecords[${lastValueIndex}].toolCallList`]: lastValue.toolCallList,
904+
chatStatus: 3,
905+
});
906+
this.autoToBottom();
907+
}
908+
}
909+
910+
if (!isToolCallContent) {
911+
contentText += content;
912+
lastValue.content = contentText;
913+
this.setData({
914+
[`chatRecords[${lastValueIndex}].content`]: lastValue.content,
915+
[`chatRecords[${lastValueIndex}].record_id`]: lastValue.record_id,
916+
chatStatus: 3,
917+
}); // 聊天状态切换为输出content中
918+
}
812919
}
813920
// 知识库,只更新一次
814921
if (type === "knowledge" && !lastValue.knowledge_meta) {
@@ -827,6 +934,39 @@ Component({
827934
chatStatus: 2,
828935
});
829936
}
937+
// tool_call 场景,调用请求
938+
if (type === "tool-call") {
939+
const { tool_call } = dataJson;
940+
const callBody = {
941+
id: tool_call.id,
942+
name: tool_call.function.name,
943+
callParams: "```json\n" + JSON.stringify(tool_call.function.arguments, null, 2) + "\n```",
944+
content: "",
945+
};
946+
if (!lastValue.toolCallList) {
947+
lastValue.toolCallList = [callBody];
948+
} else {
949+
lastValue.toolCallList.push(callBody);
950+
}
951+
this.setData({
952+
[`chatRecords[${lastValueIndex}].toolCallList`]: lastValue.toolCallList,
953+
});
954+
this.autoToBottom();
955+
}
956+
// tool_call 场景,调用响应
957+
if (type === "tool-result") {
958+
const { toolCallId, result } = dataJson;
959+
if (lastValue.toolCallList && lastValue.toolCallList.length) {
960+
const lastToolCallObj = lastValue.toolCallList.find((item) => item.id === toolCallId);
961+
if (lastToolCallObj && !lastToolCallObj.callResult) {
962+
lastToolCallObj.callResult = "```json\n" + JSON.stringify(result, null, 2) + "\n```";
963+
this.setData({
964+
[`chatRecords[${lastValueIndex}].toolCallList`]: lastValue.toolCallList,
965+
});
966+
this.autoToBottom();
967+
}
968+
}
969+
}
830970
} catch (e) {
831971
console.log("err", event, e);
832972
break;

apps/miniprogram-agent-ui/miniprogram/components/agent-ui/index.wxml

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<text class="bot-name">{{bot.name}}</text>
77
</view>
88
</view>
9-
<view style="height: 100%;overflow: auto">
9+
<view style="height: 100%;overflow: auto;">
1010
<!-- 聊天对话区 -->
1111
<scroll-view bindwheel="onWheel" enhanced="{{true}}" bindscroll="onScroll" binddragstart="handleScrollStart" class="main" style="height: 100%;" scroll-y="{{true}}" scroll-top="{{viewTop}}" scroll-into-view="{{ scrollTo }}" lower-threshold="1" bindscrolltolower="handleScrollToLower" show-scrollbar="{{false}}" refresher-enabled="{{showPullRefresh}}" refresher-threshold="{{80}}" bindrefresherrefresh="handelRefresh" refresher-triggered="{{triggered}}" bounces="{{false}}">
1212
<view wx:if="{{chatMode === 'bot' && showPullRefresh}}" class="tips">
@@ -66,10 +66,37 @@
6666
<markdownPreview markdown="{{item.reasoning_content||''}}" fontSize="{{28}}"></markdownPreview>
6767
</view>
6868
</FoldedCard>
69+
<!-- 工具调用 -->
70+
71+
<view wx:if="{{item.toolCallList && item.toolCallList.length > 0}}">
72+
<block wx:for="{{item.toolCallList}}" wx:for-item="subItem" wx:key="id">
73+
<markdownPreview markdown="{{subItem.content || ''}}"></markdownPreview>
74+
<FoldedCard initStatus="{{false}}" showBgColor="{{false}}">
75+
<view slot="title" style="opacity: 0.7;font-size: 14px; display: flex; align-items: center; gap: 8px;">
76+
<block>
77+
调用工具 {{subItem.name}}
78+
<image wx:if="{{!subItem.callResult && !subItem.error}}" src="./imgs/loading.svg" mode="aspectFill" style="width: 14px;height: 14px;" />
79+
<image wx:if="{{subItem.callResult}}" mode="widthFix" src='./imgs/check.svg' style="width: 36rpx; height: 36rpx;vertical-align: top;" bind:tap="share" />
80+
<image wx:if="{{subItem.error}}" mode="widthFix" src='./imgs/close-red.svg' style="width: 36rpx; height: 36rpx;vertical-align: top;" bind:tap="share" />
81+
</block>
82+
<!-- <block wx:else>
83+
<text>{{item.reasoning_content&&!item.content?"思考中...":"已深度思考(用时"+item.thinkingTime+"秒)"}}</text>
84+
</block> -->
85+
</view>
86+
<view style="padding-left: 25rpx;margin-top: 28rpx; border-left: rgb(165, 164, 164) solid 2px; opacity: 0.7;" slot="content">
87+
<view>参数:</view>
88+
<markdownPreview markdown="{{subItem.callParams||''}}" fontSize="{{28}}"></markdownPreview>
89+
<view>结果:</view>
90+
<markdownPreview markdown="{{subItem.callResult||''}}" fontSize="{{28}}"></markdownPreview>
91+
</view>
92+
</FoldedCard>
93+
</block>
94+
</view>
95+
<!-- 正文 -->
6996
<markdownPreview markdown="{{item.content||''}}"></markdownPreview>
7097
<!-- 下面的按钮 -->
7198
<view style="display: flex; gap: 10px;justify-content: flex;" wx:if="{{!item.hiddenBtnGround}}">
72-
<image wx:if="{{item.error}}" mode="widthFix" bind:tap="showErrorMsg" src='./imgs/error-circle.svg' style="width: 36rpx; height: 36rpx;" data-content="{{item.error}}" />
99+
<image wx:if="{{item.error}}" mode="widthFix" bind:tap="showErrorMsg" src='./imgs/error-circle.svg' style="width: 36rpx; height: 36rpx;" data-content="{{item.error}}" data-reqid="{{item.reqId}}"/>
73100
<image mode="widthFix" bind:tap="copyChatRecord" src='./imgs/copy.svg' style="width: 36rpx; height: 36rpx;" data-content="{{item.content}}" />
74101
<block wx:if="{{!item.error}}">
75102
<button class="share_btn" open-type="share">

apps/miniprogram-agent-ui/miniprogram/components/agent-ui/wd-markdown/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ Component({
8484
markdown: function () {
8585
const { mdInstance } = this.data;
8686
if (!mdInstance) return;
87+
// console.log('*****markdown', this.data.markdown)
8788
const html = mdInstance.render(this.data.markdown)
88-
// console.log(html)
89+
// console.log('*****((((((',html)
8990
this.setData({
9091
__html: html,
9192
});

apps/miniprogram-agent-ui/project.private.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
},
66
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
77
"projectname": "cloudbase-agent-ui",
8-
"libVersion": "3.7.8"
8+
"libVersion": "3.7.10"
99
}

project.config.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"appid": "wx401b4f0b10b9f661",
2+
"appid": "wxcf5102ada68a7ac9",
33
"compileType": "miniprogram",
44
"libVersion": "3.7.10",
55
"packOptions": {
@@ -26,4 +26,4 @@
2626
"tabSize": 2
2727
},
2828
"projectArchitecture": "miniProgram"
29-
}
29+
}

project.private.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
"setting": {
55
"compileHotReLoad": true
66
}
7-
}
7+
}

0 commit comments

Comments
 (0)