diff --git a/CHANGELOG.md b/CHANGELOG.md index 56f9c68..ce1e44f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.15.3](https://github.com/TencentCloudBase/cloudbase-agent-ui/compare/v1.15.2...v1.15.3) (2026-01-14) + ### [1.15.2](https://github.com/TencentCloudBase/cloudbase-agent-ui/compare/v1.15.1...v1.15.2) (2026-01-12) ### [1.15.1](https://github.com/TencentCloudBase/cloudbase-agent-ui/compare/v1.15.0...v1.15.1) (2026-01-12) diff --git a/README.md b/README.md index e62f346..0b611ab 100644 --- a/README.md +++ b/README.md @@ -5,20 +5,18 @@ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/TencentCloudBase/cloudbase-agent-ui/blob/main/LICENSE) [![GitHub Stars](https://img.shields.io/github/stars/TencentCloudBase/cloudbase-agent-ui?style=social)](https://github.com/TencentCloudBase/cloudbase-agent-ui) -cloudbase-agent-ui 是由腾讯云开发团队推出的 AI 智能对话 UI 组件,配置简单开箱即用,助力微信小程序开发者快速集成大模型能力,打造企业级LLM应用。现已支持接入 -***DeepSeek 满血版(DeepSeek-R1-671B 与 DeepSeek-V3-671B)🔥🔥🔥, 腾讯混元大模型等***。 +cloudbase-agent-ui 是由腾讯云开发团队推出的 AI 智能对话 UI 组件,配置简单开箱即用,助力微信小程序开发者快速集成大模型能力,打造企业级LLM应用。 Agent UI 演示效果图 - + ## 🌟 特性亮点 - **双模式支持** `Agent模式` 与 `大模型直连` 自由选择对话策略 -- **企业级功能集成** 流式输出/联网搜索/深度思考/多轮会话 开箱即用 -- **多模型支持** 深度兼容 DeepSeek、Hunyuan 等主流大模型 +- **企业级功能集成** 流式输出/多轮会话 开箱即用 +- **多模型支持** 深度兼容 DeepSeek、Hunyuan 等主流大模型,支持自定义模型接入 - **配置即开发** 通过配置快速接入组件能力,无需处理复杂通信逻辑 -- **支持 MCP Server 调用&自定义工具卡片** 对接云开发MCP Server能力,支持开发者定制工具卡片展示 ## 📦 使用指南 @@ -38,10 +36,15 @@ Agent UI 微信小程序组件依赖**微信云开发**服务,需先开通云 ##### 1.2、创建AI服务 -- 方式一:直接使用agent智能体服务 - ![](https://qcloudimg.tencent-cloud.cn/raw/97786aaaa15aa1f23e9bbd39a7a6762f.png) +> 注意:配置型 agent 已逐步废弃,新 agent 服务请使用框架型 agent 。 + +- 方式一:使用 agent 框架创建智能体服务 + + ![](https://qcloudimg.tencent-cloud.cn/raw/c5920ccc04caecd29eaea00b0d9ab343.png) + - 方式二:接入大模型 - ![](https://qcloudimg.tencent-cloud.cn/raw/876d2238b5331a7bdcbd91a1b38b8248.png) + + ![](https://qcloudimg.tencent-cloud.cn/raw/4e6aa1d2cab1a8da79f6a27ca18ca481.png) #### 2. 获取组件 @@ -53,124 +56,97 @@ Agent UI 微信小程序组件依赖**微信云开发**服务,需先开通云 #### 3. 微信小程序项目引入组件 1. **配置云开发环境ID** + 打开 miniprogram/app.js 文件,配置云开发环境ID。 -```js -App({ - onLaunch: function () { - if (!wx.cloud) { - console.error("请使用 2.2.3 或以上的基础库以使用云能力"); - } else { - wx.cloud.init({ - env: "your envId",// 环境id - traceUser: true, - }); - } - - this.globalData = {}; - }, -}); -``` + ```javascript + App({ + onLaunch: function () { + if (!wx.cloud) { + console.error("请使用 2.2.3 或以上的基础库以使用云能力"); + } else { + wx.cloud.init({ + env: "your envId", // 环境id + traceUser: true, + }); + } + this.globalData = {}; + }, + }); + ``` 2. **拷贝源码组件,将 agent-ui 组件放入用户项目 components 目录中** 3. **组件所属页面 .json配置文件中注册组件** -```json -{ - "usingComponents": { - "agent-ui":"/components/agent-ui/index" - }, -} - -``` + ```json + { + "usingComponents": { + "agent-ui":"/components/agent-ui/index" + }, + } + ``` 4. **组件所属页面 .wxml 文件中引用组件** -```wxml - - - -``` + ```xml + + + + ``` 5. **组件所属页面 .js 文件中编写配置** -```js -Page({ - // ... - data: { - chatMode: "bot", // bot 表示使用agent,model 表示使用大模型,两种选一种配置即可 - showBotAvatar: true, // 是否在对话框左侧显示头像 - agentConfig: { - botId: "bot-e7d1e736", // agent id, - allowWebSearch: true, // 允许客户端选择启用联网搜索 - allowUploadFile: true, // 允许上传文件 - allowPullRefresh: true, // 允许下拉刷新 - allowUploadImage: true, // 允许上传图片 - allowMultiConversation: true, // 允许客户端界面展示会话列表及新建会话按钮 - showToolCallDetail: true, // 允许展示 mcp server toolcall 细节 - allowVoice: true, // 允许展示语音按钮 - }, - modelConfig: { - modelProvider: "hunyuan-open", // 大模型服务厂商 - quickResponseModel: "hunyuan-lite", // 大模型名称 - logo: "", // model 头像 - welcomeMsg: "欢迎语", // model 欢迎语 - }, - } - // ... -}) -``` - -### 自定义 MCP 工具卡片 - -> 以下示例流程以结合腾讯地图 MCP Server 开发自定义工具卡片举例说明 - -#### 1. 开通 MCP 能力 - -- 进入云开发平台 AI+ MCP 页面,点击创建MCP Server - -![](https://qcloudimg.tencent-cloud.cn/raw/bc2a7815b542b26f5931aa835514dc37.png) - -- 若未开通过云托管服务,需先开通云托管 - -![](https://qcloudimg.tencent-cloud.cn/raw/084b50f265e0335201801c3fb741d04d.png) - -#### 2. 配置 MCP Server - -- 以腾讯地图 MCP Server 举例,选择模板进行安装(按照指引获取腾讯地图平台API KEY后,配置环境变量) - -![](https://qcloudimg.tencent-cloud.cn/raw/a5b15af9bfff83008257a0c99d252b83.png) - -#### 3. agent 绑定 MCP Server tools - -- 在 agent 配置页点击添加MCP 服务,选择对应的MCP Server tools 使用 (此处腾讯地图示例可勾选 geocoder,placeSearchNearby, directionDriving, weather等工具) - -![](https://qcloudimg.tencent-cloud.cn/raw/b45a95e06ec0df8dab5c9d9ec7707faa.png) - -#### 4. 实现 Agent UI customCard 组件 - -- 在agent-ui customCard 组件(agent-ui/customCard/index.wxml) 中添加自定义逻辑,可根据不同 tool 类型渲染不同自定义组件 - -![](https://qcloudimg.tencent-cloud.cn/raw/b4cd35ccaa3e72189934ed59d35f7ae5.png) - -如图所示,示例中添加了腾讯地图自定义卡片组件引用 - -#### 5. 自定义卡片组件开发 - -- 参照本工程中 apps/miniprogram-agent-ui/miniprogram/components/toolCard 目录内自定义腾讯地图卡片组件实现 - -![](https://qcloudimg.tencent-cloud.cn/raw/14a4a82810f0b45bde0c124cc8f3ed1c.png) - -#### 6. 自定义卡片组件引用配置 - -- 自定义卡片组件引用声明配置(可在用户小程序项目全局app.json中配置 或 agent-ui组件index.json中配置) - -![](https://qcloudimg.tencent-cloud.cn/raw/cd1dc376a1e238f3186a2209e5875698.png) - -#### 7. 卡片效果 - - - + ```javascript + Page({ + data: { + chatMode: "bot", // bot 表示使用agent,model 表示使用大模型,两种选一种配置即可 + agentConfig: { + botId: "bot-e7d1e736", // agent id + tools: [ + { + name: "get_weather", + description: "获取指定城市的天气", + parameters: { + type: "object", + properties: { city: { type: "string" } }, + required: ["city"], + }, + // 同步函数示例 + handler: (params) => { + const { city } = params; + return `城市${city}的天气是晴朗的,温度是25摄氏度,无风`; + } + }, + { + name: "get_location", + description: "获取指定城市的经纬度", + parameters: { + type: "object", + properties: { city: { type: "string" } }, + required: ["city"], + }, + // 异步函数示例 + handler: async (params) => { + const { city } = params; + // 模拟网络延迟 + return new Promise((resolve) => { + setTimeout(() => { + resolve(`城市${city}的位置是东经114.305556度,北纬22.543056度`); + }, 2000); + }); + }, + }, + ], + }, + modelConfig: { + modelProvider: "hunyuan-open", // 大模型服务厂商 + quickResponseModel: "hunyuan-lite", // 大模型名称 + logo: "", // model 头像 + welcomeMsg: "欢迎语", // model 欢迎语 + }, + } + }) + ``` ## 🏗 项目结构 @@ -198,7 +174,7 @@ Page({ | 参数 | 类型 | 必填 | 说明 | | ----------------- | ------------------------ | ---- | ------------------------------------------------------------------------------------------------------ | | `chatMode` | `String` | 是 | 组件对接的AI类型,值为 'bot' 或者 'model',为 'bot' 时,对接 agent 能力;为 'model' 时,对接大模型能力 | -| `showBotAvatar` | `Boolean` | 否 | 是否展示Bot的logo头像 | + | `agentConfig` | [AgentConfig](#Agentconfig) | 是 | Agent 调用配置 | | `modelConfig` | [ModelConfig](#Modelconfig) | 是 | Model 调用配置 | @@ -207,24 +183,17 @@ Page({ | 参数 | 类型 | 必填 | 说明 | | -------------------------- | ----------- | ---- | --------------------------------------------- | | `botId` | `String` | 否 | Agent的唯一标识ID,当 chatMode = 'bot' 时必填 | -| `allowWebSearch` | `Boolean` | 否 | 是否允许客户端界面展示联网搜索 | -| `allowUploadFile` | `Boolean` | 否 | 是否允许客户端界面展示文件上传 | -| `allowPullRefresh` | `Boolean` | 否 | 是否允许客户端界面展示下拉获取历史记录 | -| `allowUploadImage` | `Boolean` | 否 | 是否允许客户端界面展示图片上传及拍照上传 | -| `allowMultiConversation` | `Boolean` | 否 | 是否允许客户端界面展示会话列表及新建会话按钮 | -| `showToolCallDetail` | `Boolean` | 否 | 是否允许展示 mcp server toolcall 细节 | -| `allowVoice` | `Boolean` | 否 | 是否允许客户端界面展示语音按钮 | -| `showBotName` | `Boolean` | 否 | 是否允许客户端界面展示 Bot 名称 (当设置为false时,用户可手动在组件所属 page中自定义 navigationBarTitleText 为 Bot 名称) | +| `tools` | `Array` | 否 | 自定义工具列表(框架型 agent 生效) | #### ModelConfig -| 参数 | 类型 | 必填 | 说明 | -| ---------------------- | ---------- | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `modelProvider` | `String` | 是 | 大模型服务商,当 chatMode = 'model' 时,必填,值为 'hunyuan-open' 或 'deepseek' | -| `quickResponseModel` | `String` | 是 | 具体使用的模型,当 chatMode = 'model' 时,必填; modelProvider 为 deepseek时,支持 deepseek-r1/deepseek-v3; modelProvider 为 hunyuan-exp (混元体验版)/ hunyuan-open(混元正式版,使用需先[配置API Key](https://tcb.cloud.tencent.com/dev?envId=luke-agent-dev-7g1nc8tqc2ab76af#/ai?tab=ai-model&model=hunyuan-open))时,quickResponseModel 可配置为hunyuan-lite | -| `logo` | `String` | 否 | 页面 logo,当 chatMode = 'model' 时生效,选填 | -| `welcomeMsg` | `String` | 否 | 欢迎语,当 chatMode = 'model' 时生效,选填 | - +| 参数 | 类型 | 必填 | 说明 | +| ---------------------- | ---------- | ---- | ---- | +| `modelProvider` | `String` | 是 | 大模型服务商,当 chatMode = 'model' 时,必填,值为 'hunyuan-open' 或 'deepseek' | +| `quickResponseModel` | `String` | 是 | 具体使用的模型,当 chatMode = 'model' 时,必填;modelProvider 为 deepseek 时,支持 deepseek-r1/deepseek-v3;modelProvider 为 hunyuan-exp(混元体验版)/hunyuan-open(混元正式版,使用需先[配置API Key](https://tcb.cloud.tencent.com/dev?envId=luke-agent-dev-7g1nc8tqc2ab76af#/ai?tab=ai-model&model=hunyuan-open))时,quickResponseModel 可配置为 hunyuan-lite | +| `logo` | `String` | 否 | 页面 logo,当 chatMode = 'model' 时生效,选填 | +| `welcomeMsg` | `String` | 否 | 欢迎语,当 chatMode = 'model' 时生效,选填 | +## 🔗 组件使用限制 > **上传文件限制** > 大小限制:单文件不超过10M > 数量限制:单次最多支持 5 个文件 @@ -242,100 +211,239 @@ Page({ -配置示例 +## 🔧 组件配置示例 - **对接 DeepSeek 大模型** 1. 前往 miniprogram/app.js 文件配置云开发环境 ID -```javascript -wx.cloud.init({ - env: "你的环境ID", - traceUser: true, -}); -``` + ```javascript + wx.cloud.init({ + env: "你的环境ID", + traceUser: true, + }); + ``` 2. 修改组件配置,在引用 agent-ui 组件的页面配置 (也可参考apps/miniprogram-agent-ui项目 chatBot 页面配置案例) -```javascript -Page({ - //... - data: { - chatMode: 'model', - modelConfig: { - modelProvider: "deepseek", - quickResponseModel: "deepseek-v3" // or deepseek-r1 - logo: "", - welcomeMsg: "" - } - } - //... -}) -``` + ```javascript + Page({ + //... + data: { + chatMode: 'model', + modelConfig: { + modelProvider: "deepseek", + quickResponseModel: "deepseek-v3.2", + logo: "", + welcomeMsg: "" + } + } + //... + }) + ``` - **对接 Hunyuan 大模型** 1. 前往 miniprogram/app.js 文件配置云开发环境 ID -```javascript -wx.cloud.init({ - env: "你的环境ID", - traceUser: true, -}); -``` + ```javascript + wx.cloud.init({ + env: "你的环境ID", + traceUser: true, + }); + ``` 2. 修改组件配置,在引用 agent-ui 组件的页面配置 (也可参考apps/miniprogram-agent-ui项目 chatBot 页面配置案例) -```javascript -Page({ - //... - data:{ - chatMode: 'model', - modelConfig: { - modelProvider: "hunyuan-open", - quickResponseModel: "hunyuan-lite" - logo: "", - welcomeMsg: "" - } - } - //... -}) -``` + ```javascript + Page({ + //... + data: { + chatMode: 'model', + modelConfig: { + modelProvider: "hunyuan-exp", + quickResponseModel: "hunyuan-turbos-latest", + logo: "", + welcomeMsg: "" + } + } + //... + }) + ``` - **对接 腾讯云开发 Agent** 1. 前往 miniprogram/app.js 文件配置云开发环境 ID -```javascript -wx.cloud.init({ - env: "你的环境ID", - traceUser: true, -}); -``` + ```javascript + wx.cloud.init({ + env: "你的环境ID", + traceUser: true, + }); + ``` 2. 修改组件配置,在引用 agent-ui 组件的页面配置 (也可参考apps/miniprogram-agent-ui项目 chatBot 页面配置案例) + ```javascript + Page({ + //... + data: { + chatMode: "bot", // bot 表示使用agent,model 表示使用大模型 + showBotAvatar: true, // 是否在对话框左侧显示头像 + agentConfig: { + botId: "agent-xxx-xxx", // agent id + tools: [ + { + name: "get_weather", + description: "获取指定城市的天气", + parameters: { + type: "object", + properties: { city: { type: "string" } }, + required: ["city"], + }, + handler: (params) => { + const { city } = params; + return `城市${city}的天气是晴朗的,温度是25摄氏度,无风`; + } + }, + ], + } + } + //... + }) + ``` +## 🔧 工具配置示例 + +工具只支持框架型 agent 。 + +agent 框架支持前端工具和服务端工具,本示例展示了如何在 agent 中配置前端工具和服务端工具。 + +### 前端工具配置示例: + +在使用小程序组件时,需要在组件配置中添加 `tools` 字段,字段值为一个数组,数组中每个元素为一个工具配置对象。 + ```javascript -Page({ - //... - data: { - chatMode: "bot", // bot 表示使用agent,model 表示使用大模型 - showBotAvatar: true, // 是否在对话框左侧显示头像 agentConfig: { - botId: "bot-e7d1e736", // agent id, - allowWebSearch: true, // 允许客户端选择启用联网搜索 - allowUploadFile: true, // 允许上传文件 - allowPullRefresh: true, // 允许下拉刷新 - allowUploadImage: true, // 允许上传图片及拍照上传 - allowMultiConversation: true, // 允许客户端界面展示会话列表及新建会话按钮 - showToolCallDetail: true, // 允许展示 mcp server toolcall 细节 - allowVoice: true // 允许展示语音按钮 + botId: "agent-xxx-2g7292zw414326dd", + tools: [ + { + name: "get_weather", + description: "获取指定城市的天气", + parameters: { + type: "object", + properties: { city: { type: "string" } }, + required: ["city"], + }, + // 同步函数示例 + handler: (params) => { + const { city } = params; + return `城市${city}的天气是晴朗的,温度是25摄氏度,无风`; + } + }, + { + name: "get_location", + description: "获取指定城市的经纬度", + parameters: { + type: "object", + properties: { city: { type: "string" } }, + required: ["city"], + }, + // 异步函数示例 + handler: async (params) => { + const { city } = params; + // 模拟网络延迟 + return new Promise((resolve) => { + setTimeout(() => { + resolve(`城市${city}的位置是东经114.305556度,北纬22.543056度`); + }, 2000); + }); + }, + }, + ], + }, +``` +name: 工具名称 + +description: 工具的功能描述 + +parameters: 工具参数,格式为 JSON Schema 风格 + +handler: 工具处理函数,参数为parameters约定的格式,返回值为工具调用结果。 + +### 后端工具配置示例: + +使用 LangChain 模版初始化项目 + +在 src/agent.js 中添加工具配置 + +```javascript +import { clientTools } from "@cloudbase/agent-adapter-langchain"; +import { MemorySaver } from "@langchain/langgraph"; +import { ChatOpenAI } from "@langchain/openai"; +import { createAgent as createLangchainAgent } from "langchain"; +import { tool } from "@langchain/core/tools"; +import { z } from "zod"; + +const weatherTool = tool( + async ({ city }) => { + return JSON.stringify({ + city, + recommended: "黄鹤楼", + }); + }, + { + name: "where_to_go", + description: "获取当前城市今日景点推荐", + schema: z.object({ + city: z.string().describe("城市名称"), + }), } - } - //... -}) +); + + +const checkpointer = new MemorySaver(); + +export function createAgent() { + // Configure model + const model = new ChatOpenAI({ + model: process.env.OPENAI_MODEL, + apiKey: process.env.OPENAI_API_KEY, + configuration: { + baseURL: process.env.OPENAI_BASE_URL, + }, + }); + + // Create agent + return createLangchainAgent({ + model, + checkpointer, + middleware: [clientTools()], + systemPrompt: "你是一位旅游博主,回答旅游相关问题", + tools: [weatherTool] + }); +} ``` +tool 函数用于创建服务端工具, + +第一个参数为工具处理函数,函数参数为工具参数,返回值为工具调用结果。 + +第二个参数为工具配置对象,包含工具名称、功能描述、参数格式等。 + +name: 工具名称 + +description: 工具的功能描述 + +parameters: 工具参数,格式为 JSON Schema 风格 + +### 工具调用结果 + +agent 会自动收集配置的前端工具和服务端工具,前端工具会在前端调用完成后将结果自动发送给后端,后端工具会在调用时自动执行。 + +以上工具的执行结果如下: + +工具调用结果 + ## 🚀 开发路线 ### ✅ 已完成功能 @@ -343,20 +451,7 @@ Page({ - ✅ 大模型调用配置化 (DeepSeek/Hunyuan) - ✅ Agent调用配置化 (云开发平台配置) - ✅ 流式输出 -- ✅ 联网搜索 (Agent模式) -- ✅ 文档解析 (Agent模式) -- ✅ 图片上传解析(拍照/图片)(Agent模式) - ✅ 支持环境共享下使用 -- ✅ 历史会话管理,多轮对话上下文记忆(Agent模式) -- ✅ 支持 MCP 调用(Agent模式) -- ✅ 支持文字转语音播放 -- ✅ 支持用户语音输入转文字 -- ✅ 支持语音音色配置 -- ✅ UI 双标题优化 - -### 🚧 进行中开发 - -- 多模型(快速响应/深度推理)切换调用配置化 ### 📅 未来计划 @@ -365,7 +460,6 @@ Page({ - UI 高度配置化,提供页面结构配置化控制,CSS变量配置,完美融入品牌风格 - 文生图 - 文生视频 -- 文生3D - 图生视频 - 待补充... diff --git a/apps/miniprogram-agent-ui/miniprogram/components/agent-ui/index.js b/apps/miniprogram-agent-ui/miniprogram/components/agent-ui/index.js index a3feb65..5e609a7 100644 --- a/apps/miniprogram-agent-ui/miniprogram/components/agent-ui/index.js +++ b/apps/miniprogram-agent-ui/miniprogram/components/agent-ui/index.js @@ -53,9 +53,9 @@ Component({ }, // 监听agentConfig变化,判断是否是agent-开头的 agentConfig: function (agentConfig) { - console.log('mode',this.properties.chatMode) + // console.log('mode', this.properties.chatMode) // 如果是agent-开头的,从agentConfig中提取agentID和tools,组成新的agentV2Config,对用户不可见 - if (this.properties.chatMode==="bot"&&agentConfig.botId.startsWith("agent")) { + if (this.properties.chatMode === "bot" && agentConfig.botId.startsWith("agent")) { this.setData({ isAgent: true, agentV2Config: { @@ -242,7 +242,7 @@ Component({ if (!res.authSetting["scope.record"]) { wx.authorize({ scope: "scope.record", - success() {}, + success() { }, fail() { // 用户拒绝授权,可以引导用户到设置页面手动开启权限 wx.openSetting({ @@ -334,7 +334,7 @@ Component({ console.log("e", e); reject(e); }, - complete: () => {}, + complete: () => { }, header: {}, }); } @@ -1810,7 +1810,7 @@ Component({ if (finish_reason === "stop") { break; } - console.log('ryan',delta); + // console.log('ryan', delta); const { content, reasoning_content, role } = delta; reasoningText += reasoning_content || ""; contentText += content || ""; @@ -1896,7 +1896,7 @@ Component({ // 顶部文件行展现时,隐藏底部工具栏 this.setData({}); }, - subFileList: function () {}, + subFileList: function () { }, copyUrl: function (e) { const { url } = e.currentTarget.dataset; console.log(url); @@ -2334,7 +2334,7 @@ Component({ } = this.data; // 1. UI 预处理,如果是用户消息,则添加一个 AI 占位消息 const newMessages = [...messages]; - if (message?.[0].role === "user") { + if (message?.[0]?.role === "user") { const aiMsg = { id: "assistant_message_" + Date.now(), role: "assistant", parts: [] }; newMessages.push(message?.[0], aiMsg); this.setData({ @@ -2365,6 +2365,7 @@ Component({ // 3.进入流处理循环 await this.handleStream(res.eventStream, ai, agentID, currentAiMsgIndex); } catch (e) { + console.error(e); this.setData({ [`messages[${currentAiMsgIndex}].parts`]: [{ type: "error", content: "网络出错了,请稍后再试,(。ì _ í。)" }], }); @@ -2398,7 +2399,7 @@ Component({ this.setData({ [`messages[${currentAiMsgIndex}].parts[${currentParts.length - 1}].content`]: fullContent, }); - break; // 必须添加 break! + break; // 工具调用开始,push 一个 tool_call 类型的 part case "TOOL_CALL_START": fullContent = ""; @@ -2434,6 +2435,9 @@ Component({ this.setData({ [`messages[${currentAiMsgIndex}].parts[${toolCallIndex}].status`]: "success", }); + this.setData({ + [`messages[${currentAiMsgIndex}].parts[${toolCallIndex}].result`]: data.content, + }); break; case "RUN_ERROR": const agentErrorPart = { @@ -2463,44 +2467,44 @@ Component({ const tool = this.data.agentV2Config.tools.find((item) => item.name === toolCallName); // 只处理前端工具调用 if (tool) { - try { - // 调用工具处理函数 - const toolResult = await tool.handler(JSON.parse(args)); - // 处理成字符串 - const toolResultStr = JSON.stringify(toolResult); - // 调用成功,将结果添加到前端工具调用结果数组 - frontendToolsResult.push({ - toolCallId, - result: toolResultStr, - }); - // 更新工具调用状态为 success - this.setData({ - [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( - (item) => item.id === toolCallId - )}].status`]: "success", - }); - this.setData({ - [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( - (item) => item.id === toolCallId - )}].result`]: toolResultStr, - }); - } catch (e) { - frontendToolsResult.push({ - toolCallId, - result: `工具${toolCallName}调用失败:${e.message}`, - }); - // 更新工具调用状态为 failed - this.setData({ - [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( - (item) => item.id === toolCallId - )}].status`]: "failed", - }); - this.setData({ - [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( - (item) => item.id === toolCallId - )}].result`]: e.message, - }); - } + try { + // 调用工具处理函数 + const toolResult = await tool.handler(JSON.parse(args)); + // 处理成字符串 + const toolResultStr = JSON.stringify(toolResult); + // 调用成功,将结果添加到前端工具调用结果数组 + frontendToolsResult.push({ + toolCallId, + result: toolResultStr, + }); + // 更新工具调用状态为 success + this.setData({ + [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( + (item) => item.id === toolCallId + )}].status`]: "success", + }); + this.setData({ + [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( + (item) => item.id === toolCallId + )}].result`]: toolResultStr, + }); + } catch (e) { + frontendToolsResult.push({ + toolCallId, + result: `工具${toolCallName}调用失败:${e.message}`, + }); + // 更新工具调用状态为 failed + this.setData({ + [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( + (item) => item.id === toolCallId + )}].status`]: "failed", + }); + this.setData({ + [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( + (item) => item.id === toolCallId + )}].result`]: e.message, + }); + } } } // 处理工具调用结果,发送给服务端 diff --git a/components/agent-ui/index.js b/components/agent-ui/index.js index a3feb65..5e609a7 100644 --- a/components/agent-ui/index.js +++ b/components/agent-ui/index.js @@ -53,9 +53,9 @@ Component({ }, // 监听agentConfig变化,判断是否是agent-开头的 agentConfig: function (agentConfig) { - console.log('mode',this.properties.chatMode) + // console.log('mode', this.properties.chatMode) // 如果是agent-开头的,从agentConfig中提取agentID和tools,组成新的agentV2Config,对用户不可见 - if (this.properties.chatMode==="bot"&&agentConfig.botId.startsWith("agent")) { + if (this.properties.chatMode === "bot" && agentConfig.botId.startsWith("agent")) { this.setData({ isAgent: true, agentV2Config: { @@ -242,7 +242,7 @@ Component({ if (!res.authSetting["scope.record"]) { wx.authorize({ scope: "scope.record", - success() {}, + success() { }, fail() { // 用户拒绝授权,可以引导用户到设置页面手动开启权限 wx.openSetting({ @@ -334,7 +334,7 @@ Component({ console.log("e", e); reject(e); }, - complete: () => {}, + complete: () => { }, header: {}, }); } @@ -1810,7 +1810,7 @@ Component({ if (finish_reason === "stop") { break; } - console.log('ryan',delta); + // console.log('ryan', delta); const { content, reasoning_content, role } = delta; reasoningText += reasoning_content || ""; contentText += content || ""; @@ -1896,7 +1896,7 @@ Component({ // 顶部文件行展现时,隐藏底部工具栏 this.setData({}); }, - subFileList: function () {}, + subFileList: function () { }, copyUrl: function (e) { const { url } = e.currentTarget.dataset; console.log(url); @@ -2334,7 +2334,7 @@ Component({ } = this.data; // 1. UI 预处理,如果是用户消息,则添加一个 AI 占位消息 const newMessages = [...messages]; - if (message?.[0].role === "user") { + if (message?.[0]?.role === "user") { const aiMsg = { id: "assistant_message_" + Date.now(), role: "assistant", parts: [] }; newMessages.push(message?.[0], aiMsg); this.setData({ @@ -2365,6 +2365,7 @@ Component({ // 3.进入流处理循环 await this.handleStream(res.eventStream, ai, agentID, currentAiMsgIndex); } catch (e) { + console.error(e); this.setData({ [`messages[${currentAiMsgIndex}].parts`]: [{ type: "error", content: "网络出错了,请稍后再试,(。ì _ í。)" }], }); @@ -2398,7 +2399,7 @@ Component({ this.setData({ [`messages[${currentAiMsgIndex}].parts[${currentParts.length - 1}].content`]: fullContent, }); - break; // 必须添加 break! + break; // 工具调用开始,push 一个 tool_call 类型的 part case "TOOL_CALL_START": fullContent = ""; @@ -2434,6 +2435,9 @@ Component({ this.setData({ [`messages[${currentAiMsgIndex}].parts[${toolCallIndex}].status`]: "success", }); + this.setData({ + [`messages[${currentAiMsgIndex}].parts[${toolCallIndex}].result`]: data.content, + }); break; case "RUN_ERROR": const agentErrorPart = { @@ -2463,44 +2467,44 @@ Component({ const tool = this.data.agentV2Config.tools.find((item) => item.name === toolCallName); // 只处理前端工具调用 if (tool) { - try { - // 调用工具处理函数 - const toolResult = await tool.handler(JSON.parse(args)); - // 处理成字符串 - const toolResultStr = JSON.stringify(toolResult); - // 调用成功,将结果添加到前端工具调用结果数组 - frontendToolsResult.push({ - toolCallId, - result: toolResultStr, - }); - // 更新工具调用状态为 success - this.setData({ - [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( - (item) => item.id === toolCallId - )}].status`]: "success", - }); - this.setData({ - [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( - (item) => item.id === toolCallId - )}].result`]: toolResultStr, - }); - } catch (e) { - frontendToolsResult.push({ - toolCallId, - result: `工具${toolCallName}调用失败:${e.message}`, - }); - // 更新工具调用状态为 failed - this.setData({ - [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( - (item) => item.id === toolCallId - )}].status`]: "failed", - }); - this.setData({ - [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( - (item) => item.id === toolCallId - )}].result`]: e.message, - }); - } + try { + // 调用工具处理函数 + const toolResult = await tool.handler(JSON.parse(args)); + // 处理成字符串 + const toolResultStr = JSON.stringify(toolResult); + // 调用成功,将结果添加到前端工具调用结果数组 + frontendToolsResult.push({ + toolCallId, + result: toolResultStr, + }); + // 更新工具调用状态为 success + this.setData({ + [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( + (item) => item.id === toolCallId + )}].status`]: "success", + }); + this.setData({ + [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( + (item) => item.id === toolCallId + )}].result`]: toolResultStr, + }); + } catch (e) { + frontendToolsResult.push({ + toolCallId, + result: `工具${toolCallName}调用失败:${e.message}`, + }); + // 更新工具调用状态为 failed + this.setData({ + [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( + (item) => item.id === toolCallId + )}].status`]: "failed", + }); + this.setData({ + [`messages[${currentAiMsgIndex}].parts[${currentParts.findIndex( + (item) => item.id === toolCallId + )}].result`]: e.message, + }); + } } } // 处理工具调用结果,发送给服务端 diff --git a/package-lock.json b/package-lock.json index d49cb7e..e01d9f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cloudbase-agent-ui", - "version": "1.15.2", + "version": "1.15.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cloudbase-agent-ui", - "version": "1.15.2", + "version": "1.15.3", "license": "MIT", "dependencies": { "standard-version": "^9.5.0" diff --git a/package.json b/package.json index c235d8a..2319ee8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cloudbase-agent-ui", - "version": "1.15.2", + "version": "1.15.3", "description": "微信小程序 Agent UI组件", "main": "index.js", "directories": {