支持 resources/list 的调度
This commit is contained in:
parent
c716cbc6ca
commit
8d549d17e2
@ -1,5 +1,9 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## [main] 0.0.7
|
||||||
|
- 优化页面布局,使得调试内容更加紧凑
|
||||||
|
- 扩大默认的上下文长度
|
||||||
|
- 增加「通用选项」,用于设置mcp服务器的最大的等待时间
|
||||||
|
|
||||||
## [main] 0.0.6
|
## [main] 0.0.6
|
||||||
- 修复部分因为服务器名称特殊字符而导致的保存实效的错误
|
- 修复部分因为服务器名称特殊字符而导致的保存实效的错误
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 4870215 */
|
font-family: "iconfont"; /* Project id 4870215 */
|
||||||
src: url('iconfont.woff2?t=1745774700883') format('woff2'),
|
src: url('iconfont.woff2?t=1746529081655') format('woff2'),
|
||||||
url('iconfont.woff?t=1745774700883') format('woff'),
|
url('iconfont.woff?t=1746529081655') format('woff'),
|
||||||
url('iconfont.ttf?t=1745774700883') format('truetype');
|
url('iconfont.ttf?t=1746529081655') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,18 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-timeout:before {
|
||||||
|
content: "\edf5";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-dui:before {
|
||||||
|
content: "\e627";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-cuo:before {
|
||||||
|
content: "\ed1a";
|
||||||
|
}
|
||||||
|
|
||||||
.icon-video:before {
|
.icon-video:before {
|
||||||
content: "\e865";
|
content: "\e865";
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -94,7 +94,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.main {
|
.main {
|
||||||
height: calc(100vh - 50px);
|
height: calc(100vh - 5px);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ if (!tabStorage.settings) {
|
|||||||
enableTools: [],
|
enableTools: [],
|
||||||
enableWebSearch: false,
|
enableWebSearch: false,
|
||||||
temperature: 0.7,
|
temperature: 0.7,
|
||||||
contextLength: 10,
|
contextLength: 20,
|
||||||
systemPrompt: ''
|
systemPrompt: ''
|
||||||
} as ChatSetting;
|
} as ChatSetting;
|
||||||
}
|
}
|
||||||
|
@ -70,20 +70,19 @@ function setActiveTab(index: number) {
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.main-panel-container {
|
.main-panel-container {
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: 800px;
|
min-width: 800px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-left: 20px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-panel {
|
.main-panel {
|
||||||
background-color: var(--sidebar);
|
background-color: var(--sidebar);
|
||||||
border-radius: 1.2em;
|
border-radius: 1.2em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 90%;
|
height: calc(100% - 35px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-tabs-container {
|
.scroll-tabs-container {
|
||||||
@ -92,13 +91,13 @@ function setActiveTab(index: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tabs-container {
|
.tabs-container {
|
||||||
height: 78px;
|
height: 30px;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
padding: 0 10px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs-container .el-scrollbar {
|
.tabs-container .el-scrollbar {
|
||||||
@ -107,12 +106,12 @@ function setActiveTab(index: number) {
|
|||||||
|
|
||||||
.tabs-container .tab {
|
.tabs-container .tab {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
margin: 5px;
|
margin-right: 5px;
|
||||||
font-size: 13px;
|
font-size: 12px;
|
||||||
width: 120px;
|
width: 120px;
|
||||||
border-radius: .5em;
|
border-radius: .5em;
|
||||||
background-color: var(--sidebar);
|
background-color: var(--sidebar);
|
||||||
padding: 10px;
|
padding: 3px 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
transition: var(--animation-3s);
|
transition: var(--animation-3s);
|
||||||
@ -160,11 +159,9 @@ function setActiveTab(index: number) {
|
|||||||
|
|
||||||
.tabs-container .add-button {
|
.tabs-container .add-button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 20px;
|
font-size: 15px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
border-radius: .5em;
|
border-radius: .5em;
|
||||||
height: 35px;
|
|
||||||
width: 35px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -6,11 +6,14 @@
|
|||||||
<span class="iconfont icon-file"></span>
|
<span class="iconfont icon-file"></span>
|
||||||
{{ t("resources") + t("module") }}
|
{{ t("resources") + t("module") }}
|
||||||
</h2>
|
</h2>
|
||||||
<h3><code>resources/templates/list</code></h3>
|
|
||||||
|
|
||||||
<ResourceTemplates
|
<ResourceListTemplates
|
||||||
:tab-id="props.tabId"
|
:tab-id="props.tabId"
|
||||||
></ResourceTemplates>
|
></ResourceListTemplates>
|
||||||
|
|
||||||
|
<ResourceList
|
||||||
|
:tab-id="props.tabId"
|
||||||
|
></ResourceList>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
@ -29,7 +32,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps } from 'vue';
|
import { defineProps } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import ResourceTemplates from './resource-templates.vue';
|
|
||||||
|
import ResourceListTemplates from './resource-list-templates.vue';
|
||||||
|
import ResourceList from './resource-list.vue';
|
||||||
|
|
||||||
import ResourceReader from './resouce-reader.vue';
|
import ResourceReader from './resouce-reader.vue';
|
||||||
import ResourceLogger from './resource-logger.vue';
|
import ResourceLogger from './resource-logger.vue';
|
||||||
|
|
||||||
@ -42,8 +48,6 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@ -122,21 +122,28 @@ const resetForm = () => {
|
|||||||
responseData.value = undefined;
|
responseData.value = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getUri() {
|
||||||
|
if (tabStorage.currentType === 'template') {
|
||||||
|
const fillFn = currentResource.value.fill;
|
||||||
|
const uri = fillFn(tabStorage.formData);
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetResource = resourcesManager.resources.find(resources => resources.name === tabStorage.currentResourceName);
|
||||||
|
return targetResource?.uri;
|
||||||
|
}
|
||||||
|
|
||||||
// 提交表单
|
// 提交表单
|
||||||
function handleSubmit() {
|
async function handleSubmit() {
|
||||||
const fillFn = currentResource.value.fill;
|
const uri = getUri();
|
||||||
const uri = fillFn(tabStorage.formData);
|
console.log(uri);
|
||||||
|
|
||||||
const bridge = useMessageBridge();
|
const bridge = useMessageBridge();
|
||||||
|
const { code, msg } = await bridge.commandRequest('resources/read', { resourceUri: uri });
|
||||||
|
|
||||||
bridge.addCommandListener('resources/read', (data: CasualRestAPI<ResourcesReadResponse>) => {
|
if (code === 200) {
|
||||||
tabStorage.lastResourceReadResponse = data.msg;
|
tabStorage.lastResourceReadResponse = msg;
|
||||||
}, { once: true });
|
}
|
||||||
|
|
||||||
bridge.postMessage({
|
|
||||||
command: 'resources/read',
|
|
||||||
data: { resourceUri: uri }
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听资源变化重置表单
|
// 监听资源变化重置表单
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<h3 class="resource-template">
|
||||||
|
<code>resources/templates/list</code>
|
||||||
|
<span
|
||||||
|
class="iconfont icon-restart"
|
||||||
|
@click="reloadResources({ first: false })"
|
||||||
|
></span>
|
||||||
|
</h3>
|
||||||
|
|
||||||
<div class="resource-template-container-scrollbar">
|
<div class="resource-template-container-scrollbar">
|
||||||
<el-scrollbar height="500px">
|
<el-scrollbar height="500px" v-if="resourcesManager.templates.length > 0">
|
||||||
<div class="resource-template-container">
|
<div class="resource-template-container">
|
||||||
<div
|
<div
|
||||||
class="item"
|
class="item"
|
||||||
:class="{ 'active': tabStorage.currentResourceName === template.name }"
|
:class="{ 'active': tabStorage.currentType === 'template' && tabStorage.currentResourceName === template.name }"
|
||||||
v-for="template of resourcesManager.templates"
|
v-for="template of resourcesManager.templates"
|
||||||
:key="template.name"
|
:key="template.name"
|
||||||
@click="handleClick(template)"
|
@click="handleClick(template)"
|
||||||
@ -14,21 +22,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
|
<div v-else style="padding: 10px;">
|
||||||
|
empty
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="resource-template-function-container">
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
@click="reloadResources({ first: false })"
|
|
||||||
>
|
|
||||||
{{ t('refresh') }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useMessageBridge } from '@/api/message-bridge';
|
import { useMessageBridge } from '@/api/message-bridge';
|
||||||
import { CasualRestAPI, ResourceTemplate, ResourceTemplatesListResponse } from '@/hook/type';
|
import { CasualRestAPI, ResourceTemplate, ResourceTemplatesListResponse } from '@/hook/type';
|
||||||
import { onMounted, onUnmounted, defineProps } from 'vue';
|
import { onMounted, onUnmounted, defineProps, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { resourcesManager, ResourceStorage } from './resources';
|
import { resourcesManager, ResourceStorage } from './resources';
|
||||||
import { tabs } from '../panel';
|
import { tabs } from '../panel';
|
||||||
@ -63,6 +66,7 @@ function reloadResources(option: { first: boolean }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleClick(template: ResourceTemplate) {
|
function handleClick(template: ResourceTemplate) {
|
||||||
|
tabStorage.currentType = 'template';
|
||||||
tabStorage.currentResourceName = template.name;
|
tabStorage.currentResourceName = template.name;
|
||||||
tabStorage.lastResourceReadResponse = undefined;
|
tabStorage.lastResourceReadResponse = undefined;
|
||||||
}
|
}
|
||||||
@ -73,11 +77,13 @@ onMounted(() => {
|
|||||||
commandCancel = bridge.addCommandListener('resources/templates/list', (data: CasualRestAPI<ResourceTemplatesListResponse>) => {
|
commandCancel = bridge.addCommandListener('resources/templates/list', (data: CasualRestAPI<ResourceTemplatesListResponse>) => {
|
||||||
resourcesManager.templates = data.msg.resourceTemplates || [];
|
resourcesManager.templates = data.msg.resourceTemplates || [];
|
||||||
|
|
||||||
const targetResource = resourcesManager.templates.find(template => template.name === tabStorage.currentResourceName);
|
if (tabStorage.currentType === 'template') {
|
||||||
if (targetResource === undefined) {
|
const targetResource = resourcesManager.templates.find(template => template.name === tabStorage.currentResourceName);
|
||||||
tabStorage.currentResourceName = resourcesManager.templates[0]?.name;
|
if (targetResource === undefined) {
|
||||||
tabStorage.lastResourceReadResponse = undefined;
|
tabStorage.currentResourceName = resourcesManager.templates[0]?.name;
|
||||||
}
|
tabStorage.lastResourceReadResponse = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
}, { once: false });
|
}, { once: false });
|
||||||
|
|
||||||
reloadResources({ first: true });
|
reloadResources({ first: true });
|
||||||
@ -88,10 +94,23 @@ onUnmounted(() => {
|
|||||||
commandCancel();
|
commandCancel();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
h3.resource-template {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3.resource-template .iconfont.icon-restart {
|
||||||
|
margin-left: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3.resource-template .iconfont.icon-restart:hover {
|
||||||
|
color: var(--main-color);
|
||||||
|
}
|
||||||
|
|
||||||
.resource-template-container-scrollbar {
|
.resource-template-container-scrollbar {
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
173
renderer/src/components/main-panel/resource/resource-list.vue
Normal file
173
renderer/src/components/main-panel/resource/resource-list.vue
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
<template>
|
||||||
|
<h3 class="resource-template">
|
||||||
|
<code>resources/list</code>
|
||||||
|
<span
|
||||||
|
class="iconfont icon-restart"
|
||||||
|
@click="reloadResources({ first: false })"
|
||||||
|
></span>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="resource-template-container-scrollbar">
|
||||||
|
<el-scrollbar height="500px">
|
||||||
|
<div class="resource-template-container">
|
||||||
|
<div
|
||||||
|
class="item"
|
||||||
|
:class="{ 'active': tabStorage.currentType === 'resource' && tabStorage.currentResourceName === resource.name }"
|
||||||
|
v-for="resource of resourcesManager.resources"
|
||||||
|
:key="resource.uri"
|
||||||
|
@click="handleClick(resource)"
|
||||||
|
>
|
||||||
|
<span>{{ resource.name }}</span>
|
||||||
|
<span>{{ resource.mimeType }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useMessageBridge } from '@/api/message-bridge';
|
||||||
|
import { CasualRestAPI, Resources, ResourcesListResponse } from '@/hook/type';
|
||||||
|
import { onMounted, onUnmounted, defineProps, ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { resourcesManager, ResourceStorage } from './resources';
|
||||||
|
import { tabs } from '../panel';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
const bridge = useMessageBridge();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
tabId: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const tab = tabs.content[props.tabId];
|
||||||
|
const tabStorage = tab.storage as ResourceStorage;
|
||||||
|
|
||||||
|
function reloadResources(option: { first: boolean }) {
|
||||||
|
bridge.postMessage({
|
||||||
|
command: 'resources/list'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!option.first) {
|
||||||
|
ElMessage({
|
||||||
|
message: t('finish-refresh'),
|
||||||
|
type: 'success',
|
||||||
|
duration: 3000,
|
||||||
|
showClose: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClick(resource: Resources) {
|
||||||
|
tabStorage.currentType = 'resource';
|
||||||
|
tabStorage.currentResourceName = resource.name;
|
||||||
|
tabStorage.lastResourceReadResponse = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let commandCancel: (() => void);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
commandCancel = bridge.addCommandListener('resources/list', (data: CasualRestAPI<ResourcesListResponse>) => {
|
||||||
|
resourcesManager.resources = data.msg.resources || [];
|
||||||
|
|
||||||
|
if (tabStorage.currentType === 'resource') {
|
||||||
|
const targetResource = resourcesManager.resources.find(resources => resources.name === tabStorage.currentResourceName);
|
||||||
|
if (targetResource === undefined) {
|
||||||
|
tabStorage.currentResourceName = resourcesManager.templates[0]?.name;
|
||||||
|
tabStorage.lastResourceReadResponse = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, { once: false });
|
||||||
|
|
||||||
|
reloadResources({ first: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (commandCancel){
|
||||||
|
commandCancel();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h3.resource-template {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3.resource-template .iconfont.icon-restart {
|
||||||
|
margin-left: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3.resource-template .iconfont.icon-restart:hover {
|
||||||
|
color: var(--main-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-container-scrollbar {
|
||||||
|
background-color: var(--background);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-radius: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-container {
|
||||||
|
height: fit-content;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-function-container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-function-container button {
|
||||||
|
width: 175px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-container > .item {
|
||||||
|
margin: 3px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: .3em;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
transition: var(--animation-3s);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-container > .item:hover {
|
||||||
|
background-color: var(--main-light-color);
|
||||||
|
transition: var(--animation-3s);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-container > .item.active {
|
||||||
|
background-color: var(--main-light-color);
|
||||||
|
transition: var(--animation-3s);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-container > .item > span:first-child {
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-template-container > .item > span:last-child {
|
||||||
|
opacity: 0.6;
|
||||||
|
font-size: 12.5px;
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -20,7 +20,20 @@
|
|||||||
>
|
>
|
||||||
<template v-if="!showRawJson">
|
<template v-if="!showRawJson">
|
||||||
<span v-for="(content, index) of tabStorage.lastResourceReadResponse?.contents || []" :key="index">
|
<span v-for="(content, index) of tabStorage.lastResourceReadResponse?.contents || []" :key="index">
|
||||||
{{ content.text }}
|
<span v-if="content.mimeType === 'image/png'">
|
||||||
|
<img
|
||||||
|
class="resource-list-image"
|
||||||
|
:src="getImageBlobUrlByBase64(content.blob || '', content.mimeType)"
|
||||||
|
:alt="content.text"
|
||||||
|
style="max-width: 100%; max-height: 300px;"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span v-if="content.mimeType === 'image/jpeg'">
|
||||||
|
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
{{ content.text }}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
@ -36,6 +49,7 @@ import { defineComponent, defineProps, computed, ref } from 'vue';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { tabs } from '../panel';
|
import { tabs } from '../panel';
|
||||||
import { ResourceStorage } from './resources';
|
import { ResourceStorage } from './resources';
|
||||||
|
import { getImageBlobUrlByBase64 } from '@/hook/util';
|
||||||
|
|
||||||
defineComponent({ name: 'resource-logger' });
|
defineComponent({ name: 'resource-logger' });
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -101,4 +115,8 @@ const formattedJson = computed(() => {
|
|||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
background-color: var(--sidebar);
|
background-color: var(--sidebar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resource-list-image {
|
||||||
|
cursor: unset;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -1,16 +1,19 @@
|
|||||||
import { ResourcesReadResponse, ResourceTemplate, ResourceTemplatesListResponse } from '@/hook/type';
|
import { ResourcesReadResponse, ResourceTemplate, Resources } from '@/hook/type';
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
|
||||||
export const resourcesManager = reactive<{
|
export const resourcesManager = reactive<{
|
||||||
current: ResourceTemplate | undefined
|
current: ResourceTemplate | undefined
|
||||||
templates: ResourceTemplate[]
|
templates: ResourceTemplate[],
|
||||||
|
resources: Resources[]
|
||||||
}>({
|
}>({
|
||||||
current: undefined,
|
current: undefined,
|
||||||
templates: []
|
templates: [],
|
||||||
|
resources: []
|
||||||
});
|
});
|
||||||
|
|
||||||
export interface ResourceStorage {
|
export interface ResourceStorage {
|
||||||
|
currentType: 'resource' | 'template';
|
||||||
currentResourceName: string;
|
currentResourceName: string;
|
||||||
lastResourceReadResponse?: ResourcesReadResponse;
|
lastResourceReadResponse?: ResourcesReadResponse;
|
||||||
formData: Record<string, any>;
|
formData: Record<string, any>;
|
||||||
|
@ -143,8 +143,14 @@ const resetForm = () => {
|
|||||||
|
|
||||||
async function handleExecute() {
|
async function handleExecute() {
|
||||||
if (!currentTool.value) return;
|
if (!currentTool.value) return;
|
||||||
const toolResponse = await callTool(tabStorage.currentToolName, tabStorage.formData);
|
loading.value = true;
|
||||||
tabStorage.lastToolCallResponse = toolResponse;
|
try {
|
||||||
|
tabStorage.lastToolCallResponse = undefined;
|
||||||
|
const toolResponse = await callTool(tabStorage.currentToolName, tabStorage.formData);
|
||||||
|
tabStorage.lastToolCallResponse = toolResponse;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => tabStorage.currentToolName, () => {
|
watch(() => tabStorage.currentToolName, () => {
|
||||||
|
@ -15,6 +15,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- resources/list -->
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="tool-list-function-container">
|
<div class="tool-list-function-container">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
|
@ -40,7 +40,7 @@ import { defineComponent, defineProps, computed, ref } from 'vue';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { tabs } from '../panel';
|
import { tabs } from '../panel';
|
||||||
import { ToolStorage } from './tools';
|
import { ToolStorage } from './tools';
|
||||||
import { markdownToHtml } from '../chat/markdown/markdown';
|
import { useMessageBridge } from '@/api/message-bridge';
|
||||||
|
|
||||||
defineComponent({ name: 'tool-logger' });
|
defineComponent({ name: 'tool-logger' });
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { useMessageBridge } from '@/api/message-bridge';
|
import { useMessageBridge } from '@/api/message-bridge';
|
||||||
|
import { mcpSetting } from '@/hook/mcp';
|
||||||
import { ToolsListResponse, ToolCallResponse, CasualRestAPI } from '@/hook/type';
|
import { ToolsListResponse, ToolCallResponse, CasualRestAPI } from '@/hook/type';
|
||||||
import { pinkLog } from '@/views/setting/util';
|
import { pinkLog } from '@/views/setting/util';
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
@ -36,7 +37,10 @@ export function callTool(toolName: string, toolArgs: Record<string, any>) {
|
|||||||
command: 'tools/call',
|
command: 'tools/call',
|
||||||
data: {
|
data: {
|
||||||
toolName,
|
toolName,
|
||||||
toolArgs: JSON.parse(JSON.stringify(toolArgs))
|
toolArgs: JSON.parse(JSON.stringify(toolArgs)),
|
||||||
|
callToolOption: {
|
||||||
|
timeout: mcpSetting.timeout * 1000
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<div class="connected-status-container"
|
<div class="connected-status-container"
|
||||||
id="connected-status-container"
|
id="connected-status-container"
|
||||||
@click.stop="toggleConnectionPanel()"
|
@click.stop="toggleConnectionPanel()"
|
||||||
|
:class="{ 'connected': connectionResult.success }"
|
||||||
>
|
>
|
||||||
<span class="mcp-server-info">
|
<span class="mcp-server-info">
|
||||||
<el-tooltip
|
<el-tooltip
|
||||||
@ -14,12 +15,14 @@
|
|||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</span>
|
</span>
|
||||||
<span class="connect-status">
|
<span class="connect-status">
|
||||||
<span
|
<span v-if="connectionResult.success">
|
||||||
class="status-circle"
|
<span class="iconfont icon-connect"></span>
|
||||||
:class="statusColorStyle"
|
<span class="iconfont icon-dui"></span>
|
||||||
>
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
<span class="iconfont icon-connect"></span>
|
||||||
|
<span class="iconfont icon-cuo"></span>
|
||||||
</span>
|
</span>
|
||||||
<span class="status-string">{{ statusString }}</span>
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -35,22 +38,6 @@ defineComponent({ name: 'connected' });
|
|||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const statusString = computed(() => {
|
|
||||||
if (connectionResult.success) {
|
|
||||||
return t('connected');
|
|
||||||
} else {
|
|
||||||
return t('disconnected');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const statusColorStyle = computed(() => {
|
|
||||||
if (connectionResult.success) {
|
|
||||||
return 'connected-color';
|
|
||||||
} else {
|
|
||||||
return 'disconnected-color';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const fullDisplayServerName = computed(() => {
|
const fullDisplayServerName = computed(() => {
|
||||||
return connectionResult.serverInfo.name + '/' + connectionResult.serverInfo.version;
|
return connectionResult.serverInfo.name + '/' + connectionResult.serverInfo.version;
|
||||||
});
|
});
|
||||||
@ -88,9 +75,13 @@ function toggleConnectionPanel() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.connected .status-circle {
|
||||||
|
background-color: var(--el-color-success) !important;
|
||||||
|
}
|
||||||
|
|
||||||
.connected-color {
|
.connected .connect-status {
|
||||||
background-color: #21DA49;
|
border: 1px solid var(--el-color-success) !important;
|
||||||
|
color: var(--el-color-success) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.disconnected-color {
|
.disconnected-color {
|
||||||
@ -100,8 +91,8 @@ function toggleConnectionPanel() {
|
|||||||
.status-circle {
|
.status-circle {
|
||||||
height: 12px;
|
height: 12px;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
margin-right: 8px;
|
|
||||||
border-radius: 99%;
|
border-radius: 99%;
|
||||||
|
background-color: var(--main-color);
|
||||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 0 4px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +114,13 @@ function toggleConnectionPanel() {
|
|||||||
.connected-status-container .connect-status {
|
.connected-status-container .connect-status {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 20px;
|
justify-content: space-between;
|
||||||
|
margin-top: 10px;
|
||||||
|
border-radius: .5em;
|
||||||
|
padding: 5px 10px;
|
||||||
|
width: 30px;
|
||||||
|
border: 1px solid var(--main-color);
|
||||||
|
color: var(--main-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.connected-status-container:hover {
|
.connected-status-container:hover {
|
||||||
@ -148,7 +145,10 @@ function toggleConnectionPanel() {
|
|||||||
.mcp-server-info .name {
|
.mcp-server-info .name {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
max-width: 60px;
|
width: 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
white-space: wrap;
|
white-space: wrap;
|
||||||
background-color: #f39a6d;
|
background-color: #f39a6d;
|
||||||
padding: 5px 12px;
|
padding: 5px 12px;
|
||||||
|
@ -35,6 +35,8 @@ function clickLogo() {
|
|||||||
.simple-logo {
|
.simple-logo {
|
||||||
height: 73px;
|
height: 73px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-drag: none;
|
-webkit-user-drag: none;
|
||||||
@ -47,7 +49,7 @@ function clickLogo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.simple-logo .iconfont {
|
.simple-logo .iconfont {
|
||||||
font-size: 48px;
|
font-size: 38px;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -1,3 +1,5 @@
|
|||||||
|
import { reactive } from "vue";
|
||||||
|
|
||||||
interface TypeAble {
|
interface TypeAble {
|
||||||
type: string;
|
type: string;
|
||||||
}
|
}
|
||||||
@ -28,3 +30,7 @@ export function normaliseJavascriptType(type: string) {
|
|||||||
return 'string';
|
return 'string';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const mcpSetting = reactive({
|
||||||
|
timeout: 60,
|
||||||
|
});
|
@ -3,6 +3,7 @@ import { llmManager, llms } from "@/views/setting/llm";
|
|||||||
import { pinkLog } from "@/views/setting/util";
|
import { pinkLog } from "@/views/setting/util";
|
||||||
import I18n from '@/i18n/index';
|
import I18n from '@/i18n/index';
|
||||||
import { userHasReadGuide } from "@/components/guide/tour";
|
import { userHasReadGuide } from "@/components/guide/tour";
|
||||||
|
import { mcpSetting } from "./mcp";
|
||||||
|
|
||||||
export async function loadSetting() {
|
export async function loadSetting() {
|
||||||
const bridge = useMessageBridge();
|
const bridge = useMessageBridge();
|
||||||
@ -16,8 +17,9 @@ export async function loadSetting() {
|
|||||||
const persistConfig = data.msg;
|
const persistConfig = data.msg;
|
||||||
pinkLog('配置加载成功');
|
pinkLog('配置加载成功');
|
||||||
|
|
||||||
llmManager.currentModelIndex = persistConfig.MODEL_INDEX;
|
llmManager.currentModelIndex = persistConfig.MODEL_INDEX || 0;
|
||||||
I18n.global.locale.value = persistConfig.LANG;
|
I18n.global.locale.value = persistConfig.LANG || 'zh';
|
||||||
|
mcpSetting.timeout = persistConfig.MCP_TIMEOUT_SEC || 60;
|
||||||
|
|
||||||
persistConfig.LLM_INFO.forEach((element: any) => {
|
persistConfig.LLM_INFO.forEach((element: any) => {
|
||||||
llms.push(element);
|
llms.push(element);
|
||||||
@ -48,7 +50,8 @@ export function saveSetting(saveHandler?: () => void) {
|
|||||||
const saveConfig = {
|
const saveConfig = {
|
||||||
MODEL_INDEX: llmManager.currentModelIndex,
|
MODEL_INDEX: llmManager.currentModelIndex,
|
||||||
LLM_INFO: JSON.parse(JSON.stringify(llms)),
|
LLM_INFO: JSON.parse(JSON.stringify(llms)),
|
||||||
LANG: I18n.global.locale.value
|
LANG: I18n.global.locale.value,
|
||||||
|
MCP_TIMEOUT_SEC: mcpSetting.timeout
|
||||||
};
|
};
|
||||||
|
|
||||||
bridge.addCommandListener('setting/save', data => {
|
bridge.addCommandListener('setting/save', data => {
|
||||||
|
@ -21,6 +21,8 @@ export interface Content {
|
|||||||
uri: string;
|
uri: string;
|
||||||
mimeType: string;
|
mimeType: string;
|
||||||
text: string;
|
text: string;
|
||||||
|
blob?: string;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MessageContent {
|
export interface MessageContent {
|
||||||
@ -59,12 +61,18 @@ export interface ResourceTemplate {
|
|||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Resources {
|
||||||
|
uri: string;
|
||||||
|
name: string;
|
||||||
|
mimeType: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ResourceTemplatesListResponse {
|
export interface ResourceTemplatesListResponse {
|
||||||
resourceTemplates: ResourceTemplate[]
|
resourceTemplates: ResourceTemplate[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResourcesListResponse {
|
export interface ResourcesListResponse {
|
||||||
resources: any[]; // 根据示例返回空数组,可进一步定义具体类型
|
resources: Resources[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResourcesReadResponse {
|
export interface ResourcesReadResponse {
|
||||||
|
@ -64,6 +64,12 @@ export async function getBlobUrlByFilename(filename: string) {
|
|||||||
mimeType = 'image/svg+xml';
|
mimeType = 'image/svg+xml';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const blobUrl = getImageBlobUrlByBase64(base64String, mimeType, filename);
|
||||||
|
return blobUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getImageBlobUrlByBase64(base64String: string, mimeType: string, cacheKey?: string) {
|
||||||
const byteCharacters = atob(base64String);
|
const byteCharacters = atob(base64String);
|
||||||
const byteNumbers = new Array(byteCharacters.length);
|
const byteNumbers = new Array(byteCharacters.length);
|
||||||
for (let i = 0; i < byteCharacters.length; i++) {
|
for (let i = 0; i < byteCharacters.length; i++) {
|
||||||
@ -73,6 +79,8 @@ export async function getBlobUrlByFilename(filename: string) {
|
|||||||
const blob = new Blob([byteArray], { type: mimeType });
|
const blob = new Blob([byteArray], { type: mimeType });
|
||||||
const blobUrl = URL.createObjectURL(blob);
|
const blobUrl = URL.createObjectURL(blob);
|
||||||
// 将结果存入缓存
|
// 将结果存入缓存
|
||||||
blobUrlCache.set(filename, blobUrl);
|
if (cacheKey) {
|
||||||
|
blobUrlCache.set(cacheKey, blobUrl);
|
||||||
|
}
|
||||||
return blobUrl;
|
return blobUrl;
|
||||||
}
|
}
|
@ -149,5 +149,7 @@
|
|||||||
"add-system-prompt.name-placeholder": "عنوان prompt المخصص",
|
"add-system-prompt.name-placeholder": "عنوان prompt المخصص",
|
||||||
"enter-message-dot": "أدخل الرسالة...",
|
"enter-message-dot": "أدخل الرسالة...",
|
||||||
"generate-answer": "جارٍ إنشاء الإجابة",
|
"generate-answer": "جارٍ إنشاء الإجابة",
|
||||||
"choose-presetting": "اختر الإعداد المسبق"
|
"choose-presetting": "اختر الإعداد المسبق",
|
||||||
|
"cwd": "دليل التنفيذ",
|
||||||
|
"mcp-server-timeout": "أطول وقت لاستدعاء أداة MCP"
|
||||||
}
|
}
|
@ -149,5 +149,7 @@
|
|||||||
"add-system-prompt.name-placeholder": "Titel für benutzerdefinierte Eingabeaufforderung",
|
"add-system-prompt.name-placeholder": "Titel für benutzerdefinierte Eingabeaufforderung",
|
||||||
"enter-message-dot": "Nachricht eingeben...",
|
"enter-message-dot": "Nachricht eingeben...",
|
||||||
"generate-answer": "Antwort wird generiert",
|
"generate-answer": "Antwort wird generiert",
|
||||||
"choose-presetting": "Voreinstellung auswählen"
|
"choose-presetting": "Voreinstellung auswählen",
|
||||||
|
"cwd": "Ausführungsverzeichnis",
|
||||||
|
"mcp-server-timeout": "Maximale Aufrufzeit des MCP-Tools"
|
||||||
}
|
}
|
@ -149,5 +149,7 @@
|
|||||||
"add-system-prompt.name-placeholder": "Title for custom prompt",
|
"add-system-prompt.name-placeholder": "Title for custom prompt",
|
||||||
"enter-message-dot": "Enter message...",
|
"enter-message-dot": "Enter message...",
|
||||||
"generate-answer": "Generating answer",
|
"generate-answer": "Generating answer",
|
||||||
"choose-presetting": "Select preset"
|
"choose-presetting": "Select preset",
|
||||||
|
"cwd": "Execution directory",
|
||||||
|
"mcp-server-timeout": "Maximum call time of MCP tool"
|
||||||
}
|
}
|
@ -149,5 +149,7 @@
|
|||||||
"add-system-prompt.name-placeholder": "Titre de l'invite personnalisée",
|
"add-system-prompt.name-placeholder": "Titre de l'invite personnalisée",
|
||||||
"enter-message-dot": "Entrez un message...",
|
"enter-message-dot": "Entrez un message...",
|
||||||
"generate-answer": "Génération de la réponse",
|
"generate-answer": "Génération de la réponse",
|
||||||
"choose-presetting": "Sélectionner un préréglage"
|
"choose-presetting": "Sélectionner un préréglage",
|
||||||
|
"cwd": "Répertoire d'exécution",
|
||||||
|
"mcp-server-timeout": "Temps d'appel maximum de l'outil MCP"
|
||||||
}
|
}
|
@ -149,5 +149,7 @@
|
|||||||
"add-system-prompt.name-placeholder": "カスタムプロンプトのタイトル",
|
"add-system-prompt.name-placeholder": "カスタムプロンプトのタイトル",
|
||||||
"enter-message-dot": "メッセージを入力...",
|
"enter-message-dot": "メッセージを入力...",
|
||||||
"generate-answer": "回答を生成中",
|
"generate-answer": "回答を生成中",
|
||||||
"choose-presetting": "プリセットを選択"
|
"choose-presetting": "プリセットを選択",
|
||||||
|
"cwd": "実行ディレクトリ",
|
||||||
|
"mcp-server-timeout": "MCPツールの最大呼び出し時間"
|
||||||
}
|
}
|
@ -149,5 +149,7 @@
|
|||||||
"add-system-prompt.name-placeholder": "사용자 지정 프롬프트 제목",
|
"add-system-prompt.name-placeholder": "사용자 지정 프롬프트 제목",
|
||||||
"enter-message-dot": "메시지를 입력하세요...",
|
"enter-message-dot": "메시지를 입력하세요...",
|
||||||
"generate-answer": "답변 생성 중",
|
"generate-answer": "답변 생성 중",
|
||||||
"choose-presetting": "프리셋 선택"
|
"choose-presetting": "프리셋 선택",
|
||||||
|
"cwd": "실행 디렉터리",
|
||||||
|
"mcp-server-timeout": "MCP 도구 최대 호출 시간"
|
||||||
}
|
}
|
@ -149,5 +149,7 @@
|
|||||||
"add-system-prompt.name-placeholder": "Заголовок пользовательского prompt",
|
"add-system-prompt.name-placeholder": "Заголовок пользовательского prompt",
|
||||||
"enter-message-dot": "Введите сообщение...",
|
"enter-message-dot": "Введите сообщение...",
|
||||||
"generate-answer": "Генерация ответа",
|
"generate-answer": "Генерация ответа",
|
||||||
"choose-presetting": "Выбрать预设"
|
"choose-presetting": "Выбрать预设",
|
||||||
|
"cwd": "Каталог выполнения",
|
||||||
|
"mcp-server-timeout": "Максимальное время вызова инструмента MCP"
|
||||||
}
|
}
|
@ -149,5 +149,7 @@
|
|||||||
"add-system-prompt.name-placeholder": "输入自定义 prompt 的标题",
|
"add-system-prompt.name-placeholder": "输入自定义 prompt 的标题",
|
||||||
"enter-message-dot": "输入消息...",
|
"enter-message-dot": "输入消息...",
|
||||||
"generate-answer": "正在生成答案",
|
"generate-answer": "正在生成答案",
|
||||||
"choose-presetting": "选择预设"
|
"choose-presetting": "选择预设",
|
||||||
|
"cwd": "执行目录",
|
||||||
|
"mcp-server-timeout": "MCP工具最长调用时间"
|
||||||
}
|
}
|
@ -149,5 +149,7 @@
|
|||||||
"add-system-prompt.name-placeholder": "自定義提示的標題",
|
"add-system-prompt.name-placeholder": "自定義提示的標題",
|
||||||
"enter-message-dot": "輸入訊息...",
|
"enter-message-dot": "輸入訊息...",
|
||||||
"generate-answer": "正在生成答案",
|
"generate-answer": "正在生成答案",
|
||||||
"choose-presetting": "選擇預設"
|
"choose-presetting": "選擇預設",
|
||||||
|
"cwd": "執行目錄",
|
||||||
|
"mcp-server-timeout": "MCP工具最長調用時間"
|
||||||
}
|
}
|
@ -6,7 +6,7 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
OpenMCP Client 0.0.5 由 OpenMCP@<a href="https://www.zhihu.com/people/can-meng-zhong-de-che-xian">锦恢</a> 开发
|
OpenMCP Client 0.0.7 由 OpenMCP@<a href="https://www.zhihu.com/people/can-meng-zhong-de-che-xian">锦恢</a> 开发
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -6,13 +6,13 @@
|
|||||||
<el-form :model="connectionArgs" :rules="rules" ref="stdioForm">
|
<el-form :model="connectionArgs" :rules="rules" ref="stdioForm">
|
||||||
<el-form-item prop="commandString">
|
<el-form-item prop="commandString">
|
||||||
<div class="input-with-label">
|
<div class="input-with-label">
|
||||||
<span class="input-label">命令</span>
|
<span class="input-label">{{ t("command") }}</span>
|
||||||
<el-input v-model="connectionArgs.commandString" placeholder="mcp run <your script>"></el-input>
|
<el-input v-model="connectionArgs.commandString" placeholder="mcp run <your script>"></el-input>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="cwd">
|
<el-form-item prop="cwd">
|
||||||
<div class="input-with-label">
|
<div class="input-with-label">
|
||||||
<span class="input-label">执行目录</span>
|
<span class="input-label">{{ t('cwd') }}</span>
|
||||||
<el-input v-model="connectionArgs.cwd" placeholder="cwd, 可为空"></el-input>
|
<el-input v-model="connectionArgs.cwd" placeholder="cwd, 可为空"></el-input>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -139,6 +139,7 @@ function chooseDebugMode(index: number) {
|
|||||||
|
|
||||||
.debug-welcome {
|
.debug-welcome {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
height: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.debug-option.disable {
|
.debug-option.disable {
|
||||||
|
@ -14,6 +14,19 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-option">
|
||||||
|
<span>
|
||||||
|
<span class="iconfont icon-timeout"></span>
|
||||||
|
<span class="option-title">{{ t('mcp-server-timeout') }} (sec)</span>
|
||||||
|
</span>
|
||||||
|
<div style="width: 200px;">
|
||||||
|
<el-slider
|
||||||
|
v-model="mcpSetting.timeout"
|
||||||
|
:min="10" :max="10000" :step="1"
|
||||||
|
@change="safeSaveSetting" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -21,6 +34,8 @@
|
|||||||
import { defineComponent, ref } from 'vue';
|
import { defineComponent, ref } from 'vue';
|
||||||
import { languageSetting } from './language';
|
import { languageSetting } from './language';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { mcpSetting } from '@/hook/mcp';
|
||||||
|
import { debounce } from 'lodash';
|
||||||
import { saveSetting } from '@/hook/setting';
|
import { saveSetting } from '@/hook/setting';
|
||||||
|
|
||||||
defineComponent({ name: 'appearance' });
|
defineComponent({ name: 'appearance' });
|
||||||
@ -29,7 +44,11 @@ const { t, locale } = useI18n();
|
|||||||
|
|
||||||
const currentLanguage = ref('简体中文');
|
const currentLanguage = ref('简体中文');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function onlanguagechange(code: string) {
|
function onlanguagechange(code: string) {
|
||||||
|
console.log('enter lang change');
|
||||||
|
|
||||||
const option = languageSetting.options.find(item => item.value === code);
|
const option = languageSetting.options.find(item => item.value === code);
|
||||||
if (option) {
|
if (option) {
|
||||||
currentLanguage.value = option.text;
|
currentLanguage.value = option.text;
|
||||||
@ -38,6 +57,12 @@ function onlanguagechange(code: string) {
|
|||||||
|
|
||||||
saveSetting();
|
saveSetting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const safeSaveSetting = debounce(() => {
|
||||||
|
saveSetting();
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style></style>
|
<style></style>
|
@ -97,6 +97,8 @@ export class ClientController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const resource = await client.readResource(option.resourceUri);
|
const resource = await client.readResource(option.resourceUri);
|
||||||
|
console.log(resource);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: 200,
|
code: 200,
|
||||||
msg: resource
|
msg: resource
|
||||||
@ -130,7 +132,8 @@ export class ClientController {
|
|||||||
|
|
||||||
const toolResult = await client.callTool({
|
const toolResult = await client.callTool({
|
||||||
name: option.toolName,
|
name: option.toolName,
|
||||||
arguments: option.toolArgs
|
arguments: option.toolArgs,
|
||||||
|
callToolOption: option.callToolOption
|
||||||
});
|
});
|
||||||
|
|
||||||
// console.log(JSON.stringify(toolResult, null, 2));
|
// console.log(JSON.stringify(toolResult, null, 2));
|
||||||
|
@ -41,7 +41,8 @@ export class McpClient {
|
|||||||
this.transport = new StdioClientTransport({
|
this.transport = new StdioClientTransport({
|
||||||
command: this.options.command || '',
|
command: this.options.command || '',
|
||||||
args: this.options.args || [],
|
args: this.options.args || [],
|
||||||
cwd: this.options.cwd || process.cwd()
|
cwd: this.options.cwd || process.cwd(),
|
||||||
|
stderr: 'pipe'
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -117,8 +118,10 @@ export class McpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 调用工具
|
// 调用工具
|
||||||
public async callTool(options: { name: string; arguments: Record<string, any> }) {
|
public async callTool(options: { name: string; arguments: Record<string, any>, callToolOption?: any }) {
|
||||||
return await this.client.callTool(options);
|
|
||||||
|
const { callToolOption, ...methodArgs } = options;
|
||||||
|
return await this.client.callTool(methodArgs, undefined, callToolOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ function getDefaultLanguage() {
|
|||||||
const DEFAULT_CONFIG: IConfig = {
|
const DEFAULT_CONFIG: IConfig = {
|
||||||
MODEL_INDEX: 0,
|
MODEL_INDEX: 0,
|
||||||
LLM_INFO: llms,
|
LLM_INFO: llms,
|
||||||
LANG: getDefaultLanguage()
|
LANG: getDefaultLanguage(), MCP_TIMEOUT_SEC: 60
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
"currentIndex": 0,
|
"currentIndex": 0,
|
||||||
"tabs": []
|
"tabs": [
|
||||||
|
{
|
||||||
|
"name": "Blank test 1",
|
||||||
|
"icon": "icon-blank",
|
||||||
|
"type": "blank",
|
||||||
|
"componentIndex": -1,
|
||||||
|
"storage": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user