Merge branch 'main' into feat/auth
This commit is contained in:
commit
740293ab74
25
CHANGELOG.md
25
CHANGELOG.md
@ -1,5 +1,30 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## [main] 0.1.5
|
||||||
|
- 修复 gemini 获取模型列表时存在 models 前缀的问题
|
||||||
|
- 增加 web api 功能
|
||||||
|
|
||||||
|
## [main] 0.1.4
|
||||||
|
- 重新实现 openai 协议的底层网络实现,从而支持 Google Gemini 全系列模型。
|
||||||
|
- 实现 index 适配器,从而支持 Grok3 全系列模型。
|
||||||
|
- 解决 issue#23 插件创建连接时报错“Cannot read properties of undefined (reading 'name')”
|
||||||
|
- 在填写 apikey 和 baseurl 的情况下,现在可以一键刷新模型列表,避免用户手动输入模型列表。
|
||||||
|
|
||||||
|
## [main] 0.1.3
|
||||||
|
- 解决 issue#21 点击按钮后的发送文本后不会清空当前的输入框。
|
||||||
|
- 修复暂停按键在多轮对话后消失的问题。
|
||||||
|
- 修复 issue#25 无法连接 streamable http 的问题。
|
||||||
|
|
||||||
|
## [main] 0.1.2
|
||||||
|
- 新特性:用户发送的信息增加「重新发送」按钮。
|
||||||
|
- 支持特性 issue#17 「关于左侧添加mcp服务器操作优化问题」:增加强制聚焦功能,用户创建mcp服务器连接的过程中不会让输入框失去焦点。
|
||||||
|
- 更新 MCP & OpenAI 协议内容。
|
||||||
|
- 解决 issue#21 vscode插件界面bug,在高度有限情况下无法通过滚动完全显示连接按钮。
|
||||||
|
- 解决 issue#21 最后一个标签页关闭并恢复默认页面。
|
||||||
|
- 解决 issue#22 工具模块UI异常,现在 openmcp 支持解析 pydantic 进行 typing 的 python mcp 了。
|
||||||
|
- 优化对象输入框,现在对象输入框具有语法高亮和受限度的自动补全了。
|
||||||
|
- 对于 trae 的所有默认主题进行额外支持。
|
||||||
|
|
||||||
## [main] 0.1.1
|
## [main] 0.1.1
|
||||||
- 修复 SSH 连接 Ubuntu 的情况下的部分 bug
|
- 修复 SSH 连接 Ubuntu 的情况下的部分 bug
|
||||||
- 修复 python 项目点击 openmcp 进行连接时,初始化参数错误的问题
|
- 修复 python 项目点击 openmcp 进行连接时,初始化参数错误的问题
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 62 KiB |
384
package-lock.json
generated
384
package-lock.json
generated
@ -1,23 +1,23 @@
|
|||||||
{
|
{
|
||||||
"name": "openmcp",
|
"name": "openmcp",
|
||||||
"version": "0.1.1",
|
"version": "0.1.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "openmcp",
|
"name": "openmcp",
|
||||||
"version": "0.1.1",
|
"version": "0.1.3",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"service",
|
"service",
|
||||||
"renderer",
|
"renderer",
|
||||||
"software"
|
"software"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.10.2",
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||||
"@seald-io/nedb": "^4.1.1",
|
"@seald-io/nedb": "^4.1.1",
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.9.0",
|
||||||
"bson": "^6.8.0",
|
"bson": "^6.8.0",
|
||||||
"openai": "^4.93.0",
|
"openai": "^5.0.1",
|
||||||
"pako": "^2.1.0",
|
"pako": "^2.1.0",
|
||||||
"tesseract.js": "^6.0.1",
|
"tesseract.js": "^6.0.1",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
@ -510,6 +510,133 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@codemirror/autocomplete": {
|
||||||
|
"version": "6.18.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
|
||||||
|
"integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.17.0",
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/commands": {
|
||||||
|
"version": "6.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz",
|
||||||
|
"integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.4.0",
|
||||||
|
"@codemirror/view": "^6.27.0",
|
||||||
|
"@lezer/common": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/lang-json": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@lezer/json": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/language": {
|
||||||
|
"version": "6.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.0.tgz",
|
||||||
|
"integrity": "sha512-A7+f++LodNNc1wGgoRDTt78cOwWm9KVezApgjOMp1W4hM0898nsqBXwF+sbePE7ZRcjN7Sa1Z5m2oN27XkmEjQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.23.0",
|
||||||
|
"@lezer/common": "^1.1.0",
|
||||||
|
"@lezer/highlight": "^1.0.0",
|
||||||
|
"@lezer/lr": "^1.0.0",
|
||||||
|
"style-mod": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/lint": {
|
||||||
|
"version": "6.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz",
|
||||||
|
"integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.35.0",
|
||||||
|
"crelt": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/search": {
|
||||||
|
"version": "6.5.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
|
||||||
|
"integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.0.0",
|
||||||
|
"crelt": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/state": {
|
||||||
|
"version": "6.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
|
||||||
|
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@marijn/find-cluster-break": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/theme-one-dark": {
|
||||||
|
"version": "6.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz",
|
||||||
|
"integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.0.0",
|
||||||
|
"@lezer/highlight": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/view": {
|
||||||
|
"version": "6.37.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.1.tgz",
|
||||||
|
"integrity": "sha512-Qy4CAUwngy/VQkEz0XzMKVRcckQuqLYWKqVpDDDghBe5FSXSqfVrJn49nw3ePZHxRUz4nRmb05Lgi+9csWo4eg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.5.0",
|
||||||
|
"crelt": "^1.0.6",
|
||||||
|
"style-mod": "^4.1.0",
|
||||||
|
"w3c-keyname": "^2.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cspotcode/source-map-support": {
|
||||||
|
"version": "0.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||||
|
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/trace-mapping": "0.3.9"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
|
||||||
|
"version": "0.3.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||||
|
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/resolve-uri": "^3.0.3",
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@ctrl/tinycolor": {
|
"node_modules/@ctrl/tinycolor": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
||||||
@ -1436,6 +1563,41 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@lezer/common": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/highlight": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/json": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.2.0",
|
||||||
|
"@lezer/highlight": "^1.0.0",
|
||||||
|
"@lezer/lr": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/lr": {
|
||||||
|
"version": "1.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
|
||||||
|
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@malept/cross-spawn-promise": {
|
"node_modules/@malept/cross-spawn-promise": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz",
|
||||||
@ -1491,13 +1653,19 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@marijn/find-cluster-break": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@modelcontextprotocol/sdk": {
|
"node_modules/@modelcontextprotocol/sdk": {
|
||||||
"version": "1.11.4",
|
"version": "1.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.4.tgz",
|
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.12.1.tgz",
|
||||||
"integrity": "sha512-OTbhe5slIjiOtLxXhKalkKGhIQrwvhgCDs/C2r8kcBTy5HR/g43aDQU0l7r8O0VGbJPTNJvDc7ZdQMdQDJXmbw==",
|
"integrity": "sha512-KG1CZhZfWg+u8pxeM/mByJDScJSrjjxLc8fwQqbsS8xCjBmQfMNEBTotYdNanKekepnfRI85GtgQlctLFpcYPw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^8.17.1",
|
"ajv": "^6.12.6",
|
||||||
"content-type": "^1.0.5",
|
"content-type": "^1.0.5",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"cross-spawn": "^7.0.5",
|
"cross-spawn": "^7.0.5",
|
||||||
@ -1513,6 +1681,28 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@modelcontextprotocol/sdk/node_modules/ajv": {
|
||||||
|
"version": "6.12.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.1",
|
||||||
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
|
"json-schema-traverse": "^0.4.1",
|
||||||
|
"uri-js": "^4.2.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@openmcp/electron": {
|
"node_modules/@openmcp/electron": {
|
||||||
"resolved": "software",
|
"resolved": "software",
|
||||||
"link": true
|
"link": true
|
||||||
@ -3159,6 +3349,7 @@
|
|||||||
"version": "8.17.1",
|
"version": "8.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
@ -4059,6 +4250,21 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/codemirror": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
|
"@codemirror/commands": "^6.0.0",
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/lint": "^6.0.0",
|
||||||
|
"@codemirror/search": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
@ -4392,6 +4598,19 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/create-require": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/crelt": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||||
|
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
@ -5695,7 +5914,6 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fast-redact": {
|
"node_modules/fast-redact": {
|
||||||
@ -5717,6 +5935,7 @@
|
|||||||
"version": "3.0.6",
|
"version": "3.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
|
||||||
"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
|
"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
|
||||||
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -7200,6 +7419,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/json-stringify-safe": {
|
"node_modules/json-stringify-safe": {
|
||||||
@ -8221,19 +8441,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/openai": {
|
"node_modules/openai": {
|
||||||
"version": "4.100.0",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/openai/-/openai-4.100.0.tgz",
|
"resolved": "https://registry.npmjs.org/openai/-/openai-5.0.1.tgz",
|
||||||
"integrity": "sha512-9soq/wukv3utxcuD7TWFqKdKp0INWdeyhUCvxwrne5KwnxaCp4eHL4GdT/tMFhYolxgNhxFzg5GFwM331Z5CZg==",
|
"integrity": "sha512-Do6vxhbDv7cXhji/4ct1lrpZYMAOmjYbhyA9LJTuG7OfpbWMpuS+EIXkRT7R+XxpRB1OZhU/op4FU3p3uxU6gw==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "^18.11.18",
|
|
||||||
"@types/node-fetch": "^2.6.4",
|
|
||||||
"abort-controller": "^3.0.0",
|
|
||||||
"agentkeepalive": "^4.2.1",
|
|
||||||
"form-data-encoder": "1.7.2",
|
|
||||||
"formdata-node": "^4.3.2",
|
|
||||||
"node-fetch": "^2.6.7"
|
|
||||||
},
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"openai": "bin/cli"
|
"openai": "bin/cli"
|
||||||
},
|
},
|
||||||
@ -8250,21 +8461,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/openai/node_modules/@types/node": {
|
|
||||||
"version": "18.19.101",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.101.tgz",
|
|
||||||
"integrity": "sha512-Ykg7fcE3+cOQlLUv2Ds3zil6DVjriGQaSN/kEpl5HQ3DIGM6W0F2n9+GkWV4bRt7KjLymgzNdTnSKCbFUUJ7Kw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"undici-types": "~5.26.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/openai/node_modules/undici-types": {
|
|
||||||
"version": "5.26.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/opencollective-postinstall": {
|
"node_modules/opencollective-postinstall": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
|
||||||
@ -8797,7 +8993,6 @@
|
|||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@ -9030,6 +9225,7 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@ -9823,6 +10019,12 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/style-mod": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/sumchecker": {
|
"node_modules/sumchecker": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
||||||
@ -10411,7 +10613,6 @@
|
|||||||
"version": "4.4.1",
|
"version": "4.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||||
"dev": true,
|
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
@ -10563,6 +10764,12 @@
|
|||||||
"typescript": ">=5.0.0"
|
"typescript": ">=5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/w3c-keyname": {
|
||||||
|
"version": "2.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||||
|
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/wasm-feature-detect": {
|
"node_modules/wasm-feature-detect": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz",
|
||||||
@ -11027,6 +11234,10 @@
|
|||||||
"name": "@openmcp/renderer",
|
"name": "@openmcp/renderer",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.18.6",
|
||||||
|
"@codemirror/lang-json": "^6.0.1",
|
||||||
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
|
"codemirror": "^6.0.1",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"element-plus": "^2.9.9",
|
"element-plus": "^2.9.9",
|
||||||
"katex": "^0.16.21",
|
"katex": "^0.16.21",
|
||||||
@ -11107,6 +11318,51 @@
|
|||||||
"node": ">=14.14"
|
"node": ">=14.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"renderer/node_modules/openai": {
|
||||||
|
"version": "4.104.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz",
|
||||||
|
"integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^18.11.18",
|
||||||
|
"@types/node-fetch": "^2.6.4",
|
||||||
|
"abort-controller": "^3.0.0",
|
||||||
|
"agentkeepalive": "^4.2.1",
|
||||||
|
"form-data-encoder": "1.7.2",
|
||||||
|
"formdata-node": "^4.3.2",
|
||||||
|
"node-fetch": "^2.6.7"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"openai": "bin/cli"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"ws": "^8.18.0",
|
||||||
|
"zod": "^3.23.8"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ws": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"zod": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"renderer/node_modules/openai/node_modules/@types/node": {
|
||||||
|
"version": "18.19.110",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.110.tgz",
|
||||||
|
"integrity": "sha512-WW2o4gTmREtSnqKty9nhqF/vA0GKd0V/rbC0OyjSk9Bz6bzlsXKT+i7WDdS/a0z74rfT2PO4dArVCSnapNLA5Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"renderer/node_modules/openai/node_modules/undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"renderer/node_modules/vite": {
|
"renderer/node_modules/vite": {
|
||||||
"version": "6.3.5",
|
"version": "6.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
|
||||||
@ -11262,10 +11518,11 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.10.2",
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||||
"@seald-io/nedb": "^4.1.1",
|
"@seald-io/nedb": "^4.1.1",
|
||||||
"open": "^10.1.2",
|
"open": "^10.1.2",
|
||||||
"openai": "^4.96.0",
|
"axios": "^1.9.0",
|
||||||
|
"openai": "^5.0.1",
|
||||||
"pako": "^2.1.0",
|
"pako": "^2.1.0",
|
||||||
"pino": "^9.6.0",
|
"pino": "^9.6.0",
|
||||||
"pino-pretty": "^13.0.0",
|
"pino-pretty": "^13.0.0",
|
||||||
@ -11445,6 +11702,51 @@
|
|||||||
"electron-builder": "^24.13.3",
|
"electron-builder": "^24.13.3",
|
||||||
"typescript": "^5.6.3"
|
"typescript": "^5.6.3"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"software/node_modules/@types/node": {
|
||||||
|
"version": "18.19.110",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.110.tgz",
|
||||||
|
"integrity": "sha512-WW2o4gTmREtSnqKty9nhqF/vA0GKd0V/rbC0OyjSk9Bz6bzlsXKT+i7WDdS/a0z74rfT2PO4dArVCSnapNLA5Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"software/node_modules/openai": {
|
||||||
|
"version": "4.104.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz",
|
||||||
|
"integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^18.11.18",
|
||||||
|
"@types/node-fetch": "^2.6.4",
|
||||||
|
"abort-controller": "^3.0.0",
|
||||||
|
"agentkeepalive": "^4.2.1",
|
||||||
|
"form-data-encoder": "1.7.2",
|
||||||
|
"formdata-node": "^4.3.2",
|
||||||
|
"node-fetch": "^2.6.7"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"openai": "bin/cli"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"ws": "^8.18.0",
|
||||||
|
"zod": "^3.23.8"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ws": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"zod": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"software/node_modules/undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "openmcp",
|
"name": "openmcp",
|
||||||
"displayName": "OpenMCP",
|
"displayName": "OpenMCP",
|
||||||
"description": "An all in one MCP Client/TestTool",
|
"description": "An all in one MCP Client/TestTool",
|
||||||
"version": "0.1.1",
|
"version": "0.1.4",
|
||||||
"publisher": "kirigaya",
|
"publisher": "kirigaya",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "kirigaya",
|
"name": "kirigaya",
|
||||||
@ -233,11 +233,11 @@
|
|||||||
"build:task-loop": "webpack --config webpack/webpack.task-loop.js"
|
"build:task-loop": "webpack --config webpack/webpack.task-loop.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.10.2",
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||||
"@seald-io/nedb": "^4.1.1",
|
"@seald-io/nedb": "^4.1.1",
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.9.0",
|
||||||
"bson": "^6.8.0",
|
"bson": "^6.8.0",
|
||||||
"openai": "^4.93.0",
|
"openai": "^5.0.1",
|
||||||
"pako": "^2.1.0",
|
"pako": "^2.1.0",
|
||||||
"tesseract.js": "^6.0.1",
|
"tesseract.js": "^6.0.1",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
"type-check": "vue-tsc --build"
|
"type-check": "vue-tsc --build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.18.6",
|
||||||
|
"@codemirror/lang-json": "^6.0.1",
|
||||||
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
|
"codemirror": "^6.0.1",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"element-plus": "^2.9.9",
|
"element-plus": "^2.9.9",
|
||||||
"katex": "^0.16.21",
|
"katex": "^0.16.21",
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 62 KiB |
@ -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=1747820198035') format('woff2'),
|
src: url('iconfont.woff2?t=1748859145515') format('woff2'),
|
||||||
url('iconfont.woff?t=1747820198035') format('woff'),
|
url('iconfont.woff?t=1748859145515') format('woff'),
|
||||||
url('iconfont.ttf?t=1747820198035') format('truetype');
|
url('iconfont.ttf?t=1748859145515') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,10 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-proxy:before {
|
||||||
|
content: "\e723";
|
||||||
|
}
|
||||||
|
|
||||||
.icon-parallel:before {
|
.icon-parallel:before {
|
||||||
content: "\e61d";
|
content: "\e61d";
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -222,3 +222,9 @@ a {
|
|||||||
.el-dropdown-menu__item:hover {
|
.el-dropdown-menu__item:hover {
|
||||||
background-color: var(--background) !important;
|
background-color: var(--background) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* codemirror */
|
||||||
|
.ͼo,
|
||||||
|
.ͼo .cm-gutters {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
@ -1,147 +1,199 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="k-input-object">
|
<div class="k-input-object">
|
||||||
<textarea ref="textareaRef" v-model="inputValue" class="k-input-object__textarea"
|
<div :ref="el => editorContainer = el" class="k-input-object__editor"></div>
|
||||||
:class="{ 'is-invalid': isInvalid }" @input="handleInput" @blur="handleBlur"
|
<div v-if="errorMessage" class="k-input-object__error">
|
||||||
@keydown="handleKeydown"
|
{{ errorMessage }}
|
||||||
:placeholder="props.placeholder"
|
</div>
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
<div v-if="errorMessage" class="k-input-object__error">
|
|
||||||
{{ errorMessage }}
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, ref, watch, nextTick } from 'vue';
|
import { ref, onMounted, watch, type PropType } from 'vue'
|
||||||
import { debounce } from 'lodash';
|
import { EditorView, basicSetup } from 'codemirror'
|
||||||
|
import type { Completion, CompletionContext } from "@codemirror/autocomplete"
|
||||||
|
import { jsonLanguage } from "@codemirror/lang-json"
|
||||||
|
|
||||||
export default defineComponent({
|
import { json } from '@codemirror/lang-json'
|
||||||
name: 'KInputObject',
|
import { oneDark } from '@codemirror/theme-one-dark'
|
||||||
props: {
|
import { debounce } from 'lodash'
|
||||||
modelValue: {
|
|
||||||
type: Object,
|
const props = defineProps({
|
||||||
default: () => ({})
|
modelValue: {
|
||||||
},
|
type: Object,
|
||||||
placeholder: {
|
default: () => ({})
|
||||||
type: String,
|
|
||||||
default: '请输入 JSON 对象'
|
|
||||||
},
|
|
||||||
debounceTime: {
|
|
||||||
type: Number,
|
|
||||||
default: 500
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
emits: ['update:modelValue', 'parse-error'],
|
placeholder: {
|
||||||
setup(props, { emit }) {
|
type: String,
|
||||||
const textareaRef = ref<HTMLTextAreaElement | null>(null)
|
default: '请输入 JSON 对象'
|
||||||
const inputValue = ref<string>(JSON.stringify(props.modelValue, null, 2))
|
},
|
||||||
const isInvalid = ref<boolean>(false)
|
debounceTime: {
|
||||||
const errorMessage = ref<string>('')
|
type: Number,
|
||||||
|
default: 500
|
||||||
// 防抖处理输入
|
},
|
||||||
const debouncedParse = debounce((value: string) => {
|
schema: {
|
||||||
if (value.trim() === '') {
|
type: Object as PropType<{
|
||||||
errorMessage.value = '';
|
type?: string;
|
||||||
isInvalid.value = false;
|
properties?: Record<string, {
|
||||||
emit('update:modelValue', undefined);
|
type: string;
|
||||||
return;
|
description?: string;
|
||||||
}
|
default?: any;
|
||||||
try {
|
enum?: any[];
|
||||||
const parsed = JSON.parse(value);
|
}>;
|
||||||
isInvalid.value = false;
|
required?: string[];
|
||||||
errorMessage.value = '';
|
}>,
|
||||||
emit('update:modelValue', parsed);
|
default: () => ({})
|
||||||
} catch (error) {
|
|
||||||
isInvalid.value = true;
|
|
||||||
errorMessage.value = 'JSON 解析错误: ' + (error as Error).message;
|
|
||||||
emit('parse-error', error);
|
|
||||||
}
|
|
||||||
}, props.debounceTime)
|
|
||||||
|
|
||||||
const handleInput = () => {
|
|
||||||
debouncedParse(inputValue.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleBlur = () => {
|
|
||||||
// 立即执行最后一次防抖
|
|
||||||
debouncedParse.flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当外部 modelValue 变化时更新输入框内容
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(newVal) => {
|
|
||||||
const currentParsed = tryParse(inputValue.value)
|
|
||||||
if (!isDeepEqual(currentParsed, newVal)) {
|
|
||||||
inputValue.value = JSON.stringify(newVal, null, 2)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
)
|
|
||||||
|
|
||||||
// 辅助函数:尝试解析 JSON
|
|
||||||
const tryParse = (value: string): any => {
|
|
||||||
try {
|
|
||||||
return JSON.parse(value)
|
|
||||||
} catch {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 辅助函数:深度比较对象
|
|
||||||
const isDeepEqual = (obj1: any, obj2: any): boolean => {
|
|
||||||
return JSON.stringify(obj1) === JSON.stringify(obj2)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleKeydown = (event: KeyboardEvent) => {
|
|
||||||
if (event.key === '{') {
|
|
||||||
event.preventDefault();
|
|
||||||
const start = textareaRef.value!.selectionStart;
|
|
||||||
const end = textareaRef.value!.selectionEnd;
|
|
||||||
const value = inputValue.value;
|
|
||||||
const newValue = value.substring(0, start) + '{\n \n}' + value.substring(end);
|
|
||||||
inputValue.value = newValue;
|
|
||||||
nextTick(() => {
|
|
||||||
textareaRef.value!.setSelectionRange(start + 2, start + 2);
|
|
||||||
});
|
|
||||||
} else if (event.key === '"') {
|
|
||||||
event.preventDefault();
|
|
||||||
const start = textareaRef.value!.selectionStart;
|
|
||||||
const end = textareaRef.value!.selectionEnd;
|
|
||||||
const value = inputValue.value;
|
|
||||||
const newValue = value.substring(0, start) + '""' + value.substring(end);
|
|
||||||
inputValue.value = newValue;
|
|
||||||
nextTick(() => {
|
|
||||||
textareaRef.value!.setSelectionRange(start + 1, start + 1);
|
|
||||||
});
|
|
||||||
} else if (event.key === 'Tab') {
|
|
||||||
event.preventDefault();
|
|
||||||
const start = textareaRef.value!.selectionStart;
|
|
||||||
const end = textareaRef.value!.selectionEnd;
|
|
||||||
const value = inputValue.value;
|
|
||||||
const newValue = value.substring(0, start) + ' ' + value.substring(end);
|
|
||||||
inputValue.value = newValue;
|
|
||||||
nextTick(() => {
|
|
||||||
textareaRef.value!.setSelectionRange(start + 1, start + 1);
|
|
||||||
});
|
|
||||||
} else if (event.key === 'Enter' && inputValue.value.trim() === '') {
|
|
||||||
event.preventDefault();
|
|
||||||
inputValue.value = '{}';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
textareaRef,
|
|
||||||
inputValue,
|
|
||||||
isInvalid,
|
|
||||||
errorMessage,
|
|
||||||
handleInput,
|
|
||||||
handleBlur,
|
|
||||||
handleKeydown,
|
|
||||||
props
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue', 'parse-error'])
|
||||||
|
|
||||||
|
const editorContainer = ref<any>(null);
|
||||||
|
const editorView = ref<EditorView | null>(null);
|
||||||
|
const isInvalid = ref(false);
|
||||||
|
const errorMessage = ref('');
|
||||||
|
|
||||||
|
const inputValue = ref<string>(JSON.stringify(props.modelValue, null, 2));
|
||||||
|
|
||||||
|
// 防抖处理输入
|
||||||
|
const debouncedParse = debounce((value: string) => {
|
||||||
|
if (value.trim() === '') {
|
||||||
|
errorMessage.value = '';
|
||||||
|
isInvalid.value = false;
|
||||||
|
emit('update:modelValue', undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(value);
|
||||||
|
isInvalid.value = false;
|
||||||
|
errorMessage.value = '';
|
||||||
|
emit('update:modelValue', parsed);
|
||||||
|
} catch (error) {
|
||||||
|
isInvalid.value = true;
|
||||||
|
errorMessage.value = 'JSON 解析错误: ' + (error as Error).message;
|
||||||
|
emit('parse-error', error);
|
||||||
|
}
|
||||||
|
}, props.debounceTime);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (editorContainer.value) {
|
||||||
|
const extensions = [
|
||||||
|
basicSetup,
|
||||||
|
json(),
|
||||||
|
oneDark,
|
||||||
|
EditorView.updateListener.of(update => {
|
||||||
|
if (update.docChanged) {
|
||||||
|
const value = update.state.doc.toString()
|
||||||
|
debouncedParse(value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
|
||||||
|
// 如果schema不为空,添加自动补全
|
||||||
|
if (Object.keys(props.schema).length > 0) {
|
||||||
|
extensions.push(
|
||||||
|
jsonLanguage.data.of({
|
||||||
|
autocomplete: getJsonCompletion(props.schema)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
editorView.value = new EditorView({
|
||||||
|
doc: JSON.stringify(props.modelValue, null, 2),
|
||||||
|
extensions,
|
||||||
|
parent: editorContainer.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加自动补全函数
|
||||||
|
function getJsonCompletion(schema: any) {
|
||||||
|
return (context: CompletionContext) => {
|
||||||
|
// 检查当前输入是否是标点符号
|
||||||
|
const charBefore = context.state.sliceDoc(context.pos - 1, context.pos)
|
||||||
|
if (/[,.{}[\]:]/.test(charBefore)) return null
|
||||||
|
|
||||||
|
const word = context.matchBefore(/\w*/)
|
||||||
|
if (!word) return null
|
||||||
|
|
||||||
|
// 检查当前是否在字符串内
|
||||||
|
const state = context.state
|
||||||
|
const pos = context.pos
|
||||||
|
const line = state.doc.lineAt(pos)
|
||||||
|
const textBefore = line.text.slice(0, pos - line.from)
|
||||||
|
|
||||||
|
// 如果前面有奇数个双引号,说明在字符串内,不触发补全
|
||||||
|
const quoteCount = (textBefore.match(/"/g) || []).length
|
||||||
|
if (quoteCount % 2 !== 0) return null
|
||||||
|
|
||||||
|
const completions: Completion[] = []
|
||||||
|
|
||||||
|
// 处理对象属性补全
|
||||||
|
if (schema.properties) {
|
||||||
|
Object.entries(schema.properties).forEach(([key, value]) => {
|
||||||
|
completions.push({
|
||||||
|
label: key,
|
||||||
|
type: "property",
|
||||||
|
apply: `"${key}": ${getDefaultValue(value as any)}`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
from: word.from,
|
||||||
|
options: completions,
|
||||||
|
validFor: /^\w*$/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取默认值函数
|
||||||
|
function getDefaultValue(property: any): string {
|
||||||
|
if (property.default !== undefined) {
|
||||||
|
return JSON.stringify(property.default)
|
||||||
|
}
|
||||||
|
switch (property.type) {
|
||||||
|
case 'string': return '""'
|
||||||
|
case 'number': return '0'
|
||||||
|
case 'boolean': return 'false'
|
||||||
|
case 'object': return '{}'
|
||||||
|
case 'array': return '[]'
|
||||||
|
default: return 'null'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改 watch 逻辑
|
||||||
|
// watch(
|
||||||
|
// () => props.modelValue,
|
||||||
|
// (newVal) => {
|
||||||
|
// const currentParsed = tryParse(inputValue.value)
|
||||||
|
// if (!isDeepEqual(currentParsed, newVal)) {
|
||||||
|
// const newContent = JSON.stringify(newVal, null, 2)
|
||||||
|
// editorView.value?.dispatch({
|
||||||
|
// changes: {
|
||||||
|
// from: 0,
|
||||||
|
// to: editorView.value.state.doc.length,
|
||||||
|
// insert: newContent
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// { deep: true }
|
||||||
|
// )
|
||||||
|
|
||||||
|
// 辅助函数:尝试解析 JSON
|
||||||
|
const tryParse = (value: string): any => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(value)
|
||||||
|
} catch {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助函数:深度比较对象
|
||||||
|
const isDeepEqual = (obj1: any, obj2: any): boolean => {
|
||||||
|
return JSON.stringify(obj1) === JSON.stringify(obj2)
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -151,6 +203,7 @@ export default defineComponent({
|
|||||||
border-radius: .5em;
|
border-radius: .5em;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.k-input-object__textarea {
|
.k-input-object__textarea {
|
||||||
@ -174,6 +227,24 @@ export default defineComponent({
|
|||||||
border-color: var(--el-color-error);
|
border-color: var(--el-color-error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.k-input-object__error {
|
||||||
|
color: var(--el-color-error);
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-input-object__editor {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid var(--el-border-color-light);
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: var(--el-bg-color-overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-input-object__editor.is-invalid {
|
||||||
|
border-color: var(--el-color-error);
|
||||||
|
}
|
||||||
|
|
||||||
.k-input-object__error {
|
.k-input-object__error {
|
||||||
color: var(--el-color-error);
|
color: var(--el-color-error);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
@ -14,7 +14,8 @@ export enum MessageState {
|
|||||||
ToolCall = 'tool call failed',
|
ToolCall = 'tool call failed',
|
||||||
None = 'none',
|
None = 'none',
|
||||||
Success = 'success',
|
Success = 'success',
|
||||||
ParseJsonError = 'parse json error'
|
ParseJsonError = 'parse json error',
|
||||||
|
NoToolFunction = 'no tool function',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IExtraInfo {
|
export interface IExtraInfo {
|
||||||
@ -69,15 +70,7 @@ export interface ChatStorage {
|
|||||||
settings: ChatSetting
|
settings: ChatSetting
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ToolCall {
|
export type ToolCall = OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall;
|
||||||
id?: string;
|
|
||||||
index?: number;
|
|
||||||
type: string;
|
|
||||||
function: {
|
|
||||||
name: string;
|
|
||||||
arguments: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PromptTextItem {
|
interface PromptTextItem {
|
||||||
type: 'prompt'
|
type: 'prompt'
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<div class="input-wrapper">
|
<div class="input-wrapper">
|
||||||
|
|
||||||
<KRichTextarea
|
<KRichTextarea
|
||||||
|
:ref="el => editorRef = el"
|
||||||
:tabId="tabId"
|
:tabId="tabId"
|
||||||
v-model="userInput"
|
v-model="userInput"
|
||||||
:placeholder="t('enter-message-dot')"
|
:placeholder="t('enter-message-dot')"
|
||||||
@ -43,6 +44,7 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(['update:scrollToBottom']);
|
const emits = defineEmits(['update:scrollToBottom']);
|
||||||
|
const editorRef = ref<any>(null);
|
||||||
|
|
||||||
const tab = tabs.content[props.tabId];
|
const tab = tabs.content[props.tabId];
|
||||||
const tabStorage = tab.storage as ChatStorage;
|
const tabStorage = tab.storage as ChatStorage;
|
||||||
@ -84,6 +86,7 @@ function clearErrorMessage(errorMessage: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleSend(newMessage?: string) {
|
function handleSend(newMessage?: string) {
|
||||||
|
|
||||||
// 将富文本信息转换成纯文本信息
|
// 将富文本信息转换成纯文本信息
|
||||||
const userMessage = newMessage || userInput.value;
|
const userMessage = newMessage || userInput.value;
|
||||||
|
|
||||||
@ -115,8 +118,6 @@ function handleSend(newMessage?: string) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoading.value = false;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
loop.registerOnChunk(() => {
|
loop.registerOnChunk(() => {
|
||||||
@ -124,7 +125,6 @@ function handleSend(newMessage?: string) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
loop.registerOnDone(() => {
|
loop.registerOnDone(() => {
|
||||||
isLoading.value = false;
|
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -133,9 +133,16 @@ function handleSend(newMessage?: string) {
|
|||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
});
|
});
|
||||||
|
|
||||||
loop.start(tabStorage, userMessage);
|
loop.start(tabStorage, userMessage).then(() => {
|
||||||
|
isLoading.value = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 清空文本
|
||||||
userInput.value = '';
|
userInput.value = '';
|
||||||
|
const editor = editorRef.value.editor;
|
||||||
|
if (editor) {
|
||||||
|
editor.innerHTML = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAbort() {
|
function handleAbort() {
|
||||||
|
@ -117,6 +117,12 @@ function extractTextFromCollection(collection: HTMLCollection) {
|
|||||||
|
|
||||||
const isComposing = ref(false);
|
const isComposing = ref(false);
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
editor,
|
||||||
|
handleBackspace,
|
||||||
|
handleInput,
|
||||||
|
});
|
||||||
|
|
||||||
function handleKeydown(event: KeyboardEvent) {
|
function handleKeydown(event: KeyboardEvent) {
|
||||||
|
|
||||||
if (event.key === 'Enter' && !event.shiftKey && !isComposing.value) {
|
if (event.key === 'Enter' && !event.shiftKey && !isComposing.value) {
|
||||||
|
@ -1,16 +1,32 @@
|
|||||||
import type { ToolCallContent, ToolCallResponse } from "@/hook/type";
|
import type { ToolCallContent, ToolCallResponse } from "@/hook/type";
|
||||||
import { MessageState, type ToolCall } from "../chat-box/chat";
|
import { MessageState, type ToolCall } from "../chat-box/chat";
|
||||||
import { mcpClientAdapter } from "@/views/connect/core";
|
import { mcpClientAdapter } from "@/views/connect/core";
|
||||||
|
import type { BasicLlmDescription } from "@/views/setting/llm";
|
||||||
|
import { redLog } from "@/views/setting/util";
|
||||||
|
|
||||||
export interface ToolCallResult {
|
export interface ToolCallResult {
|
||||||
state: MessageState;
|
state: MessageState;
|
||||||
content: ToolCallContent[];
|
content: ToolCallContent[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type IToolCallIndex = number;
|
||||||
|
|
||||||
export async function handleToolCalls(toolCall: ToolCall): Promise<ToolCallResult> {
|
export async function handleToolCalls(toolCall: ToolCall): Promise<ToolCallResult> {
|
||||||
|
|
||||||
|
if (!toolCall.function) {
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: 'error',
|
||||||
|
text: 'no tool function'
|
||||||
|
}],
|
||||||
|
state: MessageState.NoToolFunction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 反序列化 streaming 来的参数字符串
|
// 反序列化 streaming 来的参数字符串
|
||||||
const toolName = toolCall.function.name;
|
// TODO: check as string
|
||||||
const argsResult = deserializeToolCallResponse(toolCall.function.arguments);
|
const toolName = toolCall.function.name as string;
|
||||||
|
const argsResult = deserializeToolCallResponse(toolCall.function.arguments as string);
|
||||||
|
|
||||||
if (argsResult.error) {
|
if (argsResult.error) {
|
||||||
return {
|
return {
|
||||||
@ -47,8 +63,7 @@ function deserializeToolCallResponse(toolArgs: string) {
|
|||||||
function handleToolResponse(toolResponse: ToolCallResponse) {
|
function handleToolResponse(toolResponse: ToolCallResponse) {
|
||||||
if (typeof toolResponse === 'string') {
|
if (typeof toolResponse === 'string') {
|
||||||
// 如果是 string,说明是错误信息
|
// 如果是 string,说明是错误信息
|
||||||
console.log(toolResponse);
|
redLog('error happen' + JSON.stringify(toolResponse));
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [{
|
||||||
@ -84,3 +99,37 @@ function parseErrorObject(error: any): string {
|
|||||||
return error.toString();
|
return error.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function grokIndexAdapter(toolCall: ToolCall, callId2Index: Map<string, number>): IToolCallIndex {
|
||||||
|
// grok 采用 id 作为 index,需要将 id 映射到 zero-based 的 index
|
||||||
|
if (!toolCall.id) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!callId2Index.has(toolCall.id)) {
|
||||||
|
callId2Index.set(toolCall.id, callId2Index.size);
|
||||||
|
}
|
||||||
|
return callId2Index.get(toolCall.id)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
function geminiIndexAdapter(toolCall: ToolCall): IToolCallIndex {
|
||||||
|
// TODO: 等待后续支持
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function defaultIndexAdapter(toolCall: ToolCall): IToolCallIndex {
|
||||||
|
return toolCall.index || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getToolCallIndexAdapter(llm: BasicLlmDescription) {
|
||||||
|
|
||||||
|
if (llm.userModel.startsWith('gemini')) {
|
||||||
|
return geminiIndexAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (llm.userModel.startsWith('grok')) {
|
||||||
|
const callId2Index = new Map<string, number>();
|
||||||
|
return (toolCall: ToolCall) => grokIndexAdapter(toolCall, callId2Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultIndexAdapter;
|
||||||
|
}
|
@ -3,15 +3,16 @@ import { ref, type Ref } from "vue";
|
|||||||
import { type ToolCall, type ChatStorage, getToolSchema, MessageState } from "../chat-box/chat";
|
import { type ToolCall, type ChatStorage, getToolSchema, MessageState } from "../chat-box/chat";
|
||||||
import { useMessageBridge, MessageBridge, createMessageBridge } from "@/api/message-bridge";
|
import { useMessageBridge, MessageBridge, createMessageBridge } from "@/api/message-bridge";
|
||||||
import type { OpenAI } from 'openai';
|
import type { OpenAI } from 'openai';
|
||||||
import { llmManager, llms } from "@/views/setting/llm";
|
import { llmManager, llms, type BasicLlmDescription } from "@/views/setting/llm";
|
||||||
import { pinkLog, redLog } from "@/views/setting/util";
|
import { pinkLog, redLog } from "@/views/setting/util";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { handleToolCalls, type ToolCallResult } from "./handle-tool-calls";
|
import { getToolCallIndexAdapter, handleToolCalls, type IToolCallIndex, type ToolCallResult } from "./handle-tool-calls";
|
||||||
import { getPlatform } from "@/api/platform";
|
import { getPlatform } from "@/api/platform";
|
||||||
import { getSystemPrompt } from "../chat-box/options/system-prompt";
|
import { getSystemPrompt } from "../chat-box/options/system-prompt";
|
||||||
|
import { mcpSetting } from "@/hook/mcp";
|
||||||
|
|
||||||
export type ChatCompletionChunk = OpenAI.Chat.Completions.ChatCompletionChunk;
|
export type ChatCompletionChunk = OpenAI.Chat.Completions.ChatCompletionChunk;
|
||||||
export type ChatCompletionCreateParamsBase = OpenAI.Chat.Completions.ChatCompletionCreateParams & { id?: string };
|
export type ChatCompletionCreateParamsBase = OpenAI.Chat.Completions.ChatCompletionCreateParams & { id?: string, proxyServer?: string };
|
||||||
export interface TaskLoopOptions {
|
export interface TaskLoopOptions {
|
||||||
maxEpochs?: number;
|
maxEpochs?: number;
|
||||||
maxJsonParseRetry?: number;
|
maxJsonParseRetry?: number;
|
||||||
@ -44,7 +45,7 @@ export class TaskLoop {
|
|||||||
private onToolCalled: (toolCallResult: ToolCallResult) => ToolCallResult = toolCallResult => toolCallResult;
|
private onToolCalled: (toolCallResult: ToolCallResult) => ToolCallResult = toolCallResult => toolCallResult;
|
||||||
private onEpoch: () => void = () => {};
|
private onEpoch: () => void = () => {};
|
||||||
private completionUsage: ChatCompletionChunk['usage'] | undefined;
|
private completionUsage: ChatCompletionChunk['usage'] | undefined;
|
||||||
private llmConfig: any;
|
private llmConfig?: BasicLlmDescription;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly taskOptions: TaskLoopOptions = { maxEpochs: 20, maxJsonParseRetry: 3, adapter: undefined },
|
private readonly taskOptions: TaskLoopOptions = { maxEpochs: 20, maxJsonParseRetry: 3, adapter: undefined },
|
||||||
@ -75,17 +76,23 @@ export class TaskLoop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleChunkDeltaToolCalls(chunk: ChatCompletionChunk) {
|
private handleChunkDeltaToolCalls(chunk: ChatCompletionChunk, toolcallIndexAdapter: (toolCall: ToolCall) => IToolCallIndex) {
|
||||||
const toolCall = chunk.choices[0]?.delta?.tool_calls?.[0];
|
const toolCall = chunk.choices[0]?.delta?.tool_calls?.[0];
|
||||||
|
|
||||||
if (toolCall) {
|
if (toolCall) {
|
||||||
const currentCall = this.streamingToolCalls.value[toolCall.index];
|
if (toolCall.index === undefined || toolCall.index === null) {
|
||||||
|
console.warn('tool_call.index is undefined or null');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const index = toolcallIndexAdapter(toolCall);
|
||||||
|
const currentCall = this.streamingToolCalls.value[index];
|
||||||
|
|
||||||
if (currentCall === undefined) {
|
if (currentCall === undefined) {
|
||||||
// 新的工具调用开始
|
// 新的工具调用开始
|
||||||
this.streamingToolCalls.value[toolCall.index] = {
|
this.streamingToolCalls.value[index] = {
|
||||||
id: toolCall.id,
|
id: toolCall.id,
|
||||||
index: toolCall.index,
|
index,
|
||||||
type: 'function',
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
name: toolCall.function?.name || '',
|
name: toolCall.function?.name || '',
|
||||||
@ -99,10 +106,10 @@ export class TaskLoop {
|
|||||||
currentCall.id = toolCall.id;
|
currentCall.id = toolCall.id;
|
||||||
}
|
}
|
||||||
if (toolCall.function?.name) {
|
if (toolCall.function?.name) {
|
||||||
currentCall.function.name = toolCall.function.name;
|
currentCall.function!.name = toolCall.function.name;
|
||||||
}
|
}
|
||||||
if (toolCall.function?.arguments) {
|
if (toolCall.function?.arguments) {
|
||||||
currentCall.function.arguments += toolCall.function.arguments;
|
currentCall.function!.arguments += toolCall.function.arguments;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,16 +124,18 @@ export class TaskLoop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private doConversation(chatData: ChatCompletionCreateParamsBase) {
|
private doConversation(chatData: ChatCompletionCreateParamsBase, toolcallIndexAdapter: (toolCall: ToolCall) => IToolCallIndex) {
|
||||||
|
|
||||||
return new Promise<IDoConversationResult>((resolve, reject) => {
|
return new Promise<IDoConversationResult>((resolve, reject) => {
|
||||||
const chunkHandler = this.bridge.addCommandListener('llm/chat/completions/chunk', data => {
|
const chunkHandler = this.bridge.addCommandListener('llm/chat/completions/chunk', data => {
|
||||||
// data.code 一定为 200,否则不会走这个 route
|
// data.code 一定为 200,否则不会走这个 route
|
||||||
const { chunk } = data.msg as { chunk: ChatCompletionChunk };
|
const { chunk } = data.msg as { chunk: ChatCompletionChunk };
|
||||||
|
|
||||||
|
console.log(chunk);
|
||||||
|
|
||||||
// 处理增量的 content 和 tool_calls
|
// 处理增量的 content 和 tool_calls
|
||||||
this.handleChunkDeltaContent(chunk);
|
this.handleChunkDeltaContent(chunk);
|
||||||
this.handleChunkDeltaToolCalls(chunk);
|
this.handleChunkDeltaToolCalls(chunk, toolcallIndexAdapter);
|
||||||
this.handleChunkUsage(chunk);
|
this.handleChunkUsage(chunk);
|
||||||
|
|
||||||
this.onChunk(chunk);
|
this.onChunk(chunk);
|
||||||
@ -181,6 +190,7 @@ export class TaskLoop {
|
|||||||
const temperature = tabStorage.settings.temperature;
|
const temperature = tabStorage.settings.temperature;
|
||||||
const tools = getToolSchema(tabStorage.settings.enableTools);
|
const tools = getToolSchema(tabStorage.settings.enableTools);
|
||||||
const parallelToolCalls = tabStorage.settings.parallelToolCalls;
|
const parallelToolCalls = tabStorage.settings.parallelToolCalls;
|
||||||
|
const proxyServer = mcpSetting.proxyServer || '';
|
||||||
|
|
||||||
const userMessages = [];
|
const userMessages = [];
|
||||||
|
|
||||||
@ -211,6 +221,7 @@ export class TaskLoop {
|
|||||||
tools,
|
tools,
|
||||||
parallelToolCalls,
|
parallelToolCalls,
|
||||||
messages: userMessages,
|
messages: userMessages,
|
||||||
|
proxyServer
|
||||||
} as ChatCompletionCreateParamsBase;
|
} as ChatCompletionCreateParamsBase;
|
||||||
|
|
||||||
return chatData;
|
return chatData;
|
||||||
@ -342,9 +353,11 @@ export class TaskLoop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.currentChatId = chatData.id!;
|
this.currentChatId = chatData.id!;
|
||||||
|
const llm = this.getLlmConfig();
|
||||||
|
const toolcallIndexAdapter = getToolCallIndexAdapter(llm);
|
||||||
|
|
||||||
// 发送请求
|
// 发送请求
|
||||||
const doConverationResult = await this.doConversation(chatData);
|
const doConverationResult = await this.doConversation(chatData, toolcallIndexAdapter);
|
||||||
|
|
||||||
console.log('[doConverationResult] Response');
|
console.log('[doConverationResult] Response');
|
||||||
console.log(doConverationResult);
|
console.log(doConverationResult);
|
||||||
@ -395,8 +408,8 @@ export class TaskLoop {
|
|||||||
} else if (toolCallResult.state === MessageState.Success) {
|
} else if (toolCallResult.state === MessageState.Success) {
|
||||||
tabStorage.messages.push({
|
tabStorage.messages.push({
|
||||||
role: 'tool',
|
role: 'tool',
|
||||||
index: toolCall.index || 0,
|
index: toolcallIndexAdapter(toolCall),
|
||||||
tool_call_id: toolCall.id || toolCall.function.name,
|
tool_call_id: toolCall.id || '',
|
||||||
content: toolCallResult.content,
|
content: toolCallResult.content,
|
||||||
extraInfo: {
|
extraInfo: {
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
@ -409,8 +422,8 @@ export class TaskLoop {
|
|||||||
|
|
||||||
tabStorage.messages.push({
|
tabStorage.messages.push({
|
||||||
role: 'tool',
|
role: 'tool',
|
||||||
index: toolCall.index || 0,
|
index: toolcallIndexAdapter(toolCall),
|
||||||
tool_call_id: toolCall.id || toolCall.function.name,
|
tool_call_id: toolCall.id || toolCall.function!.name,
|
||||||
content: toolCallResult.content,
|
content: toolCallResult.content,
|
||||||
extraInfo: {
|
extraInfo: {
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
<span class="tool-name">
|
<span class="tool-name">
|
||||||
<span class="iconfont icon-tool"></span>
|
<span class="iconfont icon-tool"></span>
|
||||||
|
|
||||||
{{ props.message.tool_calls[0].function.name }}
|
{{ props.message.tool_calls[0].function!.name }}
|
||||||
</span>
|
</span>
|
||||||
<el-button size="small" @click="createTest(props.message.tool_calls[0])">
|
<el-button size="small" @click="createTest(props.message.tool_calls[0])">
|
||||||
<span class="iconfont icon-send"></span>
|
<span class="iconfont icon-send"></span>
|
||||||
@ -37,7 +37,7 @@
|
|||||||
<span class="tool-name">
|
<span class="tool-name">
|
||||||
<span class="iconfont icon-tool"></span>
|
<span class="iconfont icon-tool"></span>
|
||||||
|
|
||||||
{{ props.message.tool_calls[toolIndex].function.name }}
|
{{ props.message.tool_calls[toolIndex].function!.name }}
|
||||||
</span>
|
</span>
|
||||||
<el-button size="small" @click="createTest(props.message.tool_calls[toolIndex])">
|
<el-button size="small" @click="createTest(props.message.tool_calls[toolIndex])">
|
||||||
<span class="iconfont icon-send"></span>
|
<span class="iconfont icon-send"></span>
|
||||||
@ -46,7 +46,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tool-arguments">
|
<div class="tool-arguments">
|
||||||
<json-render :json="props.message.tool_calls[toolIndex].function.arguments"/>
|
<json-render :json="props.message.tool_calls[toolIndex].function!.arguments"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 工具调用结果 -->
|
<!-- 工具调用结果 -->
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
<el-button @click="copy">
|
<el-button @click="copy">
|
||||||
<span class="iconfont icon-copy"></span>
|
<span class="iconfont icon-copy"></span>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button @click="reload">
|
||||||
|
<span class="iconfont icon-restart"></span>
|
||||||
|
</el-button>
|
||||||
<el-button @click="toggleEdit">
|
<el-button @click="toggleEdit">
|
||||||
<span class="iconfont icon-edit2"></span>
|
<span class="iconfont icon-edit2"></span>
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -91,6 +94,16 @@ const copy = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const reload = async () => {
|
||||||
|
const index = tabStorage.messages.findIndex(msg => msg.extraInfo === props.message.extraInfo);
|
||||||
|
|
||||||
|
if (index !== -1 && chatContext.handleSend) {
|
||||||
|
// 把 index 之后的全部删除(包括 index)
|
||||||
|
tabStorage.messages.splice(index);
|
||||||
|
chatContext.handleSend(props.message.content);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -60,7 +60,7 @@ export function createTab(type: string, index: number): Tab {
|
|||||||
if (customName !== null) {
|
if (customName !== null) {
|
||||||
return customName;
|
return customName;
|
||||||
}
|
}
|
||||||
return t('blank-test') + ` ${index}`;
|
return t('blank-test');
|
||||||
},
|
},
|
||||||
set name(value: string) {
|
set name(value: string) {
|
||||||
customName = value; // 允许外部修改 name
|
customName = value; // 允许外部修改 name
|
||||||
@ -85,8 +85,6 @@ export function addNewTab() {
|
|||||||
|
|
||||||
|
|
||||||
export function closeTab(index: number) {
|
export function closeTab(index: number) {
|
||||||
if (tabs.content.length <= 1) return; // 至少保留一个标签页
|
|
||||||
|
|
||||||
tabs.content.splice(index, 1);
|
tabs.content.splice(index, 1);
|
||||||
|
|
||||||
console.log(tabs.content);
|
console.log(tabs.content);
|
||||||
@ -95,4 +93,8 @@ export function closeTab(index: number) {
|
|||||||
if (tabs.activeIndex >= index) {
|
if (tabs.activeIndex >= index) {
|
||||||
tabs.activeIndex = Math.max(0, tabs.activeIndex - 1);
|
tabs.activeIndex = Math.max(0, tabs.activeIndex - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tabs.content.length === 0) {
|
||||||
|
addNewTab();
|
||||||
|
}
|
||||||
}
|
}
|
@ -38,6 +38,7 @@
|
|||||||
<k-input-object
|
<k-input-object
|
||||||
v-else-if="property.type === 'object'"
|
v-else-if="property.type === 'object'"
|
||||||
v-model="tabStorage.formData[name]"
|
v-model="tabStorage.formData[name]"
|
||||||
|
:schema="property"
|
||||||
:placeholder="property.description || t('enter') + ' ' + (property.title || name)"
|
:placeholder="property.description || t('enter') + ' ' + (property.title || name)"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -84,22 +85,24 @@ if (!tabStorage.formData) {
|
|||||||
tabStorage.formData = {};
|
tabStorage.formData = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(tabStorage.formData);
|
|
||||||
|
|
||||||
|
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
const currentTool = computed(() => {
|
const currentTool = computed(() => {
|
||||||
for (const client of mcpClientAdapter.clients) {
|
for (const client of mcpClientAdapter.clients) {
|
||||||
const tool = client.tools?.get(tabStorage.currentToolName);
|
const tool = client.tools?.get(tabStorage.currentToolName);
|
||||||
if (tool) return tool;
|
if (tool) {
|
||||||
|
console.log(tool);
|
||||||
|
|
||||||
|
return tool;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const formRules = computed<FormRules>(() => {
|
const formRules = computed<FormRules>(() => {
|
||||||
const rules: FormRules = {};
|
const rules: FormRules = {};
|
||||||
|
|
||||||
if (!currentTool.value?.inputSchema?.properties) return rules;
|
if (!currentTool.value?.inputSchema?.properties) return rules;
|
||||||
|
|
||||||
Object.entries(currentTool.value.inputSchema.properties).forEach(([name, property]) => {
|
Object.entries(currentTool.value.inputSchema.properties).forEach(([name, property]) => {
|
||||||
@ -127,8 +130,6 @@ const initFormData = () => {
|
|||||||
|
|
||||||
const newSchemaDataForm: Record<string, number | boolean | string | object> = {};
|
const newSchemaDataForm: Record<string, number | boolean | string | object> = {};
|
||||||
|
|
||||||
console.log(currentTool.value.inputSchema.properties);
|
|
||||||
|
|
||||||
Object.entries(currentTool.value.inputSchema.properties).forEach(([name, property]) => {
|
Object.entries(currentTool.value.inputSchema.properties).forEach(([name, property]) => {
|
||||||
newSchemaDataForm[name] = getDefaultValue(property);
|
newSchemaDataForm[name] = getDefaultValue(property);
|
||||||
const originType = normaliseJavascriptType(typeof tabStorage.formData[name]);
|
const originType = normaliseJavascriptType(typeof tabStorage.formData[name]);
|
||||||
|
@ -176,9 +176,10 @@ export class MacroColor {
|
|||||||
// 额外支持 trae 的默认主题
|
// 额外支持 trae 的默认主题
|
||||||
const sidebarColorString = this.rootStyles.getPropertyValue('--sidebar');
|
const sidebarColorString = this.rootStyles.getPropertyValue('--sidebar');
|
||||||
if (sidebarColorString === backgroundColorString) {
|
if (sidebarColorString === backgroundColorString) {
|
||||||
|
// trae 默认主题的特点:sidebarColorString 和 backgroundColorString 一样
|
||||||
|
// 把 默认主题的特点:sidebarColorString 的颜色加深一些
|
||||||
const newSidebarColor = this.theme === 'dark' ? '#252a38' : '#edeff2';
|
const newSidebarColor = this.theme === 'dark' ? '#252a38' : '#edeff2';
|
||||||
document.documentElement.style.setProperty('--sidebar', newSidebarColor);
|
document.documentElement.style.setProperty('--sidebar', 'var(--vscode-icube-colorBg2)');
|
||||||
pinkLog('修改 sidebar 颜色为' + newSidebarColor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +27,11 @@ export function normaliseJavascriptType(type: string) {
|
|||||||
case 'string':
|
case 'string':
|
||||||
return 'string';
|
return 'string';
|
||||||
default:
|
default:
|
||||||
return 'string';
|
return type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mcpSetting = reactive({
|
export const mcpSetting = reactive({
|
||||||
timeout: 60,
|
timeout: 60,
|
||||||
|
proxyServer: '',
|
||||||
});
|
});
|
@ -20,6 +20,7 @@ export async function loadSetting() {
|
|||||||
llmManager.currentModelIndex = persistConfig.MODEL_INDEX || 0;
|
llmManager.currentModelIndex = persistConfig.MODEL_INDEX || 0;
|
||||||
I18n.global.locale.value = persistConfig.LANG || 'zh';
|
I18n.global.locale.value = persistConfig.LANG || 'zh';
|
||||||
mcpSetting.timeout = persistConfig.MCP_TIMEOUT_SEC || 60;
|
mcpSetting.timeout = persistConfig.MCP_TIMEOUT_SEC || 60;
|
||||||
|
mcpSetting.proxyServer = persistConfig.PROXY_SERVER || '';
|
||||||
|
|
||||||
persistConfig.LLM_INFO.forEach((element: any) => {
|
persistConfig.LLM_INFO.forEach((element: any) => {
|
||||||
llms.push(element);
|
llms.push(element);
|
||||||
@ -51,7 +52,8 @@ export function saveSetting(saveHandler?: () => void) {
|
|||||||
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
|
MCP_TIMEOUT_SEC: mcpSetting.timeout,
|
||||||
|
PROXY_SERVER: mcpSetting.proxyServer
|
||||||
};
|
};
|
||||||
|
|
||||||
bridge.addCommandListener('setting/save', data => {
|
bridge.addCommandListener('setting/save', data => {
|
||||||
|
@ -10,6 +10,7 @@ export interface InputSchema {
|
|||||||
properties: Record<string, SchemaProperty>;
|
properties: Record<string, SchemaProperty>;
|
||||||
required?: string[];
|
required?: string[];
|
||||||
title?: string;
|
title?: string;
|
||||||
|
$defs?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Argument {
|
export interface Argument {
|
||||||
@ -40,6 +41,7 @@ export interface ToolItem {
|
|||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
inputSchema: InputSchema;
|
inputSchema: InputSchema;
|
||||||
|
anyOf?: any;
|
||||||
}
|
}
|
||||||
export interface ToolsListResponse {
|
export interface ToolsListResponse {
|
||||||
tools: ToolItem[]
|
tools: ToolItem[]
|
||||||
|
@ -156,5 +156,7 @@
|
|||||||
"error": "خطأ",
|
"error": "خطأ",
|
||||||
"feedback": "تعليقات",
|
"feedback": "تعليقات",
|
||||||
"waiting-mcp-server": "في انتظار استجابة خادم MCP",
|
"waiting-mcp-server": "في انتظار استجابة خادم MCP",
|
||||||
"parallel-tool-calls": "السماح للنموذج باستدعاء أدوات متعددة في رد واحد"
|
"parallel-tool-calls": "السماح للنموذج باستدعاء أدوات متعددة في رد واحد",
|
||||||
|
"proxy-server": "خادم وكيل",
|
||||||
|
"update-model-list": "تحديث قائمة النماذج"
|
||||||
}
|
}
|
@ -156,5 +156,7 @@
|
|||||||
"error": "Fehler",
|
"error": "Fehler",
|
||||||
"feedback": "Feedback",
|
"feedback": "Feedback",
|
||||||
"waiting-mcp-server": "Warten auf Antwort vom MCP-Server",
|
"waiting-mcp-server": "Warten auf Antwort vom MCP-Server",
|
||||||
"parallel-tool-calls": "Erlauben Sie dem Modell, mehrere Tools in einer einzigen Antwort aufzurufen"
|
"parallel-tool-calls": "Erlauben Sie dem Modell, mehrere Tools in einer einzigen Antwort aufzurufen",
|
||||||
|
"proxy-server": "Proxy-Server",
|
||||||
|
"update-model-list": "Modellliste aktualisieren"
|
||||||
}
|
}
|
@ -156,5 +156,7 @@
|
|||||||
"error": "Error",
|
"error": "Error",
|
||||||
"feedback": "Feedback",
|
"feedback": "Feedback",
|
||||||
"waiting-mcp-server": "Waiting for MCP server response",
|
"waiting-mcp-server": "Waiting for MCP server response",
|
||||||
"parallel-tool-calls": "Allow the model to call multiple tools in a single reply"
|
"parallel-tool-calls": "Allow the model to call multiple tools in a single reply",
|
||||||
|
"proxy-server": "Proxy server",
|
||||||
|
"update-model-list": "Update model list"
|
||||||
}
|
}
|
@ -156,5 +156,7 @@
|
|||||||
"error": "Erreur",
|
"error": "Erreur",
|
||||||
"feedback": "Retour",
|
"feedback": "Retour",
|
||||||
"waiting-mcp-server": "En attente de la réponse du serveur MCP",
|
"waiting-mcp-server": "En attente de la réponse du serveur MCP",
|
||||||
"parallel-tool-calls": "Permettre au modèle d'appeler plusieurs outils en une seule réponse"
|
"parallel-tool-calls": "Permettre au modèle d'appeler plusieurs outils en une seule réponse",
|
||||||
|
"proxy-server": "Serveur proxy",
|
||||||
|
"update-model-list": "Mettre à jour la liste des modèles"
|
||||||
}
|
}
|
@ -156,5 +156,7 @@
|
|||||||
"error": "エラー",
|
"error": "エラー",
|
||||||
"feedback": "フィードバック",
|
"feedback": "フィードバック",
|
||||||
"waiting-mcp-server": "MCPサーバーの応答を待機中",
|
"waiting-mcp-server": "MCPサーバーの応答を待機中",
|
||||||
"parallel-tool-calls": "モデルが単一の返信で複数のツールを呼び出すことを許可する"
|
"parallel-tool-calls": "モデルが単一の返信で複数のツールを呼び出すことを許可する",
|
||||||
|
"proxy-server": "プロキシサーバー",
|
||||||
|
"update-model-list": "モデルリストを更新"
|
||||||
}
|
}
|
@ -156,5 +156,7 @@
|
|||||||
"error": "오류",
|
"error": "오류",
|
||||||
"feedback": "피드백",
|
"feedback": "피드백",
|
||||||
"waiting-mcp-server": "MCP 서버 응답 대기 중",
|
"waiting-mcp-server": "MCP 서버 응답 대기 중",
|
||||||
"parallel-tool-calls": "모델이 단일 응답에서 여러 도구를 호출할 수 있도록 허용"
|
"parallel-tool-calls": "모델이 단일 응답에서 여러 도구를 호출할 수 있도록 허용",
|
||||||
|
"proxy-server": "프록시 서버",
|
||||||
|
"update-model-list": "모델 목록 업데이트"
|
||||||
}
|
}
|
@ -156,5 +156,7 @@
|
|||||||
"error": "Ошибка",
|
"error": "Ошибка",
|
||||||
"feedback": "Обратная связь",
|
"feedback": "Обратная связь",
|
||||||
"waiting-mcp-server": "Ожидание ответа от сервера MCP",
|
"waiting-mcp-server": "Ожидание ответа от сервера MCP",
|
||||||
"parallel-tool-calls": "Разрешить модели вызывать несколько инструментов в одном ответе"
|
"parallel-tool-calls": "Разрешить модели вызывать несколько инструментов в одном ответе",
|
||||||
|
"proxy-server": "Прокси-сервер",
|
||||||
|
"update-model-list": "Обновить список моделей"
|
||||||
}
|
}
|
@ -156,5 +156,7 @@
|
|||||||
"error": "错误",
|
"error": "错误",
|
||||||
"feedback": "反馈",
|
"feedback": "反馈",
|
||||||
"waiting-mcp-server": "等待 MCP 服务器响应",
|
"waiting-mcp-server": "等待 MCP 服务器响应",
|
||||||
"parallel-tool-calls": "允许模型在单轮回复中调用多个工具"
|
"parallel-tool-calls": "允许模型在单轮回复中调用多个工具",
|
||||||
|
"proxy-server": "代理服务器",
|
||||||
|
"update-model-list": "更新模型列表"
|
||||||
}
|
}
|
@ -156,5 +156,7 @@
|
|||||||
"error": "錯誤",
|
"error": "錯誤",
|
||||||
"feedback": "反饋",
|
"feedback": "反饋",
|
||||||
"waiting-mcp-server": "等待MCP伺服器響應",
|
"waiting-mcp-server": "等待MCP伺服器響應",
|
||||||
"parallel-tool-calls": "允許模型在單輪回覆中調用多個工具"
|
"parallel-tool-calls": "允許模型在單輪回覆中調用多個工具",
|
||||||
|
"proxy-server": "代理伺服器",
|
||||||
|
"update-model-list": "更新模型列表"
|
||||||
}
|
}
|
@ -6,7 +6,7 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
OpenMCP Client 0.1.1 由 OpenMCP@<a href="https://www.zhihu.com/people/can-meng-zhong-de-che-xian">锦恢</a> 开发
|
OpenMCP Client 0.1.4 由 OpenMCP@<a href="https://www.zhihu.com/people/can-meng-zhong-de-che-xian">锦恢</a> 开发
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -121,4 +121,9 @@ const validateForm = async () => {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.connection-option .el-form-item {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -53,7 +53,7 @@ function clearLogs() {
|
|||||||
<style>
|
<style>
|
||||||
|
|
||||||
.connection-log {
|
.connection-log {
|
||||||
height: 90vh;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-scrollbar>
|
<el-scrollbar height="98%">
|
||||||
<div class="connection-container" @dragover.prevent="handleDragOver" @drop.prevent="handleDrop">
|
<div class="connection-container" @dragover.prevent="handleDragOver" @drop.prevent="handleDrop">
|
||||||
<div v-if="isDraging" class="drag-mask">
|
<div v-if="isDraging" class="drag-mask">
|
||||||
<span class="iconfont icon-connect"></span>
|
<span class="iconfont icon-connect"></span>
|
||||||
@ -24,7 +24,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -126,6 +125,7 @@ function handleDrop(event: DragEvent) {
|
|||||||
<style>
|
<style>
|
||||||
.connection-container {
|
.connection-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
max-height: 85vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -133,7 +133,6 @@ function handleDrop(event: DragEvent) {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 45%;
|
width: 45%;
|
||||||
max-height: 85vh;
|
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
min-width: 350px;
|
min-width: 350px;
|
||||||
padding: 5px 20px;
|
padding: 5px 20px;
|
||||||
@ -143,7 +142,6 @@ function handleDrop(event: DragEvent) {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 55%;
|
width: 55%;
|
||||||
max-height: 85vh;
|
|
||||||
min-width: 450px;
|
min-width: 450px;
|
||||||
padding: 5px 20px;
|
padding: 5px 20px;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,66 @@ function prettifyMapKeys(keys: MapIterator<string>) {
|
|||||||
return result.join('\n');
|
return result.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _processSchemaNode(node: any, defs: Record<string, any> = {}): any {
|
||||||
|
// Handle $ref references
|
||||||
|
if ('$ref' in node) {
|
||||||
|
const refPath = node['$ref'];
|
||||||
|
if (refPath.startsWith('#/$defs/')) {
|
||||||
|
const refName = refPath.split('/').pop();
|
||||||
|
if (refName && refName in defs) {
|
||||||
|
// Process the referenced definition
|
||||||
|
return _processSchemaNode(defs[refName], defs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with a new schema object
|
||||||
|
const result: Record<string, any> = {};
|
||||||
|
|
||||||
|
// Copy the basic properties
|
||||||
|
if ('type' in node) {
|
||||||
|
result.type = node.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle anyOf (often used for optional fields with None)
|
||||||
|
if ('anyOf' in node) {
|
||||||
|
const nonNullTypes = node.anyOf.filter((t: any) => t?.type !== 'null');
|
||||||
|
if (nonNullTypes.length > 0) {
|
||||||
|
// Process the first non-null type
|
||||||
|
const processed = _processSchemaNode(nonNullTypes[0], defs);
|
||||||
|
Object.assign(result, processed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle description
|
||||||
|
if ('description' in node) {
|
||||||
|
result.description = node.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle object properties recursively
|
||||||
|
if (node?.type === 'object' && 'properties' in node) {
|
||||||
|
result.type = 'object';
|
||||||
|
result.properties = {};
|
||||||
|
|
||||||
|
// Process each property
|
||||||
|
for (const [propName, propSchema] of Object.entries(node.properties)) {
|
||||||
|
result.properties[propName] = _processSchemaNode(propSchema as any, defs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add required fields if present
|
||||||
|
if ('required' in node) {
|
||||||
|
result.required = node.required;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle arrays
|
||||||
|
if (node?.type === 'array' && 'items' in node) {
|
||||||
|
result.type = 'array';
|
||||||
|
result.items = _processSchemaNode(node.items, defs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
export class McpClient {
|
export class McpClient {
|
||||||
// 连接入参
|
// 连接入参
|
||||||
@ -139,6 +199,11 @@ export class McpClient {
|
|||||||
|
|
||||||
this.tools = new Map<string, ToolItem>();
|
this.tools = new Map<string, ToolItem>();
|
||||||
msg.tools.forEach(tool => {
|
msg.tools.forEach(tool => {
|
||||||
|
const standardSchema = _processSchemaNode(tool.inputSchema, tool.inputSchema.$defs || {});
|
||||||
|
console.log(standardSchema);
|
||||||
|
|
||||||
|
tool.inputSchema = standardSchema;
|
||||||
|
|
||||||
this.tools!.set(tool.name, tool);
|
this.tools!.set(tool.name, tool);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -104,18 +104,15 @@ function deleteServer(index: number) {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 150px;
|
width: 150px;
|
||||||
height: 50px;
|
|
||||||
border-right: 1px solid var(--border-color);
|
border-right: 1px solid var(--border-color);
|
||||||
padding: 15px 25px;
|
padding: 0 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.server-name {
|
.server-name {
|
||||||
font-size: 15px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.server-item {
|
.server-item {
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -51,10 +51,21 @@
|
|||||||
<div class="setting-save-container">
|
<div class="setting-save-container">
|
||||||
<el-button
|
<el-button
|
||||||
id="add-new-server-button"
|
id="add-new-server-button"
|
||||||
type="success" @click="addNewServer">
|
type="success"
|
||||||
|
@click="addNewServer"
|
||||||
|
>
|
||||||
{{ t("add-new-server") }}
|
{{ t("add-new-server") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
id="add-new-server-button"
|
||||||
|
type="success"
|
||||||
|
@click="updateModels"
|
||||||
|
:loading="updateModelLoading"
|
||||||
|
>
|
||||||
|
{{ t('update-model-list') }}
|
||||||
|
</el-button>
|
||||||
|
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
id="test-llm-button"
|
id="test-llm-button"
|
||||||
@ -120,6 +131,7 @@ import { pinkLog } from './util';
|
|||||||
import ConnectInterfaceOpenai from './connect-interface-openai.vue';
|
import ConnectInterfaceOpenai from './connect-interface-openai.vue';
|
||||||
import ConnectTest from './connect-test.vue';
|
import ConnectTest from './connect-test.vue';
|
||||||
import { llmSettingRef, makeSimpleTalk, simpleTestResult } from './api';
|
import { llmSettingRef, makeSimpleTalk, simpleTestResult } from './api';
|
||||||
|
import { useMessageBridge } from '@/api/message-bridge';
|
||||||
|
|
||||||
defineComponent({ name: 'api' });
|
defineComponent({ name: 'api' });
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -212,6 +224,43 @@ function addNewProvider() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const updateModelLoading = ref(false);
|
||||||
|
|
||||||
|
async function updateModels() {
|
||||||
|
updateModelLoading.value = true;
|
||||||
|
|
||||||
|
const llm = llms[llmManager.currentModelIndex];
|
||||||
|
const apiKey = llm.userToken;
|
||||||
|
const baseURL = llm.baseUrl;
|
||||||
|
|
||||||
|
const bridge = useMessageBridge();
|
||||||
|
const { code, msg } = await bridge.commandRequest('llm/models', {
|
||||||
|
apiKey,
|
||||||
|
baseURL
|
||||||
|
});
|
||||||
|
|
||||||
|
const isGemini = baseURL.includes('googleapis');
|
||||||
|
|
||||||
|
if (code === 200 && Array.isArray(msg)) {
|
||||||
|
const models = msg
|
||||||
|
.filter(item => item.object === 'model')
|
||||||
|
.map(item => {
|
||||||
|
let modelName = item.id as string;
|
||||||
|
if (isGemini && modelName.includes('/')) {
|
||||||
|
modelName = modelName.split('/')[1];
|
||||||
|
}
|
||||||
|
return modelName;
|
||||||
|
});
|
||||||
|
|
||||||
|
llm.models = models;
|
||||||
|
saveLlmSetting();
|
||||||
|
} else {
|
||||||
|
ElMessage.error('模型列表更新失败' + msg);
|
||||||
|
}
|
||||||
|
updateModelLoading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
function updateProvider() {
|
function updateProvider() {
|
||||||
if (editingIndex.value < 0) {
|
if (editingIndex.value < 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
v-for="option in llms[llmManager.currentModelIndex].models"
|
v-for="option in llms[llmManager.currentModelIndex].models"
|
||||||
:value="option"
|
:value="option"
|
||||||
:label="option"
|
:label="option"
|
||||||
:key="option.id"
|
:key="option"
|
||||||
></el-option>
|
></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div class="extra-info warning" v-if="isGoogle">
|
||||||
|
当前模型组协议兼容性较差,特别是 gemini-2.0-flash 模型的函数调用能力不稳定;如果想要稳定使用 gemini 的服务,请尽可能使用最新的模型或者使用 newApi 进行协议转接。
|
||||||
|
</div>
|
||||||
<div class="connect-test" v-if="simpleTestResult.done || simpleTestResult.error">
|
<div class="connect-test" v-if="simpleTestResult.done || simpleTestResult.error">
|
||||||
<div class="test-result">
|
<div class="test-result">
|
||||||
<div class="result-item" v-if="simpleTestResult.done">
|
<div class="result-item" v-if="simpleTestResult.done">
|
||||||
@ -18,9 +21,19 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { simpleTestResult } from './api';
|
import { simpleTestResult } from './api';
|
||||||
|
import { llmManager, llms } from './llm';
|
||||||
|
import { computed } from '@vue/reactivity';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const isGoogle = computed(() => {
|
||||||
|
const model = llms[llmManager.currentModelIndex];
|
||||||
|
return model.userModel.startsWith('gemini') || model.baseUrl.includes('googleapis');
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(llms[llmManager.currentModelIndex]);
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -61,4 +74,12 @@ const { t } = useI18n();
|
|||||||
.result-item .iconfont {
|
.result-item .iconfont {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.extra-info.warning {
|
||||||
|
background-color: rgba(230, 162, 60, 0.5);
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -27,6 +27,20 @@
|
|||||||
@change="safeSaveSetting" />
|
@change="safeSaveSetting" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-option">
|
||||||
|
<span>
|
||||||
|
<span class="iconfont icon-proxy"></span>
|
||||||
|
<span class="option-title">{{ t('proxy-server') }}</span>
|
||||||
|
</span>
|
||||||
|
<div style="width: 200px;">
|
||||||
|
<el-input
|
||||||
|
v-model="mcpSetting.proxyServer"
|
||||||
|
:placeholder="'http://localhost:7890'"
|
||||||
|
@input="safeSaveSetting"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -6,12 +6,25 @@ import type { ToolCall } from '@/components/main-panel/chat/chat-box/chat';
|
|||||||
import I18n from '@/i18n';
|
import I18n from '@/i18n';
|
||||||
const { t } = I18n.global;
|
const { t } = I18n.global;
|
||||||
|
|
||||||
export const llms = reactive<any[]>([]);
|
export const llms = reactive<BasicLlmDescription[]>([]);
|
||||||
|
|
||||||
export const llmManager = reactive({
|
export const llmManager = reactive({
|
||||||
currentModelIndex: 0,
|
currentModelIndex: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export interface BasicLlmDescription {
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
baseUrl: string,
|
||||||
|
models: string[],
|
||||||
|
isOpenAICompatible: boolean,
|
||||||
|
description: string,
|
||||||
|
website: string,
|
||||||
|
userToken: string,
|
||||||
|
userModel: string,
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
export function createTest(call: ToolCall) {
|
export function createTest(call: ToolCall) {
|
||||||
const tab = createTab('tool', 0);
|
const tab = createTab('tool', 0);
|
||||||
tab.componentIndex = 2;
|
tab.componentIndex = 2;
|
||||||
@ -21,8 +34,8 @@ export function createTest(call: ToolCall) {
|
|||||||
|
|
||||||
const storage: ToolStorage = {
|
const storage: ToolStorage = {
|
||||||
activeNames: [0],
|
activeNames: [0],
|
||||||
currentToolName: call.function.name,
|
currentToolName: call.function!.name!,
|
||||||
formData: JSON.parse(call.function.arguments)
|
formData: JSON.parse(call.function!.arguments!)
|
||||||
};
|
};
|
||||||
|
|
||||||
tab.storage = storage;
|
tab.storage = storage;
|
||||||
|
@ -35,10 +35,11 @@
|
|||||||
"webpack-node-externals": "^3.0.0"
|
"webpack-node-externals": "^3.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.10.2",
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||||
"@seald-io/nedb": "^4.1.1",
|
"@seald-io/nedb": "^4.1.1",
|
||||||
"open": "^10.1.2",
|
"open": "^10.1.2",
|
||||||
"openai": "^4.96.0",
|
"axios": "^1.9.0",
|
||||||
|
"openai": "^5.0.1",
|
||||||
"pako": "^2.1.0",
|
"pako": "^2.1.0",
|
||||||
"pino": "^9.6.0",
|
"pino": "^9.6.0",
|
||||||
"pino-pretty": "^13.0.0",
|
"pino-pretty": "^13.0.0",
|
||||||
|
211
service/src/hook/axios-fetch.ts
Normal file
211
service/src/hook/axios-fetch.ts
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||||
|
|
||||||
|
interface FetchOptions {
|
||||||
|
method?: string;
|
||||||
|
headers?: Record<string, string>;
|
||||||
|
body?: string | Buffer | FormData | URLSearchParams | object;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FetchResponse {
|
||||||
|
ok: boolean;
|
||||||
|
status: number;
|
||||||
|
statusText: string;
|
||||||
|
headers: Headers;
|
||||||
|
url: string;
|
||||||
|
redirected: boolean;
|
||||||
|
type: string;
|
||||||
|
body: any;
|
||||||
|
|
||||||
|
json(): Promise<any>;
|
||||||
|
text(): Promise<string>;
|
||||||
|
arrayBuffer(): Promise<ArrayBuffer>;
|
||||||
|
getReader(): ReadableStreamDefaultReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReadableStreamDefaultReader {
|
||||||
|
read(): Promise<{ done: boolean, value?: any }>;
|
||||||
|
cancel(): Promise<void>;
|
||||||
|
releaseLock(): void;
|
||||||
|
get closed(): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 axios 配置转换为 fetch 风格的配置
|
||||||
|
*/
|
||||||
|
function adaptRequestOptions(url: string, options: FetchOptions = {}): any {
|
||||||
|
const axiosConfig: any = {
|
||||||
|
url,
|
||||||
|
method: options.method || 'GET',
|
||||||
|
headers: options.headers,
|
||||||
|
responseType: 'stream'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理 body/data 转换
|
||||||
|
if (options.body) {
|
||||||
|
if (typeof options.body === 'string' || Buffer.isBuffer(options.body)) {
|
||||||
|
axiosConfig.data = options.body;
|
||||||
|
} else if (typeof options.body === 'object') {
|
||||||
|
// 如果是 FormData、URLSearchParams 等特殊类型需要特殊处理
|
||||||
|
if (options.body instanceof FormData) {
|
||||||
|
axiosConfig.data = options.body;
|
||||||
|
axiosConfig.headers = {
|
||||||
|
...axiosConfig.headers,
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
};
|
||||||
|
} else if (options.body instanceof URLSearchParams) {
|
||||||
|
axiosConfig.data = options.body.toString();
|
||||||
|
axiosConfig.headers = {
|
||||||
|
...axiosConfig.headers,
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// 普通 JSON 对象
|
||||||
|
axiosConfig.data = JSON.stringify(options.body);
|
||||||
|
axiosConfig.headers = {
|
||||||
|
...axiosConfig.headers,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return axiosConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 axios 响应转换为 fetch 风格的 Response 对象
|
||||||
|
*/
|
||||||
|
function adaptResponse(axiosResponse: FetchOptions): FetchResponse {
|
||||||
|
// 创建 Headers 对象
|
||||||
|
const headers = new Headers();
|
||||||
|
Object.entries(axiosResponse.headers || {}).forEach(([key, value]) => {
|
||||||
|
headers.append(key, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建符合 Fetch API 的 Response 对象
|
||||||
|
const fetchResponse = {
|
||||||
|
ok: axiosResponse.status >= 200 && axiosResponse.status < 300,
|
||||||
|
status: axiosResponse.status,
|
||||||
|
statusText: axiosResponse.statusText,
|
||||||
|
headers: headers,
|
||||||
|
url: axiosResponse.config.url,
|
||||||
|
redirected: false, // axios 不直接提供此信息
|
||||||
|
type: 'basic', // 简单类型
|
||||||
|
body: null,
|
||||||
|
|
||||||
|
// 标准方法
|
||||||
|
json: async () => {
|
||||||
|
if (typeof axiosResponse.data === 'object') {
|
||||||
|
return axiosResponse.data;
|
||||||
|
}
|
||||||
|
throw new Error('Response is not JSON');
|
||||||
|
},
|
||||||
|
text: async () => {
|
||||||
|
if (typeof axiosResponse.data === 'string') {
|
||||||
|
return axiosResponse.data;
|
||||||
|
}
|
||||||
|
return JSON.stringify(axiosResponse.data);
|
||||||
|
},
|
||||||
|
arrayBuffer: async () => {
|
||||||
|
throw new Error('arrayBuffer not implemented for streaming');
|
||||||
|
},
|
||||||
|
|
||||||
|
// 流式支持
|
||||||
|
getReader: () => {
|
||||||
|
if (!axiosResponse.data.on || typeof axiosResponse.data.on !== 'function') {
|
||||||
|
throw new Error('Not a stream response');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 Node.js 流转换为 Web Streams 的 ReadableStream
|
||||||
|
const nodeStream = axiosResponse.data;
|
||||||
|
let isCancelled = false;
|
||||||
|
|
||||||
|
return {
|
||||||
|
read: () => {
|
||||||
|
if (isCancelled) {
|
||||||
|
return Promise.resolve({ done: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const onData = (chunk: any) => {
|
||||||
|
cleanup();
|
||||||
|
resolve({ done: false, value: chunk });
|
||||||
|
};
|
||||||
|
|
||||||
|
const onEnd = () => {
|
||||||
|
cleanup();
|
||||||
|
resolve({ done: true });
|
||||||
|
};
|
||||||
|
|
||||||
|
const onError = (err: Error) => {
|
||||||
|
cleanup();
|
||||||
|
reject(err);
|
||||||
|
};
|
||||||
|
|
||||||
|
const cleanup = () => {
|
||||||
|
nodeStream.off('data', onData);
|
||||||
|
nodeStream.off('end', onEnd);
|
||||||
|
nodeStream.off('error', onError);
|
||||||
|
};
|
||||||
|
|
||||||
|
nodeStream.once('data', onData);
|
||||||
|
nodeStream.once('end', onEnd);
|
||||||
|
nodeStream.once('error', onError);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
cancel: () => {
|
||||||
|
isCancelled = true;
|
||||||
|
nodeStream.destroy();
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
|
||||||
|
releaseLock: () => {
|
||||||
|
// TODO: 实现 releaseLock 方法
|
||||||
|
},
|
||||||
|
|
||||||
|
get closed() {
|
||||||
|
return isCancelled;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} as FetchResponse;
|
||||||
|
|
||||||
|
// 设置 body 为可读流
|
||||||
|
if (axiosResponse.data.on && typeof axiosResponse.data.on === 'function') {
|
||||||
|
fetchResponse.body = {
|
||||||
|
getReader: fetchResponse.getReader
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetchResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 主函数 - 用 axios 实现 fetch
|
||||||
|
*/
|
||||||
|
export async function axiosFetch(input: any, init: any, requestOption: { proxyServer?: string } = {}): Promise<any> {
|
||||||
|
const axiosConfig = adaptRequestOptions(input, init);
|
||||||
|
|
||||||
|
const {
|
||||||
|
proxyServer = ''
|
||||||
|
} = requestOption;
|
||||||
|
|
||||||
|
if (proxyServer) {
|
||||||
|
const proxyAgent = new HttpsProxyAgent(proxyServer);
|
||||||
|
axiosConfig.httpsAgent = proxyAgent;
|
||||||
|
axiosConfig.httpAgent = proxyAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios(axiosConfig) as FetchOptions;
|
||||||
|
return adaptResponse(response);
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.response) {
|
||||||
|
return adaptResponse(error.response);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
@ -47,6 +47,30 @@ export const llms = [
|
|||||||
userToken: '',
|
userToken: '',
|
||||||
userModel: 'doubao-1.5-pro-32k'
|
userModel: 'doubao-1.5-pro-32k'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'gemini',
|
||||||
|
name: 'Gemini',
|
||||||
|
baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai/',
|
||||||
|
models: ['gemini-2.0-flash', 'gemini-2.5-flash-preview-05-20', 'gemini-2.5-pro-preview-05-06'],
|
||||||
|
provider: 'google',
|
||||||
|
isOpenAICompatible: true,
|
||||||
|
description: 'Google Gemini',
|
||||||
|
website: 'https://ai.google.dev/gemini-api/docs/models?hl=zh-cn%2F%2Fgemini-2.5-pro-preview-05-06#gemini-2.5-pro-preview-05-06',
|
||||||
|
userToken: '',
|
||||||
|
userModel: 'gemini-2.0-flash'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'grok',
|
||||||
|
name: 'Grok',
|
||||||
|
baseUrl: 'https://api.x.ai/v1',
|
||||||
|
models: ['grok-3', 'grok-3-fast', 'grok-3-mini', 'grok-3-mini-fast'],
|
||||||
|
provider: 'xai',
|
||||||
|
isOpenAICompatible: true,
|
||||||
|
description: 'xAI Grok',
|
||||||
|
website: 'https://docs.x.ai/docs/models',
|
||||||
|
userToken: '',
|
||||||
|
userModel: 'grok-3-mini'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'mistral',
|
id: 'mistral',
|
||||||
name: 'Mistral',
|
name: 'Mistral',
|
||||||
@ -108,3 +132,5 @@ export const llms = [
|
|||||||
userModel: 'moonshot-v1-8k'
|
userModel: 'moonshot-v1-8k'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { RequestData } from "../common/index.dto.js";
|
|||||||
import { PostMessageble } from "../hook/adapter.js";
|
import { PostMessageble } from "../hook/adapter.js";
|
||||||
import { getClient } from "../mcp/connect.service.js";
|
import { getClient } from "../mcp/connect.service.js";
|
||||||
import { abortMessageService, streamingChatCompletion } from "./llm.service.js";
|
import { abortMessageService, streamingChatCompletion } from "./llm.service.js";
|
||||||
|
import { OpenAI } from "openai";
|
||||||
export class LlmController {
|
export class LlmController {
|
||||||
|
|
||||||
@Controller('llm/chat/completions')
|
@Controller('llm/chat/completions')
|
||||||
@ -35,4 +35,20 @@ export class LlmController {
|
|||||||
return abortMessageService(data, webview);
|
return abortMessageService(data, webview);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Controller('llm/models')
|
||||||
|
async getModels(data: RequestData, webview: PostMessageble) {
|
||||||
|
const {
|
||||||
|
baseURL,
|
||||||
|
apiKey,
|
||||||
|
} = data;
|
||||||
|
|
||||||
|
const client = new OpenAI({ apiKey, baseURL });
|
||||||
|
const models = await client.models.list();
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
msg: models.data
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,3 +7,20 @@ export type MyMessageType = OpenAI.Chat.ChatCompletionMessageParam & {
|
|||||||
export type MyToolMessageType = OpenAI.Chat.ChatCompletionToolMessageParam & {
|
export type MyToolMessageType = OpenAI.Chat.ChatCompletionToolMessageParam & {
|
||||||
extraInfo?: any;
|
extraInfo?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OpenMcpChatOption {
|
||||||
|
baseURL: string;
|
||||||
|
apiKey: string;
|
||||||
|
model: string;
|
||||||
|
messages: any[];
|
||||||
|
temperature?: number;
|
||||||
|
tools?: any[];
|
||||||
|
parallelToolCalls?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MyStream<T> extends AsyncIterable<T> {
|
||||||
|
[Symbol.asyncIterator](): AsyncIterator<T>;
|
||||||
|
controller: {
|
||||||
|
abort(): void;
|
||||||
|
};
|
||||||
|
}
|
@ -5,6 +5,7 @@ import { RestfulResponse } from "../common/index.dto.js";
|
|||||||
import { ocrDB } from "../hook/db.js";
|
import { ocrDB } from "../hook/db.js";
|
||||||
import type { ToolCallContent } from "../mcp/client.dto.js";
|
import type { ToolCallContent } from "../mcp/client.dto.js";
|
||||||
import { ocrWorkerStorage } from "../mcp/ocr.service.js";
|
import { ocrWorkerStorage } from "../mcp/ocr.service.js";
|
||||||
|
import { axiosFetch } from "../hook/axios-fetch.js";
|
||||||
|
|
||||||
export let currentStream: AsyncIterable<any> | null = null;
|
export let currentStream: AsyncIterable<any> | null = null;
|
||||||
|
|
||||||
@ -12,33 +13,51 @@ export async function streamingChatCompletion(
|
|||||||
data: any,
|
data: any,
|
||||||
webview: PostMessageble
|
webview: PostMessageble
|
||||||
) {
|
) {
|
||||||
let {
|
const {
|
||||||
baseURL,
|
baseURL,
|
||||||
apiKey,
|
apiKey,
|
||||||
model,
|
model,
|
||||||
messages,
|
messages,
|
||||||
temperature,
|
temperature,
|
||||||
tools = [],
|
tools = [],
|
||||||
parallelToolCalls = true
|
parallelToolCalls = true,
|
||||||
} = data;
|
proxyServer = ''
|
||||||
|
} = data;
|
||||||
|
|
||||||
const client = new OpenAI({
|
const client = new OpenAI({
|
||||||
baseURL,
|
baseURL,
|
||||||
apiKey
|
apiKey,
|
||||||
|
fetch: async (input: string | URL | Request, init?: RequestInit) => {
|
||||||
|
|
||||||
|
console.log('openai fetch begin, proxyServer:', proxyServer);
|
||||||
|
|
||||||
|
if (model.startsWith('gemini') && init) {
|
||||||
|
// 该死的 google
|
||||||
|
init.headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${apiKey}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return await axiosFetch(input, init, { proxyServer });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (tools.length === 0) {
|
const seriableTools = (tools.length === 0) ? undefined: tools;
|
||||||
tools = undefined;
|
const seriableParallelToolCalls = (tools.length === 0)?
|
||||||
}
|
undefined: model.startsWith('gemini') ? undefined : parallelToolCalls;
|
||||||
|
|
||||||
await postProcessMessages(messages);
|
await postProcessMessages(messages);
|
||||||
|
|
||||||
|
console.log('seriableTools', seriableTools);
|
||||||
|
console.log('seriableParallelToolCalls', seriableParallelToolCalls);
|
||||||
|
|
||||||
const stream = await client.chat.completions.create({
|
const stream = await client.chat.completions.create({
|
||||||
model,
|
model,
|
||||||
messages,
|
messages,
|
||||||
temperature,
|
temperature,
|
||||||
tools,
|
tools: seriableTools,
|
||||||
parallel_tool_calls: parallelToolCalls,
|
parallel_tool_calls: seriableParallelToolCalls,
|
||||||
stream: true
|
stream: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import { VSCodeWebViewLike } from './hook/adapter.js';
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import { setRunningCWD } from './hook/setting.js';
|
import { setRunningCWD } from './hook/setting.js';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
export interface VSCodeMessage {
|
export interface VSCodeMessage {
|
||||||
command: string;
|
command: string;
|
||||||
|
@ -166,11 +166,7 @@ export class McpClient {
|
|||||||
// 调用工具
|
// 调用工具
|
||||||
public async callTool(options: { name: string; arguments: Record<string, any>, callToolOption?: any }) {
|
public async callTool(options: { name: string; arguments: Record<string, any>, callToolOption?: any }) {
|
||||||
const { callToolOption, ...methodArgs } = options;
|
const { callToolOption, ...methodArgs } = options;
|
||||||
console.log('methodArgs', methodArgs);
|
|
||||||
console.log('callToolOption', callToolOption);
|
|
||||||
const res = await this.client.callTool(methodArgs, undefined, callToolOption);
|
const res = await this.client.callTool(methodArgs, undefined, callToolOption);
|
||||||
console.log('callTool res', res);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,6 @@ export class ConnectController {
|
|||||||
async lookupEnvVar(data: RequestData, webview: PostMessageble) {
|
async lookupEnvVar(data: RequestData, webview: PostMessageble) {
|
||||||
const { keys } = data;
|
const { keys } = data;
|
||||||
const values = keys.map((key: string) => {
|
const values = keys.map((key: string) => {
|
||||||
// TODO: 在 Windows 上测试
|
|
||||||
console.log(key);
|
|
||||||
console.log(process.env);
|
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
@ -79,7 +79,6 @@ export class PanelController {
|
|||||||
|
|
||||||
@Controller('system-prompts/load')
|
@Controller('system-prompts/load')
|
||||||
async loadSystemPrompts(data: RequestData, webview: PostMessageble) {
|
async loadSystemPrompts(data: RequestData, webview: PostMessageble) {
|
||||||
const client = getClient(data.clientId);
|
|
||||||
const queryPrompts = await systemPromptDB.findAll();
|
const queryPrompts = await systemPromptDB.findAll();
|
||||||
const prompts = [];
|
const prompts = [];
|
||||||
for (const prompt of queryPrompts) {
|
for (const prompt of queryPrompts) {
|
||||||
|
@ -52,7 +52,11 @@ export function loadSetting(): IConfig {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const configData = fs.readFileSync(configPath, 'utf-8');
|
const configData = fs.readFileSync(configPath, 'utf-8');
|
||||||
return JSON.parse(configData) as IConfig;
|
const config = JSON.parse(configData) as IConfig;
|
||||||
|
if (!config.LLM_INFO || (Array.isArray(config.LLM_INFO) && config.LLM_INFO.length === 0)) {
|
||||||
|
config.LLM_INFO = llms;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading config file, creating new one:', error);
|
console.error('Error loading config file, creating new one:', error);
|
||||||
return createConfig();
|
return createConfig();
|
||||||
|
@ -68,6 +68,19 @@ export function getConnectionConfig() {
|
|||||||
let connection;
|
let connection;
|
||||||
try {
|
try {
|
||||||
connection = JSON.parse(rawConnectionString) as IConnectionConfig;
|
connection = JSON.parse(rawConnectionString) as IConnectionConfig;
|
||||||
|
|
||||||
|
// 对连接信息进行校验
|
||||||
|
if (!connection.items) {
|
||||||
|
connection = { items: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.items = connection.items.filter(item => {
|
||||||
|
if (Array.isArray(item) && item.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
connection = { items: [] };
|
connection = { items: [] };
|
||||||
}
|
}
|
||||||
@ -110,6 +123,19 @@ export function getWorkspaceConnectionConfig() {
|
|||||||
let connection;
|
let connection;
|
||||||
try {
|
try {
|
||||||
connection = JSON.parse(rawConnectionString) as IConnectionConfig;
|
connection = JSON.parse(rawConnectionString) as IConnectionConfig;
|
||||||
|
|
||||||
|
// 对连接信息进行校验
|
||||||
|
if (!connection.items) {
|
||||||
|
connection = { items: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.items = connection.items.filter(item => {
|
||||||
|
if (Array.isArray(item) && item.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
connection = { items: [] };
|
connection = { items: [] };
|
||||||
}
|
}
|
||||||
@ -169,7 +195,7 @@ export function saveWorkspaceConnectionConfig(workspace: string) {
|
|||||||
|
|
||||||
const workspacePath = getWorkspacePath();
|
const workspacePath = getWorkspacePath();
|
||||||
for (let item of connectionConfig.items) {
|
for (let item of connectionConfig.items) {
|
||||||
const connections = Array.isArray(item)? item : [item];
|
const connections = Array.isArray(item) ? item : [item];
|
||||||
for (let connection of connections) {
|
for (let connection of connections) {
|
||||||
const connectionType = (connection.type || connection.connectionType).toUpperCase() as ConnectionType;
|
const connectionType = (connection.type || connection.connectionType).toUpperCase() as ConnectionType;
|
||||||
connection.type = undefined;
|
connection.type = undefined;
|
||||||
@ -283,7 +309,7 @@ export function getWorkspaceConnectionConfigItemByPath(absPath: string) {
|
|||||||
|
|
||||||
const normaliseAbsPath = absPath.replace(/\\/g, '/');
|
const normaliseAbsPath = absPath.replace(/\\/g, '/');
|
||||||
for (let item of workspaceConnectionConfig.items) {
|
for (let item of workspaceConnectionConfig.items) {
|
||||||
const nItem = Array.isArray(item)? item[0] : item;
|
const nItem = Array.isArray(item) ? item[0] : item;
|
||||||
|
|
||||||
const filePath = normaliseConnectionFilePath(nItem, workspacePath);
|
const filePath = normaliseConnectionFilePath(nItem, workspacePath);
|
||||||
if (filePath === normaliseAbsPath) {
|
if (filePath === normaliseAbsPath) {
|
||||||
@ -303,7 +329,7 @@ export function getInstalledConnectionConfigItemByPath(absPath: string) {
|
|||||||
|
|
||||||
const normaliseAbsPath = absPath.replace(/\\/g, '/');
|
const normaliseAbsPath = absPath.replace(/\\/g, '/');
|
||||||
for (let item of installedConnectionConfig.items) {
|
for (let item of installedConnectionConfig.items) {
|
||||||
const nItem = Array.isArray(item)? item[0] : item;
|
const nItem = Array.isArray(item) ? item[0] : item;
|
||||||
|
|
||||||
const filePath = (nItem.filePath || '').replace(/\\/g, '/');
|
const filePath = (nItem.filePath || '').replace(/\\/g, '/');
|
||||||
if (filePath === normaliseAbsPath) {
|
if (filePath === normaliseAbsPath) {
|
||||||
|
@ -58,7 +58,8 @@ export async function acquireInstalledConnection(): Promise<McpOptions[]> {
|
|||||||
// 让用户选择连接类型
|
// 让用户选择连接类型
|
||||||
const connectionType = await vscode.window.showQuickPick(['STDIO', 'SSE', 'STREAMABLE_HTTP'], {
|
const connectionType = await vscode.window.showQuickPick(['STDIO', 'SSE', 'STREAMABLE_HTTP'], {
|
||||||
placeHolder: '请选择连接类型',
|
placeHolder: '请选择连接类型',
|
||||||
canPickMany: false
|
canPickMany: false,
|
||||||
|
ignoreFocusOut: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!connectionType) {
|
if (!connectionType) {
|
||||||
|
@ -63,7 +63,7 @@ export class McpWorkspaceConnectProvider implements vscode.TreeDataProvider<Conn
|
|||||||
|
|
||||||
const item = await acquireUserCustomConnection();
|
const item = await acquireUserCustomConnection();
|
||||||
|
|
||||||
if (!item) {
|
if (item.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +59,10 @@ export async function validateAndGetCommandPath(command: string, cwd?: string):
|
|||||||
|
|
||||||
export async function acquireUserCustomConnection(): Promise<McpOptions[]> {
|
export async function acquireUserCustomConnection(): Promise<McpOptions[]> {
|
||||||
// 让用户选择连接类型
|
// 让用户选择连接类型
|
||||||
const connectionType = await vscode.window.showQuickPick(['STDIO', 'SSE'], {
|
const connectionType = await vscode.window.showQuickPick(['STDIO', 'SSE', 'STREAMABLE_HTTP'], {
|
||||||
placeHolder: '请选择连接类型'
|
placeHolder: '请选择连接类型',
|
||||||
|
canPickMany: false,
|
||||||
|
ignoreFocusOut: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!connectionType) {
|
if (!connectionType) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user