push save MVP to 95%
This commit is contained in:
parent
03d79d0222
commit
3976670295
4
.gitignore
vendored
4
.gitignore
vendored
@ -4,4 +4,6 @@ node_modules
|
||||
.vscode-test/
|
||||
*.vsix
|
||||
.env
|
||||
resources
|
||||
resources
|
||||
.DS_Store
|
||||
.exe
|
@ -1,5 +0,0 @@
|
||||
import { defineConfig } from '@vscode/test-cli';
|
||||
|
||||
export default defineConfig({
|
||||
files: 'out/test/**/*.test.js',
|
||||
});
|
@ -1,5 +1,8 @@
|
||||
# Change Log
|
||||
|
||||
## [main] 0.0.5
|
||||
- 支持对已经打开过的文件项目进行管理
|
||||
|
||||
## [main] 0.0.4
|
||||
- 修复选择模型后点击确认跳转回 deepseek 的 bug
|
||||
- 修复 mcp 项目初始化点击工具全部都是空的 bug
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "openmcp",
|
||||
"displayName": "OpenMCP",
|
||||
"description": "An all in one MCP Client/TestTool",
|
||||
"version": "0.0.4",
|
||||
"version": "0.0.5",
|
||||
"publisher": "kirigaya",
|
||||
"author": {
|
||||
"name": "kirigaya",
|
||||
|
@ -3,19 +3,19 @@
|
||||
<h3>{{ currentResource.template?.name }}</h3>
|
||||
</div>
|
||||
<div class="resource-reader-container">
|
||||
<el-form :model="formData" :rules="formRules" ref="formRef" label-position="top">
|
||||
<el-form :model="tabStorage.formData" :rules="formRules" ref="formRef" label-position="top">
|
||||
<el-form-item v-for="param in currentResource?.params" :key="param.name"
|
||||
:label="param.name" :prop="param.name">
|
||||
<!-- 根据不同类型渲染不同输入组件 -->
|
||||
<el-input v-if="param.type === 'string'" v-model="formData[param.name]"
|
||||
<el-input v-if="param.type === 'string'" v-model="tabStorage.formData[param.name]"
|
||||
:placeholder="param.placeholder || `请输入${param.name}`"
|
||||
@keydown.enter.prevent="handleSubmit" />
|
||||
|
||||
<el-input-number v-else-if="param.type === 'number'" v-model="formData[param.name]"
|
||||
<el-input-number v-else-if="param.type === 'number'" v-model="tabStorage.formData[param.name]"
|
||||
:placeholder="param.placeholder || `请输入${param.name}`"
|
||||
@keydown.enter.prevent="handleSubmit" />
|
||||
|
||||
<el-switch v-else-if="param.type === 'boolean'" v-model="formData[param.name]" />
|
||||
<el-switch v-else-if="param.type === 'boolean'" v-model="tabStorage.formData[param.name]" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
@ -38,6 +38,7 @@ import { tabs } from '../panel';
|
||||
import { parseResourceTemplate, resourcesManager, ResourceStorage } from './resources';
|
||||
import { CasualRestAPI, ResourcesReadResponse } from '@/hook/type';
|
||||
import { useMessageBridge } from '@/api/message-bridge';
|
||||
import { getDefaultValue, normaliseJavascriptType } from '@/hook/mcp';
|
||||
|
||||
defineComponent({ name: 'resource-reader' });
|
||||
|
||||
@ -53,9 +54,12 @@ const props = defineProps({
|
||||
const tab = tabs.content[props.tabId];
|
||||
const tabStorage = tab.storage as ResourceStorage;
|
||||
|
||||
if (!tabStorage.formData) {
|
||||
tabStorage.formData = {};
|
||||
}
|
||||
|
||||
// 表单相关状态
|
||||
const formRef = ref<FormInstance>();
|
||||
const formData = ref<Record<string, any>>({});
|
||||
const loading = ref(false);
|
||||
const responseData = ref<ResourcesReadResponse>();
|
||||
|
||||
@ -94,12 +98,21 @@ const formRules = computed<FormRules>(() => {
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// 初始化表单数据
|
||||
const initFormData = () => {
|
||||
formData.value = {}
|
||||
currentResource.value?.params.forEach(param => {
|
||||
formData.value[param.name] = param.type === 'number' ? 0 :
|
||||
param.type === 'boolean' ? false : ''
|
||||
if (!currentResource.value?.params) return;
|
||||
|
||||
const newSchemaDataForm: Record<string, number | boolean | string> = {};
|
||||
|
||||
currentResource.value.params.forEach(param => {
|
||||
newSchemaDataForm[param.name] = getDefaultValue(param);
|
||||
const originType = normaliseJavascriptType(typeof tabStorage.formData[param.name]);
|
||||
|
||||
if (tabStorage.formData[param.name]!== undefined && originType === param.type) {
|
||||
newSchemaDataForm[param.name] = tabStorage.formData[param.name];
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -112,7 +125,7 @@ const resetForm = () => {
|
||||
// 提交表单
|
||||
function handleSubmit() {
|
||||
const fillFn = currentResource.value.fill;
|
||||
const uri = fillFn(formData.value);
|
||||
const uri = fillFn(tabStorage.formData);
|
||||
|
||||
const bridge = useMessageBridge();
|
||||
|
||||
|
@ -64,7 +64,6 @@ function reloadResources(option: { first: boolean }) {
|
||||
|
||||
function handleClick(template: ResourceTemplate) {
|
||||
tabStorage.currentResourceName = template.name;
|
||||
// TODO: 恢复这部分响应?
|
||||
tabStorage.lastResourceReadResponse = undefined;
|
||||
}
|
||||
|
||||
@ -74,9 +73,9 @@ onMounted(() => {
|
||||
commandCancel = bridge.addCommandListener('resources/templates/list', (data: CasualRestAPI<ResourceTemplatesListResponse>) => {
|
||||
resourcesManager.templates = data.msg.resourceTemplates || [];
|
||||
|
||||
if (resourcesManager.templates.length > 0) {
|
||||
const targetResource = resourcesManager.templates.find(template => template.name === tabStorage.currentResourceName);
|
||||
if (targetResource === undefined) {
|
||||
tabStorage.currentResourceName = resourcesManager.templates[0].name;
|
||||
// TODO: 恢复这部分响应?
|
||||
tabStorage.lastResourceReadResponse = undefined;
|
||||
}
|
||||
}, { once: false });
|
||||
|
@ -13,6 +13,7 @@ export const resourcesManager = reactive<{
|
||||
export interface ResourceStorage {
|
||||
currentResourceName: string;
|
||||
lastResourceReadResponse?: ResourcesReadResponse;
|
||||
formData: Record<string, number | string | boolean>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -22,7 +23,7 @@ export interface ResourceStorage {
|
||||
*/
|
||||
export function parseResourceTemplate(template: string): {
|
||||
params: string[],
|
||||
fill: (params: Record<string, string>) => string
|
||||
fill: (params: Record<string, number | boolean | string>) => string
|
||||
} {
|
||||
// 1. 提取所有参数名
|
||||
const paramRegex = /\{([^}]+)\}/g;
|
||||
@ -36,7 +37,7 @@ export function parseResourceTemplate(template: string): {
|
||||
const paramList = Array.from(params);
|
||||
|
||||
// 2. 创建填充函数
|
||||
const fill = (values: Record<string, string>): string => {
|
||||
const fill = (values: Record<string, number | boolean | string>): string => {
|
||||
let result = template;
|
||||
|
||||
// 验证所有必填参数
|
||||
@ -48,7 +49,7 @@ export function parseResourceTemplate(template: string): {
|
||||
|
||||
// 替换所有参数
|
||||
for (const param of paramList) {
|
||||
result = result.replace(new RegExp(`\\{${param}\\}`, 'g'), values[param]);
|
||||
result = result.replace(new RegExp(`\\{${param}\\}`, 'g'), values[param].toString());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -54,6 +54,7 @@ import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { tabs } from '../panel';
|
||||
import { callTool, toolsManager, ToolStorage } from './tools';
|
||||
import { pinkLog } from '@/views/setting/util';
|
||||
import { getDefaultValue, normaliseJavascriptType } from '@/hook/mcp';
|
||||
|
||||
defineComponent({ name: 'tool-executor' });
|
||||
|
||||
@ -99,15 +100,6 @@ const formRules = computed<FormRules>(() => {
|
||||
return rules;
|
||||
});
|
||||
|
||||
const getDefaultValue = (property: any) => {
|
||||
if (property.type === 'number' || property.type === 'integer') {
|
||||
return 0;
|
||||
} else if (property.type === 'boolean') {
|
||||
return false;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
const initFormData = () => {
|
||||
// 初始化,根据输入的 inputSchema 校验
|
||||
@ -120,11 +112,8 @@ const initFormData = () => {
|
||||
|
||||
Object.entries(currentTool.value.inputSchema.properties).forEach(([name, property]) => {
|
||||
newSchemaDataForm[name] = getDefaultValue(property);
|
||||
let originType: string = typeof tabStorage.formData[name];
|
||||
if (originType === 'number') {
|
||||
originType = 'integer';
|
||||
}
|
||||
|
||||
const originType = normaliseJavascriptType(typeof tabStorage.formData[name]);
|
||||
|
||||
if (tabStorage.formData[name] !== undefined && originType === property.type) {
|
||||
newSchemaDataForm[name] = tabStorage.formData[name];
|
||||
}
|
||||
@ -135,7 +124,6 @@ const initFormData = () => {
|
||||
|
||||
const resetForm = () => {
|
||||
formRef.value?.resetFields();
|
||||
tabStorage.lastToolCallResponse = undefined;
|
||||
};
|
||||
|
||||
async function handleExecute() {
|
||||
|
30
renderer/src/hook/mcp.ts
Normal file
30
renderer/src/hook/mcp.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { SchemaProperty } from "./type";
|
||||
|
||||
interface TypeAble {
|
||||
type: string;
|
||||
}
|
||||
|
||||
export function getDefaultValue(property: TypeAble) {
|
||||
if (property.type === 'number' || property.type === 'integer') {
|
||||
return 0;
|
||||
} else if (property.type === 'boolean') {
|
||||
return false;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function normaliseJavascriptType(type: string) {
|
||||
switch (type) {
|
||||
case 'integer':
|
||||
return 'number';
|
||||
case 'number':
|
||||
return 'integer';
|
||||
case 'boolean':
|
||||
return 'boolean';
|
||||
case 'string':
|
||||
return 'string';
|
||||
default:
|
||||
return 'string';
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"currentIndex": 1,
|
||||
"currentIndex": 2,
|
||||
"tabs": [
|
||||
{
|
||||
"name": "交互测试",
|
||||
@ -133,12 +133,33 @@
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "CityWeather(city_name_en='hangzhou', city_name_cn='杭州', city_code='101210101', temp='20.7', wd='', ws='', sd='93%', aqi='13', weather='阴')"
|
||||
"text": "CityWeather(city_name_en='hangzhou', city_name_cn='杭州', city_code='101210101', temp='20.3', wd='', ws='', sd='89%', aqi='38', weather='阴')"
|
||||
}
|
||||
],
|
||||
"isError": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "资源",
|
||||
"icon": "icon-file",
|
||||
"type": "blank",
|
||||
"componentIndex": 0,
|
||||
"storage": {
|
||||
"currentResourceName": "greeting",
|
||||
"formData": {
|
||||
"name": "kirigaya"
|
||||
},
|
||||
"lastResourceReadResponse": {
|
||||
"contents": [
|
||||
{
|
||||
"uri": "greeting://kirigaya",
|
||||
"mimeType": "text/plain",
|
||||
"text": "Hello, kirigaya!"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user