fix(site): add MCP tools for query examples and jump examples (#3623)
This commit is contained in:
parent
41b9fbaade
commit
96cd780f26
|
@ -10,7 +10,7 @@
|
|||
<div class="right-panel" :class="{ collapsed: !showTinyRobot }">
|
||||
<tiny-robot-chat />
|
||||
</div>
|
||||
<IconAi @click="handleShowTinyRobot" class="style-settings-icon"></IconAi>
|
||||
<IconAi v-show="!showTinyRobot" @click="handleShowTinyRobot" class="style-settings-icon"></IconAi>
|
||||
<tiny-dialog-box
|
||||
v-model:visible="boxVisibility"
|
||||
:close-on-click-modal="false"
|
||||
|
@ -136,7 +136,7 @@ const handleShowTinyRobot = () => {
|
|||
padding: 34px 0 0;
|
||||
}
|
||||
}
|
||||
.right-panel {
|
||||
.right-panel:not(.collapsed) {
|
||||
:deep(.tr-container) {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<tr-container v-model:show="showTinyRobot" v-model:fullscreen="fullscreen">
|
||||
<tr-bubble-provider :message-renderers="messageRenderers">
|
||||
<div v-if="showMessages.length === 0">
|
||||
<div class="robot-top-msg" v-if="showMessages.length === 0">
|
||||
<tr-welcome title="智能助手" description="您好,我是Opentiny AI智能助手" :icon="welcomeIcon">
|
||||
<template #footer>
|
||||
<div class="welcome-footer"></div>
|
||||
|
@ -17,7 +17,8 @@
|
|||
@item-click="handlePromptItemClick"
|
||||
></tr-prompts>
|
||||
</div>
|
||||
<tr-bubble-list v-else :items="showMessages" :roles="roles" auto-scroll> </tr-bubble-list>
|
||||
<tr-bubble-list v-else class="robot-top-msg markdown-body" :items="showMessages" :roles="roles" auto-scroll>
|
||||
</tr-bubble-list>
|
||||
</tr-bubble-provider>
|
||||
|
||||
<template #footer>
|
||||
|
@ -172,6 +173,11 @@ watch(() => messages.value[messages.value.length - 1]?.content, scrollToBottom)
|
|||
height: 600px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
/** 聊天顶部要撑开空间 */
|
||||
.robot-top-msg {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -22,8 +22,13 @@ export const useTinyRobot = () => {
|
|||
|
||||
const promptItems = [
|
||||
{
|
||||
label: '智能操作网页',
|
||||
description: '帮我选中最贵的手机商品',
|
||||
label: '快速跳到文档',
|
||||
description: '帮我切换到国际化指南',
|
||||
icon: h('span', { style: { fontSize: '18px' } }, '🕹')
|
||||
},
|
||||
{
|
||||
label: '快速跳到组件',
|
||||
description: '帮我切换到 Select 组件',
|
||||
icon: h('span', { style: { fontSize: '18px' } }, '🕹')
|
||||
}
|
||||
]
|
||||
|
@ -54,14 +59,24 @@ export const useTinyRobot = () => {
|
|||
const suggestionPillItems = [
|
||||
{
|
||||
id: '1',
|
||||
text: '帮我选中最贵的手机商品',
|
||||
icon: h('span', { style: { fontSize: '18px' } }, '🕹')
|
||||
text: 'Select',
|
||||
icon: h('span', { style: { fontSize: '18px' } }, '🧩')
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
text: '表格',
|
||||
icon: h('span', { style: { fontSize: '18px' } }, '🧩')
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
text: '树组件',
|
||||
icon: h('span', { style: { fontSize: '18px' } }, '🧩')
|
||||
}
|
||||
]
|
||||
|
||||
function handleSuggestionPillItemClick(item: SuggestionItem) {
|
||||
if (item.id === '1') {
|
||||
let templateText = `请对 [目标组件] ,执行 [操作]`
|
||||
let templateText = `帮我跳转到 [目标组件]`
|
||||
let currentInitialValue = { 目标组件: item.text, 操作: '' }
|
||||
|
||||
if (senderRef.value) {
|
||||
|
|
|
@ -2,6 +2,9 @@ import { genMenus } from '../menus'
|
|||
import { z } from 'zod'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
// 组件页面的右上导航的数据回调函数
|
||||
export const cmpAnchorDataCallback = { value: null }
|
||||
|
||||
export const createGlobalMcpTool = (server) => {
|
||||
const router = useRouter()
|
||||
server.registerResource(
|
||||
|
@ -26,11 +29,13 @@ export const createGlobalMcpTool = (server) => {
|
|||
'swtich-router',
|
||||
{
|
||||
title: 'router',
|
||||
description: '可以帮用户跳转页面,比如:跳转到组件文档页面和API文档页面',
|
||||
description: '可以帮用户跳转到文档页面,组件示例的总页面或组件API文档页面,或组件库的概览页面',
|
||||
inputSchema: {
|
||||
key: z.string().describe('跳转页面路径'),
|
||||
type: z.enum(['components', 'docs', 'overview', 'features']).describe('跳转页面类型'),
|
||||
isOpenApi: z.boolean().describe('是否打开API文档')
|
||||
type: z
|
||||
.enum(['components', 'docs', 'overview', 'features'])
|
||||
.describe('跳转页面类型,比如:组件的页面,文档的页面,组件的概览页面'),
|
||||
isOpenApi: z.boolean().describe('跳转到组件页面时,是否打开API文档')
|
||||
}
|
||||
},
|
||||
async ({ key, type, isOpenApi }) => {
|
||||
|
@ -51,6 +56,49 @@ export const createGlobalMcpTool = (server) => {
|
|||
}
|
||||
)
|
||||
|
||||
server.registerTool(
|
||||
'get-component-demos',
|
||||
{
|
||||
title: '查询全部示例的信息',
|
||||
description:
|
||||
'查询当前组件的全部示例信息,demos信息。返回值是一个数组,其中每一项的 demoId 属性是示例的键,通过键可以跳转到该示例。desc属性是示例的详细描述。',
|
||||
inputSchema: {}
|
||||
},
|
||||
async () => {
|
||||
// 通知组件页面返回右侧导航的数据
|
||||
if (cmpAnchorDataCallback.value != null) {
|
||||
const links = cmpAnchorDataCallback.value()
|
||||
|
||||
return {
|
||||
content: [{ type: 'text', text: JSON.stringify(links) }]
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
content: [{ type: 'text', text: '找不到示例' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
server.registerTool(
|
||||
'jump-to-demo',
|
||||
{
|
||||
title: '跳转到组件的示例demo',
|
||||
description: '根据参数demoId, 跳转到指定的示例demo。',
|
||||
inputSchema: {
|
||||
demoId: z.string().describe('示例的id,唯一标识。')
|
||||
}
|
||||
},
|
||||
async ({ demoId }) => {
|
||||
// 通知组件页面返回右侧导航的数据
|
||||
location.hash = '#' + demoId
|
||||
|
||||
return {
|
||||
content: [{ type: 'text', text: '跳转示例成功' }]
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// 长任务示例
|
||||
server.registerTool(
|
||||
'long-task',
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, computed, watch, onMounted, nextTick, ref } from 'vue'
|
||||
import { reactive, computed, watch, onMounted, nextTick, ref, onUnmounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { TinyTabs, TinyTabItem } from '@opentiny/vue'
|
||||
import { debounce } from '@opentiny/utils'
|
||||
|
@ -106,6 +106,7 @@ import ApiDocs from '../../components/api-docs.vue'
|
|||
import McpDocs from '../../components/mcp-docs.vue'
|
||||
import useTasksFinish from '../../composable/useTasksFinish'
|
||||
import { appData } from '../../tools/appData'
|
||||
import { cmpAnchorDataCallback } from '../../tools/globalMcpTool'
|
||||
|
||||
const props = defineProps({ loadData: {}, appMode: {}, demoKey: {} })
|
||||
|
||||
|
@ -442,6 +443,11 @@ const handleAnchorClick = (e, data) => {
|
|||
}
|
||||
}
|
||||
|
||||
cmpAnchorDataCallback.value = () => state.currJson.demos
|
||||
onUnmounted(() => {
|
||||
cmpAnchorDataCallback.value = null
|
||||
})
|
||||
|
||||
defineExpose({ loadPage })
|
||||
</script>
|
||||
|
||||
|
|
Loading…
Reference in New Issue