xiaozhi-client 1.9.4-beta.4 → 1.9.4-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/WebServer.js +12 -12
- package/dist/backend/WebServer.js.map +1 -1
- package/dist/backend/WebServerLauncher.js +11 -11
- package/dist/backend/WebServerLauncher.js.map +1 -1
- package/dist/backend/managers/MCPServiceManagerSingleton.js +5 -5
- package/dist/backend/managers/MCPServiceManagerSingleton.js.map +1 -1
- package/dist/backend/package.json +9 -11
- package/dist/backend/templates/default/xiaozhi.cache.json +0 -0
- package/dist/backend/templates/default/xiaozhi.log +0 -0
- package/dist/backend/templates/hello-world/xiaozhi.cache.json +0 -0
- package/dist/backend/templates/hello-world/xiaozhi.log +0 -0
- package/dist/backend/templates/json5/xiaozhi.cache.json +0 -0
- package/dist/backend/templates/json5/xiaozhi.log +0 -0
- package/dist/backend/templates/jsonc/xiaozhi.cache.json +0 -0
- package/dist/backend/templates/jsonc/xiaozhi.log +0 -0
- package/dist/backend/templates/modelscope/xiaozhi.cache.json +0 -0
- package/dist/backend/templates/modelscope/xiaozhi.log +0 -0
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +580 -0
- package/dist/config/index.js +1784 -0
- package/dist/config/index.js.map +1 -0
- package/dist/frontend/assets/index-88NfCOo9.js.map +1 -1
- package/package.json +9 -11
- package/templates/default/xiaozhi.cache.json +0 -0
- package/templates/default/xiaozhi.log +0 -0
- package/templates/hello-world/xiaozhi.cache.json +0 -0
- package/templates/hello-world/xiaozhi.log +0 -0
- package/templates/json5/xiaozhi.cache.json +0 -0
- package/templates/json5/xiaozhi.log +0 -0
- package/templates/jsonc/xiaozhi.cache.json +0 -0
- package/templates/jsonc/xiaozhi.log +0 -0
- package/templates/modelscope/xiaozhi.cache.json +0 -0
- package/templates/modelscope/xiaozhi.log +0 -0
- package/dist/backend/lib/config/manager.js +0 -3
- package/dist/backend/lib/config/manager.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var
|
|
2
|
-
`)}catch{this.safeWrite(t)}},"write")}}safeWrite(e){try{process.stderr&&typeof process.stderr.write=="function"&&process.stderr.write(e)}catch{}}formatConsoleMessageOptimized(e,t){let r=$e(new Date),o=t.get(e.level)||{name:"UNKNOWN",color:a(c=>c,"color")},n=o.color(`[${o.name}]`),i=e.msg;if(e.args&&Array.isArray(e.args)){let c=e.args.map(l=>typeof l=="object"?JSON.stringify(l):String(l)).join(" ");i=`${i} ${c}`}return`[${r}] ${n} ${i}`}initLogFile(e){this.logFilePath=d.join(e,"xiaozhi.log"),this.rotateLogFileIfNeeded(),p.existsSync(this.logFilePath)||p.writeFileSync(this.logFilePath,""),this.pinoInstance=this.createPinoInstance()}enableFileLogging(e){e&&this.logFilePath&&(this.pinoInstance=this.createPinoInstance())}info(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.info(e):this.pinoInstance.info({args:t},e):this.pinoInstance.info(e,t[0]||"")}success(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.info(e):this.pinoInstance.info({args:t},e):this.pinoInstance.info(e,t[0]||"")}warn(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.warn(e):this.pinoInstance.warn({args:t},e):this.pinoInstance.warn(e,t[0]||"")}error(e,...t){if(typeof e=="string")if(t.length===0)this.pinoInstance.error(e);else{let r=t.map(o=>o instanceof Error?this.pinoInstance.level==="debug"?o.message:{message:o.message,stack:o.stack,name:o.name,cause:o.cause}:o);this.pinoInstance.error({args:r},e)}else{let r=this.enhanceErrorObject(e);this.pinoInstance.error(r,t[0]||"")}}debug(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.debug(e):this.pinoInstance.debug({args:t},e):this.pinoInstance.debug(e,t[0]||"")}log(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.info(e):this.pinoInstance.info({args:t},e):this.pinoInstance.info(e,t[0]||"")}enhanceErrorObject(e){let t={...e};for(let[r,o]of Object.entries(t))o instanceof Error&&(t[r]={message:o.message,stack:o.stack,name:o.name,cause:o.cause});return t}rotateLogFileIfNeeded(){if(!(!this.logFilePath||!p.existsSync(this.logFilePath)))try{p.statSync(this.logFilePath).size>this.maxLogFileSize&&this.rotateLogFile()}catch{}}rotateLogFile(){if(this.logFilePath)try{let e=d.dirname(this.logFilePath),t=d.basename(this.logFilePath,".log");for(let o=this.maxLogFiles-1;o>=1;o--){let n=d.join(e,`${t}.${o}.log`),i=d.join(e,`${t}.${o+1}.log`);p.existsSync(n)&&(o===this.maxLogFiles-1?p.unlinkSync(n):p.renameSync(n,i))}let r=d.join(e,`${t}.1.log`);p.renameSync(this.logFilePath,r)}catch{}}cleanupOldLogs(){if(this.logFilePath)try{let e=d.dirname(this.logFilePath),t=d.basename(this.logFilePath,".log");for(let r=this.maxLogFiles+1;r<=this.maxLogFiles+10;r++){let o=d.join(e,`${t}.${r}.log`);p.existsSync(o)&&p.unlinkSync(o)}}catch{}}setLogFileOptions(e,t){this.maxLogFileSize=e,this.maxLogFiles=t}close(){}setLevel(e){this.logLevel=this.validateLogLevel(e),this.pinoInstance=this.createPinoInstance()}getLevel(){return this.logLevel}},Y=null,Le="info";function Ae(){return Y||(Y=new X(Le)),Y}a(Ae,"getLogger");var v=Ae();var te=class extends De{static{a(this,"EventBus")}logger;eventStats=new Map;maxListeners=50;constructor(){super(),this.logger=v,this.setMaxListeners(this.maxListeners),this.setupErrorHandling()}setupErrorHandling(){this.on("error",e=>{this.logger.error("EventBus \u5185\u90E8\u9519\u8BEF:",e)}),this.on("newListener",e=>{let t=this.listenerCount(e);t>this.maxListeners*.8&&this.logger.warn(`\u4E8B\u4EF6 ${e} \u7684\u76D1\u542C\u5668\u6570\u91CF\u8FC7\u591A: ${t}`)})}emitEvent(e,t){try{return this.updateEventStats(e),this.logger.debug(`\u53D1\u5C04\u4E8B\u4EF6: ${e}`,t),super.emit(e,t)}catch(r){return this.logger.error(`\u53D1\u5C04\u4E8B\u4EF6\u5931\u8D25: ${e}`,r),r instanceof Error&&this.emit("error",r),!1}}onEvent(e,t){return this.logger.debug(`\u6DFB\u52A0\u4E8B\u4EF6\u76D1\u542C\u5668: ${e}`),this.on(e,t)}onceEvent(e,t){this.logger.debug(`\u6DFB\u52A0\u4E00\u6B21\u6027\u4E8B\u4EF6\u76D1\u542C\u5668: ${e}`);let r=a(o=>{try{t(o)}catch(n){throw this.emit("error",n),n}finally{this.offEvent(e,r)}},"onceListener");return this.on(e,r)}offEvent(e,t){return this.logger.debug(`\u79FB\u9664\u4E8B\u4EF6\u76D1\u542C\u5668: ${e}`),this.off(e,t)}updateEventStats(e){let t=this.eventStats.get(e)||{count:0,lastEmitted:new Date};t.count++,t.lastEmitted=new Date,this.eventStats.set(e,t)}getEventStats(){let e={};for(let[t,r]of this.eventStats)e[t]={...r};return e}getListenerStats(){let e={};for(let t of this.eventNames())e[t]=this.listenerCount(t);return e}clearEventStats(){this.eventStats.clear(),this.logger.info("\u4E8B\u4EF6\u7EDF\u8BA1\u5DF2\u6E05\u7406")}getStatus(){return{totalEvents:this.eventStats.size,totalListeners:Object.values(this.getListenerStats()).reduce((e,t)=>e+t,0),eventStats:this.getEventStats(),listenerStats:this.getListenerStats()}}destroy(){this.removeAllListeners(),this.eventStats.clear(),this.logger.info("EventBus \u5DF2\u9500\u6BC1")}},ee=null;function S(){return ee||(ee=new te),ee}a(S,"getEventBus");var R;(t=>{function s(r){if(!r||typeof r!="object")return r;let o=JSON.parse(JSON.stringify(r));if(!("type"in o))return o;let n=o.type;if(n==="sse"||n==="streamable-http")return o;let i;return n==="streamableHttp"||n==="streamable_http"?i="streamable-http":n==="s_se"||n==="s-se"?i="sse":i=e(n),(i==="sse"||i==="streamable-http")&&(o.type=i),o}t.normalizeTypeField=s,a(s,"normalizeTypeField");function e(r){return r.replace(/([a-z])([A-Z])/g,"$1-$2").replace(/_/g,"-").toLowerCase()}a(e,"convertToKebabCase")})(R||={});function Oe(s){if(!s||typeof s!="object")throw new Error("\u670D\u52A1\u914D\u7F6E\u5FC5\u987B\u662F\u4E00\u4E2A\u6709\u6548\u7684\u5BF9\u8C61");if("command"in s&&typeof s.command=="string")return"stdio";if("type"in s&&s.type==="sse")return"sse";if("type"in s&&s.type==="streamable-http"||"url"in s&&typeof s.url=="string")return"streamable-http";throw new Error("\u65E0\u6CD5\u8BC6\u522B\u7684 MCP \u670D\u52A1\u914D\u7F6E\u7C7B\u578B\u3002\u914D\u7F6E\u5FC5\u987B\u5305\u542B command \u5B57\u6BB5\uFF08stdio\uFF09\u3001type: 'sse' \u5B57\u6BB5\uFF08sse\uFF09\u6216 url \u5B57\u6BB5\uFF08streamable-http\uFF09")}a(Oe,"getMcpServerCommunicationType");function re(s,e){if(!e||typeof e!="object"||Array.isArray(e))return{valid:!1,error:`\u670D\u52A1 "${s}" \u7684\u914D\u7F6E\u5FC5\u987B\u662F\u4E00\u4E2A\u5BF9\u8C61`};try{let t=Oe(e),r=e;switch(t){case"stdio":if(!r.command||typeof r.command!="string")return{valid:!1,error:`\u670D\u52A1 "${s}" \u7F3A\u5C11\u5FC5\u9700\u7684 command \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};if(!Array.isArray(r.args))return{valid:!1,error:`\u670D\u52A1 "${s}" \u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4`};if(r.env&&(typeof r.env!="object"||Array.isArray(r.env)))return{valid:!1,error:`\u670D\u52A1 "${s}" \u7684 env \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61`};break;case"sse":if(r.type!=="sse")return{valid:!1,error:`\u670D\u52A1 "${s}" \u7684 type \u5B57\u6BB5\u5FC5\u987B\u662F "sse"`};if(!r.url||typeof r.url!="string")return{valid:!1,error:`\u670D\u52A1 "${s}" \u7F3A\u5C11\u5FC5\u9700\u7684 url \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};if(r.headers&&(typeof r.headers!="object"||Array.isArray(r.headers)))return{valid:!1,error:`\u670D\u52A1 "${s}" \u7684 headers \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61`};break;case"streamable-http":if(!r.url||typeof r.url!="string")return{valid:!1,error:`\u670D\u52A1 "${s}" \u7F3A\u5C11\u5FC5\u9700\u7684 url \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};if(r.type&&r.type!=="streamable-http")return{valid:!1,error:`\u670D\u52A1 "${s}" \u7684 type \u5B57\u6BB5\u5982\u679C\u5B58\u5728\uFF0C\u5FC5\u987B\u662F "streamable-http"`};if(r.headers&&(typeof r.headers!="object"||Array.isArray(r.headers)))return{valid:!1,error:`\u670D\u52A1 "${s}" \u7684 headers \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61`};break;default:return{valid:!1,error:`\u670D\u52A1 "${s}" \u7684\u914D\u7F6E\u7C7B\u578B\u65E0\u6CD5\u8BC6\u522B`}}return{valid:!0}}catch(t){return{valid:!1,error:`\u670D\u52A1 "${s}" \u7684\u914D\u7F6E\u65E0\u6548: ${t instanceof Error?t.message:"\u672A\u77E5\u9519\u8BEF"}`}}}a(re,"validateMcpServerConfig");import*as x from"comment-json";import me from"dayjs";import*as D from"comment-json";function ue(s){let e=D.parse(s);return{write(t){e&&typeof e=="object"&&t&&Object.assign(e,t)},toSource(){return D.stringify(e,null,2)}}}a(ue,"createJson5Writer");function ge(s){return D.parse(s)}a(ge,"parseJson5");var pe=Ue(Fe(import.meta.url)),oe={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},ne=class s{static{a(this,"ConfigManager")}static instance;defaultConfigPath;config=null;currentConfigPath=null;json5Writer=null;eventBus=S();statsUpdateLocks=new Map;statsUpdateLockTimeouts=new Map;STATS_UPDATE_TIMEOUT=5e3;constructor(){let e=[T(pe,"templates","default","xiaozhi.config.json"),T(pe,"..","templates","default","xiaozhi.config.json"),T(process.cwd(),"templates","default","xiaozhi.config.json")];this.defaultConfigPath=e.find(t=>U(t))||e[0]}getConfigFilePath(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=["xiaozhi.config.json5","xiaozhi.config.jsonc","xiaozhi.config.json"];for(let r of t){let o=T(e,r);if(U(o))return o}return T(e,"xiaozhi.config.json")}getConfigFileFormat(e){return e.endsWith(".json5")?"json5":e.endsWith(".jsonc")?"jsonc":"json"}static getInstance(){return s.instance||(s.instance=new s),s.instance}configExists(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=["xiaozhi.config.json5","xiaozhi.config.jsonc","xiaozhi.config.json"];for(let r of t){let o=T(e,r);if(U(o))return!0}return!1}initConfig(e="json"){if(!U(this.defaultConfigPath))throw new Error(`\u9ED8\u8BA4\u914D\u7F6E\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${this.defaultConfigPath}`);if(this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let t=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),r=`xiaozhi.config.${e}`,o=T(t,r);ze(this.defaultConfigPath,o),this.config=null,this.json5Writer=null}loadConfig(){if(!this.configExists()){let e=new Error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E");throw this.eventBus.emitEvent("config:error",{error:e,operation:"loadConfig"}),e}try{let e=this.getConfigFilePath();this.currentConfigPath=e;let t=this.getConfigFileFormat(e),o=je(e,"utf8").replace(/^\uFEFF/,""),n;switch(t){case"json5":n=ge(o),this.json5Writer=ue(o);break;case"jsonc":n=x.parse(o);break;default:n=JSON.parse(o);break}return this.validateConfig(n),n}catch(e){throw this.eventBus.emitEvent("config:error",{error:e instanceof Error?e:new Error(String(e)),operation:"loadConfig"}),e instanceof SyntaxError?new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${e.message}`):e}}validateConfig(e){if(!e||typeof e!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A\u6839\u5BF9\u8C61\u65E0\u6548");let t=e;if(t.mcpEndpoint===void 0||t.mcpEndpoint===null)throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(typeof t.mcpEndpoint!="string")if(Array.isArray(t.mcpEndpoint)){for(let r of t.mcpEndpoint)if(typeof r!="string"||r.trim()==="")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216\u5B57\u7B26\u4E32\u6570\u7EC4");if(!t.mcpServers||typeof t.mcpServers!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers \u5B57\u6BB5\u65E0\u6548");for(let[r,o]of Object.entries(t.mcpServers)){if(!o||typeof o!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${r} \u65E0\u6548`);let n=R.normalizeTypeField(o),i=re(r,n);if(!i.valid)throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A${i.error}`)}}getConfig(){return this.config=this.loadConfig(),JSON.parse(JSON.stringify(this.config))}getMutableConfig(){return this.config||(this.config=this.loadConfig()),this.config}getMcpEndpoint(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?e.mcpEndpoint[0]||"":e.mcpEndpoint}getMcpEndpoints(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?[...e.mcpEndpoint]:e.mcpEndpoint?[e.mcpEndpoint]:[]}getMcpServers(){return this.getConfig().mcpServers}getMcpServerConfig(){return this.getConfig().mcpServerConfig||{}}getServerToolsConfig(e){return this.getMcpServerConfig()[e]?.tools||{}}isToolEnabled(e,t){return this.getServerToolsConfig(e)[t]?.enable!==!1}updateMcpEndpoint(e){if(Array.isArray(e)){for(let r of e)if(!r||typeof r!="string")throw new Error("MCP \u7AEF\u70B9\u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}let t=this.getMutableConfig();t.mcpEndpoint=e,this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"endpoint",timestamp:new Date})}addMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig(),r=this.getMcpEndpoints();if(r.includes(e))throw new Error(`MCP \u7AEF\u70B9 ${e} \u5DF2\u5B58\u5728`);let o=[...r,e];t.mcpEndpoint=o,this.saveConfig(t)}removeMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig(),r=this.getMcpEndpoints();if(r.indexOf(e)===-1)throw new Error(`MCP \u7AEF\u70B9 ${e} \u4E0D\u5B58\u5728`);let n=r.filter(i=>i!==e);t.mcpEndpoint=n,this.saveConfig(t)}updateMcpServer(e,t){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let r=re(e,t);if(!r.valid)throw new Error(r.error||"\u670D\u52A1\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");let o=this.getMutableConfig();o.mcpServers[e]=t,this.saveConfig(o)}removeMcpServer(e){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig();if(!t.mcpServers[e])throw new Error(`\u670D\u52A1 ${e} \u4E0D\u5B58\u5728`);if(delete t.mcpServers[e],t.mcpServerConfig?.[e]&&delete t.mcpServerConfig[e],t.customMCP?.tools){let r=t.customMCP.tools.filter(o=>o.handler?.type==="mcp"&&o.handler.config?.serviceName===e);for(let o of r){let n=t.customMCP.tools.findIndex(i=>i.name===o.name);n!==-1&&t.customMCP.tools.splice(n,1)}t.customMCP.tools.length===0&&(t.customMCP=void 0)}this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"customMCP",timestamp:new Date})}updateConfig(e){let t=this.getMutableConfig();if(e.mcpEndpoint!==void 0&&(t.mcpEndpoint=e.mcpEndpoint),e.mcpServers){let r={...t.mcpServers};for(let[o,n]of Object.entries(e.mcpServers))t.mcpServers[o]=n;for(let o of Object.keys(r))o in e.mcpServers||(delete t.mcpServers[o],t.mcpServerConfig?.[o]&&delete t.mcpServerConfig[o])}if(e.connection&&(t.connection||(t.connection={}),Object.assign(t.connection,e.connection)),e.modelscope&&(t.modelscope||(t.modelscope={}),Object.assign(t.modelscope,e.modelscope)),e.webUI&&(t.webUI||(t.webUI={}),Object.assign(t.webUI,e.webUI)),e.mcpServerConfig)for(let[r,o]of Object.entries(e.mcpServerConfig))t.mcpServerConfig?.[r]&&(t.mcpServerConfig[r]=o);if(e.platforms)for(let[r,o]of Object.entries(e.platforms))t.platforms||(t.platforms={}),t.platforms[r]=o;this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"config",timestamp:new Date})}updateServerToolsConfig(e,t){let r=this.getMutableConfig();r.mcpServerConfig||(r.mcpServerConfig={}),Object.keys(t).length===0?delete r.mcpServerConfig[e]:r.mcpServerConfig[e]={tools:t},this.saveConfig(r),this.eventBus.emitEvent("config:updated",{type:"serverTools",serviceName:e,timestamp:new Date})}removeServerToolsConfig(e){let r={...this.getConfig()};r.mcpServerConfig&&(delete r.mcpServerConfig[e],this.saveConfig(r))}cleanupInvalidServerToolsConfig(){let e=this.getMutableConfig();if(!e.mcpServerConfig)return;let t=Object.keys(e.mcpServers),o=Object.keys(e.mcpServerConfig).filter(n=>!t.includes(n));if(o.length>0){for(let n of o)delete e.mcpServerConfig[n];this.saveConfig(e)}}setToolEnabled(e,t,r,o){let n=this.getMutableConfig();n.mcpServerConfig||(n.mcpServerConfig={}),n.mcpServerConfig[e]||(n.mcpServerConfig[e]={tools:{}}),n.mcpServerConfig[e].tools[t]={...n.mcpServerConfig[e].tools[t],enable:r,...o&&{description:o}},this.saveConfig(n)}saveConfig(e){try{this.validateConfig(e);let t;this.currentConfigPath?t=this.currentConfigPath:(t=this.getConfigFilePath(),this.currentConfigPath=t);let r=this.getConfigFileFormat(t),o;switch(r){case"json5":try{this.json5Writer?(this.json5Writer.write(e),o=this.json5Writer.toSource()):o=x.stringify(e,null,2)}catch{o=x.stringify(e,null,2)}break;case"jsonc":try{o=x.stringify(e,null,2)}catch{o=JSON.stringify(e,null,2)}break;default:o=JSON.stringify(e,null,2);break}He(t,o,"utf8"),this.config=e,this.notifyConfigUpdate(e)}catch(t){throw this.eventBus.emitEvent("config:error",{error:t instanceof Error?t:new Error(String(t)),operation:"saveConfig"}),new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}reloadConfig(){this.config=null,this.currentConfigPath=null,this.json5Writer=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}getConnectionConfig(){let t=this.getConfig().connection||{};return{heartbeatInterval:t.heartbeatInterval??oe.heartbeatInterval,heartbeatTimeout:t.heartbeatTimeout??oe.heartbeatTimeout,reconnectInterval:t.reconnectInterval??oe.reconnectInterval}}getHeartbeatInterval(){return this.getConnectionConfig().heartbeatInterval}getHeartbeatTimeout(){return this.getConnectionConfig().heartbeatTimeout}getReconnectInterval(){return this.getConnectionConfig().reconnectInterval}updateConnectionConfig(e){let t=this.getMutableConfig();t.connection||(t.connection={}),Object.assign(t.connection,e),this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"connection",timestamp:new Date})}async updateToolUsageStats(e,t,r){try{if(typeof t=="string"&&r){let o=e,n=t,i=r;await Promise.all([this._updateMCPServerToolStats(o,n,i),this.updateCustomMCPToolStats(o,n,i)])}else{let o=e,n=t,i=new Date().toISOString();await this.updateCustomMCPToolStats(o,i,n)}}catch{if(typeof t=="string"&&r){let n=e,i=t}else{let n=e}}}async updateMCPServerToolStats(e,t,r,o=!0){await this._updateMCPServerToolStats(e,t,r,o)}setHeartbeatInterval(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatInterval:e})}setHeartbeatTimeout(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatTimeout:e})}setReconnectInterval(e){if(e<=0)throw new Error("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({reconnectInterval:e})}getModelScopeConfig(){return this.getConfig().modelscope||{}}getModelScopeApiKey(){return this.getModelScopeConfig().apiKey||process.env.MODELSCOPE_API_TOKEN}updateModelScopeConfig(e){let t=this.getMutableConfig();t.modelscope||(t.modelscope={}),Object.assign(t.modelscope,e),this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"modelscope",timestamp:new Date})}setModelScopeApiKey(e){if(!e||typeof e!="string")throw new Error("API Key \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");this.updateModelScopeConfig({apiKey:e})}getCustomMCPConfig(){return this.getConfig().customMCP||null}getCustomMCPTools(){let e=this.getCustomMCPConfig();return!e||!e.tools?[]:e.tools}validateCustomMCPTools(e){if(!Array.isArray(e))return!1;for(let t of e)if(!t.name||typeof t.name!="string"||!t.description||typeof t.description!="string"||!t.inputSchema||typeof t.inputSchema!="object"||!t.handler||typeof t.handler!="object"||!["proxy","function","http","script","chain","mcp"].includes(t.handler.type)||!this.validateHandlerConfig(t.name,t.handler))return!1;return!0}validateHandlerConfig(e,t){switch(t.type){case"proxy":return this.validateProxyHandler(e,t);case"http":return this.validateHttpHandler(e,t);case"function":return this.validateFunctionHandler(e,t);case"script":return this.validateScriptHandler(e,t);case"chain":return this.validateChainHandler(e,t);case"mcp":return this.validateMCPHandler(e,t);default:return!1}}validateProxyHandler(e,t){return!(!t.platform||!["coze","openai","anthropic","custom"].includes(t.platform)||!t.config||typeof t.config!="object"||t.platform==="coze"&&!t.config.workflow_id&&!t.config.bot_id)}validateHttpHandler(e,t){if(!t.url||typeof t.url!="string")return!1;try{new URL(t.url)}catch{return!1}return!(t.method&&!["GET","POST","PUT","DELETE","PATCH"].includes(t.method))}validateFunctionHandler(e,t){return!(!t.module||typeof t.module!="string"||!t.function||typeof t.function!="string")}validateScriptHandler(e,t){return!(!t.script||typeof t.script!="string"||t.interpreter&&!["node","python","bash"].includes(t.interpreter))}validateChainHandler(e,t){return!(!t.tools||!Array.isArray(t.tools)||t.tools.length===0||!["sequential","parallel"].includes(t.mode)||!["stop","continue","retry"].includes(t.error_handling))}validateMCPHandler(e,t){return!(!t.config||typeof t.config!="object"||!t.config.serviceName||typeof t.config.serviceName!="string"||!t.config.toolName||typeof t.config.toolName!="string")}hasValidCustomMCPTools(){try{let e=this.getCustomMCPTools();return e.length===0?!1:this.validateCustomMCPTools(e)}catch{return!1}}addCustomMCPTool(e){if(!e||typeof e!="object")throw new Error("\u5DE5\u5177\u914D\u7F6E\u4E0D\u80FD\u4E3A\u7A7A");let t=this.getMutableConfig();if(t.customMCP||(t.customMCP={tools:[]}),t.customMCP.tools.find(o=>o.name===e.name))throw new Error(`\u5DE5\u5177 "${e.name}" \u5DF2\u5B58\u5728`);if(!this.validateCustomMCPTools([e]))throw new Error("\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");t.customMCP.tools.unshift(e),this.saveConfig(t)}async addCustomMCPTools(e){if(!Array.isArray(e))throw new Error("\u5DE5\u5177\u914D\u7F6E\u5FC5\u987B\u662F\u6570\u7EC4");if(e.length===0)return;let t=this.getMutableConfig();t.customMCP||(t.customMCP={tools:[]});let r=new Set(t.customMCP.tools.map(n=>n.name)),o=e.filter(n=>!r.has(n.name));if(o.length>0){if(!this.validateCustomMCPTools(o))throw new Error("\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");t.customMCP.tools.push(...o),this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"customMCP",timestamp:new Date})}}removeCustomMCPTool(e){if(!e||typeof e!="string")throw new Error("\u5DE5\u5177\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");let t=this.getMutableConfig();if(!t.customMCP||!t.customMCP.tools)throw new Error("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49 MCP \u5DE5\u5177");let r=t.customMCP.tools.findIndex(o=>o.name===e);if(r===-1)throw new Error(`\u5DE5\u5177 "${e}" \u4E0D\u5B58\u5728`);t.customMCP.tools.splice(r,1),this.saveConfig(t)}updateCustomMCPTool(e,t){if(!e||typeof e!="string")throw new Error("\u5DE5\u5177\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");if(!t||typeof t!="object")throw new Error("\u66F4\u65B0\u540E\u7684\u5DE5\u5177\u914D\u7F6E\u4E0D\u80FD\u4E3A\u7A7A");let r=this.getMutableConfig();if(!r.customMCP||!r.customMCP.tools)throw new Error("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49 MCP \u5DE5\u5177");let o=r.customMCP.tools.findIndex(n=>n.name===e);if(o===-1)throw new Error(`\u5DE5\u5177 "${e}" \u4E0D\u5B58\u5728`);if(!this.validateCustomMCPTools([t]))throw new Error("\u66F4\u65B0\u540E\u7684\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");r.customMCP.tools[o]=t,this.saveConfig(r)}updateCustomMCPTools(e){if(!Array.isArray(e))throw new Error("\u5DE5\u5177\u914D\u7F6E\u5FC5\u987B\u662F\u6570\u7EC4");if(!this.validateCustomMCPTools(e))throw new Error("\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");let t=this.getMutableConfig();t.customMCP||(t.customMCP={tools:[]}),t.customMCP.tools=e,this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"customMCP",timestamp:new Date})}getWebUIConfig(){return this.getConfig().webUI||{}}getWebUIPort(){return this.getWebUIConfig().port??9999}notifyConfigUpdate(e){try{let t=global.__webServer;t&&typeof t.broadcastConfigUpdate=="function"&&t.broadcastConfigUpdate(e)}catch{}}updateWebUIConfig(e){let t=this.getMutableConfig();t.webUI||(t.webUI={}),Object.assign(t.webUI,e),this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"webui",timestamp:new Date})}setWebUIPort(e){if(!Number.isInteger(e)||e<=0||e>65535)throw new Error("\u7AEF\u53E3\u53F7\u5FC5\u987B\u662F 1-65535 \u4E4B\u95F4\u7684\u6574\u6570");this.updateWebUIConfig({port:e})}updatePlatformConfig(e,t){let r=this.getMutableConfig();r.platforms||(r.platforms={}),r.platforms[e]=t,this.saveConfig(r),this.eventBus.emitEvent("config:updated",{type:"platform",platformName:e,timestamp:new Date})}getCozePlatformConfig(){let t=this.getConfig().platforms?.coze;return!t||!t.token?null:{token:t.token}}getCozeToken(){return this.getCozePlatformConfig()?.token||null}setCozePlatformConfig(e){if(!e.token||typeof e.token!="string"||e.token.trim()==="")throw new Error("\u6263\u5B50 API Token \u4E0D\u80FD\u4E3A\u7A7A");this.updatePlatformConfig("coze",{token:e.token.trim()})}isCozeConfigValid(){let e=this.getCozePlatformConfig();return e!==null&&typeof e.token=="string"&&e.token.trim()!==""}async _updateMCPServerToolStats(e,t,r,o=!0){let n=this.getMutableConfig();n.mcpServerConfig||(n.mcpServerConfig={}),n.mcpServerConfig[e]||(n.mcpServerConfig[e]={tools:{}}),n.mcpServerConfig[e].tools[t]||(n.mcpServerConfig[e].tools[t]={enable:!0});let i=n.mcpServerConfig[e].tools[t],c=i.usageCount||0,l=i.lastUsedTime;o&&(i.usageCount=c+1),(!l||new Date(r)>new Date(l))&&(i.lastUsedTime=me(r).format("YYYY-MM-DD HH:mm:ss")),this.saveConfig(n)}async updateCustomMCPToolStats(e,t,r){try{let o,n,i=!0,c;if(typeof r=="string"){let b=e;o=`${b}__${t}`,n=r,c=`${b}/${t}`}else o=e,n=t,i=r||!0,c=o;let l=this.getCustomMCPTools(),u=l.findIndex(b=>b.name===o);if(u===-1)return;let h=[...l],g=h[u];g.stats||(g.stats={});let P=g.stats.usageCount||0,y=g.stats.lastUsedTime;i&&(g.stats.usageCount=P+1),(!y||new Date(n)>new Date(y))&&(g.stats.lastUsedTime=me(n).format("YYYY-MM-DD HH:mm:ss")),await this.updateCustomMCPTools(h)}catch{if(typeof r=="string"){let n=e,i=t}else{let n=e}}}async acquireStatsUpdateLock(e){if(this.statsUpdateLocks.has(e))return!1;let t=new Promise(o=>{});this.statsUpdateLocks.set(e,t);let r=setTimeout(()=>{this.releaseStatsUpdateLock(e)},this.STATS_UPDATE_TIMEOUT);return this.statsUpdateLockTimeouts.set(e,r),!0}releaseStatsUpdateLock(e){this.statsUpdateLocks.delete(e);let t=this.statsUpdateLockTimeouts.get(e);t&&(clearTimeout(t),this.statsUpdateLockTimeouts.delete(e))}async updateToolUsageStatsWithLock(e,t=!0){let r=`custommcp_${e}`;if(await this.acquireStatsUpdateLock(r))try{await this.updateToolUsageStats(e,t)}catch(o){throw o}finally{this.releaseStatsUpdateLock(r)}}async updateMCPServerToolStatsWithLock(e,t,r,o=!0){let n=`mcpserver_${e}_${t}`;if(await this.acquireStatsUpdateLock(n))try{await this.updateMCPServerToolStats(e,t,r,o)}catch(i){throw i}finally{this.releaseStatsUpdateLock(n)}}clearAllStatsUpdateLocks(){let e=this.statsUpdateLocks.size;this.statsUpdateLocks.clear();for(let t of this.statsUpdateLockTimeouts.values())clearTimeout(t);this.statsUpdateLockTimeouts.clear(),e>0}getStatsUpdateLocks(){return Array.from(this.statsUpdateLocks.keys())}getToolCallLogConfig(){return this.getConfig().toolCallLog||{}}updateToolCallLogConfig(e){let t=this.getMutableConfig();t.toolCallLog||(t.toolCallLog={}),Object.assign(t.toolCallLog,e),this.saveConfig(t)}getConfigDir(){return process.env.XIAOZHI_CONFIG_DIR||process.cwd()}},m=ne.getInstance();import{EventEmitter as Qe}from"events";import{isAbsolute as Gt,resolve as Qt}from"path";var N=(r=>(r.STDIO="stdio",r.SSE="sse",r.STREAMABLE_HTTP="streamable-http",r))(N||{});function _e(s){return typeof s=="object"&&s!==null&&"type"in s&&s.type==="object"}a(_e,"isValidToolJSONSchema");function de(s){return _e(s)?s:{type:"object",properties:{},required:[],additionalProperties:!0}}a(de,"ensureToolJSONSchema");var M=class extends Error{constructor(t,r,o){super(r);this.code=t;this.data=o;this.name="ToolCallError"}static{a(this,"ToolCallError")}};function he(s,e){try{let r=new URL(s).pathname;return r.endsWith("/sse")?"sse":r.endsWith("/mcp")?"streamable-http":(e?.serviceName,"streamable-http")}catch{return e?.serviceName,"streamable-http"}}a(he,"inferTransportTypeFromUrl");function fe(s){if(s.type)return R.normalizeTypeField(s);if(s.command)return{...s,type:"stdio"};if(s.url!==void 0&&s.url!==null){let e=he(s.url,{serviceName:s.name});return{...s,type:e}}throw new Error(`\u65E0\u6CD5\u4E3A\u670D\u52A1 ${s.name} \u63A8\u65AD\u4F20\u8F93\u7C7B\u578B\u3002\u8BF7\u663E\u5F0F\u6307\u5B9A type \u5B57\u6BB5\uFF0C\u6216\u63D0\u4F9B command/url \u914D\u7F6E`)}a(fe,"inferTransportTypeFromConfig");function Ce(s,e){let t={validateName:!0,validateArguments:!0,allowEmptyArguments:!0,...e};if(!s||typeof s!="object")throw new M(-32602,"\u8BF7\u6C42\u53C2\u6570\u5FC5\u987B\u662F\u5BF9\u8C61");let r=s;if(t.validateName&&(!r.name||typeof r.name!="string"))throw new M(-32602,"\u5DE5\u5177\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(t.validateArguments&&r.arguments!==void 0&&r.arguments!==null&&(typeof r.arguments!="object"||Array.isArray(r.arguments)))throw new M(-32602,"\u5DE5\u5177\u53C2\u6570\u5FC5\u987B\u662F\u5BF9\u8C61");if(!t.allowEmptyArguments&&r.arguments!==void 0&&r.arguments!==null){let o=r.arguments;if(Object.keys(o).length===0)throw new M(-32602,"\u5DE5\u5177\u53C2\u6570\u4E0D\u80FD\u4E3A\u7A7A")}if(t.customValidator){let o=t.customValidator(r);if(o)throw new M(-32602,o)}return{name:r.name,arguments:r.arguments}}a(Ce,"validateToolCallParams");function ve(s){return s.includes("modelscope.net")||s.includes("modelscope.cn")}a(ve,"isModelScopeURL");var f={};Ne(f,{CozeApiService:()=>k,config:()=>O,createCozeClient:()=>F});var O={zh:{COZE_BASE_URL:"https://api.coze.cn",COZE_BASE_WS_URL:"wss://ws.coze.cn"},en:{COZE_BASE_URL:"https://api.coze.com",COZE_BASE_WS_URL:"wss://ws.coze.com"}};L(f,gr);import*as gr from"@coze/api";function F(s,e="zh"){if(!s||typeof s!="string"||s.trim()==="")throw new Error("\u6263\u5B50 API Token \u4E0D\u80FD\u4E3A\u7A7A");let t=O[e]||O.zh;return new f.CozeAPI({baseURL:t.COZE_BASE_URL,token:s.trim(),baseWsURL:t.COZE_BASE_WS_URL,debug:!1})}a(F,"createCozeClient");import We from"node-cache";var k=class{static{a(this,"CozeApiService")}cache;token;client;constructor(e){this.token=e.trim(),this.client=F(this.token),this.cache=new We({stdTTL:300})}async getWorkspaces(){let e="workspaces",t=this.cache.get(e);if(t)return t;let{workspaces:r=[]}=await this.client.workspaces.list();return this.cache.set(e,r,1800),r}async getWorkflows(e){let{workspace_id:t,page_num:r=1,page_size:o=20}=e;if(!t||typeof t!="string")throw new Error("\u5DE5\u4F5C\u7A7A\u95F4ID\u4E0D\u80FD\u4E3A\u7A7A");let n=`workflows:${t}:${r}:${o}`,i=this.cache.get(n);if(i)return i;let l=(await this.client.get("/v1/workflows",{workspace_id:t,page_num:r,page_size:o,workflow_mode:"workflow"})).data;return this.cache.set(n,l),l}callWorkflow(e,t){return this.client.workflows.runs.create({workflow_id:e,parameters:t})}clearCache(e){if(!e){this.cache.flushAll();return}let r=this.cache.keys().filter(o=>o.startsWith(e));this.cache.del(r)}getCacheStats(){let e=this.cache.getStats(),t=this.cache.keys(),r=e.hits+e.misses,o=r>0?e.hits/r:0;return{size:e.keys,keys:t,hits:e.hits,misses:e.misses,hitRate:o,ksize:e.ksize,vsize:e.vsize}}};import{createHash as Be}from"crypto";function C(s,e){let t=Be("md5").update(JSON.stringify(e||{})).digest("hex");return`${s}_${t}`}a(C,"generateCacheKey");function se(s,e){let t=new Date(s).getTime();return Date.now()-t>e}a(se,"isCacheExpired");function z(s){let e=Date.now(),t=new Date(s.timestamp).getTime();return!!(s.consumed&&e-t>6e4||e-t>s.ttl||s.status==="failed")}a(z,"shouldCleanupCache");var _={TIMEOUT:8e3,CACHE_TTL:3e5,CLEANUP_INTERVAL:6e4,MAX_CACHE_SIZE:1e3,ENABLE_ONE_TIME_CACHE:!0};var j=class s extends Error{static{a(this,"TimeoutError")}name="TimeoutError";constructor(e){super(e),this.name="TimeoutError",Error.captureStackTrace(this,s)}toJSON(){return{name:this.name,message:this.message,stack:this.stack}}};function Se(s,e){return{content:[{type:"text",text:e?Je(e,s):Me(s)}],isError:!1,taskId:s,status:"timeout",message:"\u5DE5\u5177\u8C03\u7528\u8D85\u65F6\uFF0C\u6B63\u5728\u540E\u53F0\u5904\u7406\u4E2D",nextAction:"\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u7B49\u5F85\u4EFB\u52A1\u5B8C\u6210"}}a(Se,"createTimeoutResponse");function Je(s,e){let t={coze_workflow:`\u23F1\uFE0F \u6263\u5B50\u5DE5\u4F5C\u6D41\u6267\u884C\u8D85\u65F6\uFF0C\u6B63\u5728\u540E\u53F0\u5904\u7406\u4E2D...
|
|
1
|
+
var K=Object.defineProperty;var pe=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var fe=Object.prototype.hasOwnProperty;var c=(s,e)=>K(s,"name",{value:e,configurable:!0});var Ce=(s,e)=>{for(var t in e)K(s,t,{get:e[t],enumerable:!0})},re=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of de(e))!fe.call(s,o)&&o!==t&&K(s,o,{get:()=>e[o],enumerable:!(r=pe(e,o))||r.enumerable});return s},R=(s,e,t)=>(re(s,e,"default"),t&&re(t,e,"default"));import{EventEmitter as ke}from"events";import{EventEmitter as ye}from"events";import*as u from"fs";import*as g from"path";import x from"chalk";import P from"pino";import{z as ve}from"zod";var Se=ve.enum(["fatal","error","warn","info","debug","trace"]);function Me(s){let e=s.getFullYear(),t=String(s.getMonth()+1).padStart(2,"0"),r=String(s.getDate()).padStart(2,"0"),o=String(s.getHours()).padStart(2,"0"),n=String(s.getMinutes()).padStart(2,"0"),i=String(s.getSeconds()).padStart(2,"0");return`${e}-${t}-${r} ${o}:${n}:${i}`}c(Me,"formatDateTime");var J=class{static{c(this,"Logger")}logFilePath=null;pinoInstance;isDaemonMode;logLevel;maxLogFileSize=10*1024*1024;maxLogFiles=5;constructor(e="info"){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.logLevel=this.validateLogLevel(e),this.pinoInstance=this.createPinoInstance()}validateLogLevel(e){let t=e.toLowerCase(),r=Se.safeParse(t);return r.success?r.data:"info"}createPinoInstance(){let e=[];if(!this.isDaemonMode){let t=this.createOptimizedConsoleStream();e.push({level:this.logLevel,stream:t})}return this.logFilePath&&e.push({level:this.logLevel,stream:P.destination({dest:this.logFilePath,sync:!1,append:!0,mkdir:!0})}),e.length===0&&e.push({level:this.logLevel,stream:P.destination({dest:"/dev/null"})}),P({level:this.logLevel,timestamp:P.stdTimeFunctions?.isoTime||(()=>`,"time":${Date.now()}`),formatters:{level:c((t,r)=>({level:r}),"level")},base:null,serializers:{err:P.stdSerializers?.err||(t=>t)}},P.multistream(e,{dedupe:!0}))}createOptimizedConsoleStream(){let e=new Map([[20,{name:"DEBUG",color:x.gray}],[30,{name:"INFO",color:x.blue}],[40,{name:"WARN",color:x.yellow}],[50,{name:"ERROR",color:x.red}],[60,{name:"FATAL",color:x.red}]]);return{write:c(t=>{try{let r=JSON.parse(t),o=this.formatConsoleMessageOptimized(r,e);this.safeWrite(`${o}
|
|
2
|
+
`)}catch{this.safeWrite(t)}},"write")}}safeWrite(e){try{process.stderr&&typeof process.stderr.write=="function"&&process.stderr.write(e)}catch{}}formatConsoleMessageOptimized(e,t){let r=Me(new Date),o=t.get(e.level)||{name:"UNKNOWN",color:c(a=>a,"color")},n=o.color(`[${o.name}]`),i=e.msg;if(e.args&&Array.isArray(e.args)){let a=e.args.map(l=>typeof l=="object"?JSON.stringify(l):String(l)).join(" ");i=`${i} ${a}`}return`[${r}] ${n} ${i}`}initLogFile(e){this.logFilePath=g.join(e,"xiaozhi.log"),this.rotateLogFileIfNeeded(),u.existsSync(this.logFilePath)||u.writeFileSync(this.logFilePath,""),this.pinoInstance=this.createPinoInstance()}enableFileLogging(e){e&&this.logFilePath&&(this.pinoInstance=this.createPinoInstance())}info(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.info(e):this.pinoInstance.info({args:t},e):this.pinoInstance.info(e,t[0]||"")}success(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.info(e):this.pinoInstance.info({args:t},e):this.pinoInstance.info(e,t[0]||"")}warn(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.warn(e):this.pinoInstance.warn({args:t},e):this.pinoInstance.warn(e,t[0]||"")}error(e,...t){if(typeof e=="string")if(t.length===0)this.pinoInstance.error(e);else{let r=t.map(o=>o instanceof Error?this.pinoInstance.level==="debug"?o.message:{message:o.message,stack:o.stack,name:o.name,cause:o.cause}:o);this.pinoInstance.error({args:r},e)}else{let r=this.enhanceErrorObject(e);this.pinoInstance.error(r,t[0]||"")}}debug(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.debug(e):this.pinoInstance.debug({args:t},e):this.pinoInstance.debug(e,t[0]||"")}log(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.info(e):this.pinoInstance.info({args:t},e):this.pinoInstance.info(e,t[0]||"")}enhanceErrorObject(e){let t={...e};for(let[r,o]of Object.entries(t))o instanceof Error&&(t[r]={message:o.message,stack:o.stack,name:o.name,cause:o.cause});return t}rotateLogFileIfNeeded(){if(!(!this.logFilePath||!u.existsSync(this.logFilePath)))try{u.statSync(this.logFilePath).size>this.maxLogFileSize&&this.rotateLogFile()}catch{}}rotateLogFile(){if(this.logFilePath)try{let e=g.dirname(this.logFilePath),t=g.basename(this.logFilePath,".log");for(let o=this.maxLogFiles-1;o>=1;o--){let n=g.join(e,`${t}.${o}.log`),i=g.join(e,`${t}.${o+1}.log`);u.existsSync(n)&&(o===this.maxLogFiles-1?u.unlinkSync(n):u.renameSync(n,i))}let r=g.join(e,`${t}.1.log`);u.renameSync(this.logFilePath,r)}catch{}}cleanupOldLogs(){if(this.logFilePath)try{let e=g.dirname(this.logFilePath),t=g.basename(this.logFilePath,".log");for(let r=this.maxLogFiles+1;r<=this.maxLogFiles+10;r++){let o=g.join(e,`${t}.${r}.log`);u.existsSync(o)&&u.unlinkSync(o)}}catch{}}setLogFileOptions(e,t){this.maxLogFileSize=e,this.maxLogFiles=t}close(){}setLevel(e){this.logLevel=this.validateLogLevel(e),this.pinoInstance=this.createPinoInstance()}getLevel(){return this.logLevel}},V=null,Pe="info";function Te(){return V||(V=new J(Pe)),V}c(Te,"getLogger");var v=Te();var Q=class extends ye{static{c(this,"EventBus")}logger;eventStats=new Map;maxListeners=50;constructor(){super(),this.logger=v,this.setMaxListeners(this.maxListeners),this.setupErrorHandling()}setupErrorHandling(){this.on("error",e=>{this.logger.error("EventBus \u5185\u90E8\u9519\u8BEF:",e)}),this.on("newListener",e=>{let t=this.listenerCount(e);t>this.maxListeners*.8&&this.logger.warn(`\u4E8B\u4EF6 ${e} \u7684\u76D1\u542C\u5668\u6570\u91CF\u8FC7\u591A: ${t}`)})}emitEvent(e,t){try{return this.updateEventStats(e),this.logger.debug(`\u53D1\u5C04\u4E8B\u4EF6: ${e}`,t),super.emit(e,t)}catch(r){return this.logger.error(`\u53D1\u5C04\u4E8B\u4EF6\u5931\u8D25: ${e}`,r),r instanceof Error&&this.emit("error",r),!1}}onEvent(e,t){return this.logger.debug(`\u6DFB\u52A0\u4E8B\u4EF6\u76D1\u542C\u5668: ${e}`),this.on(e,t)}onceEvent(e,t){this.logger.debug(`\u6DFB\u52A0\u4E00\u6B21\u6027\u4E8B\u4EF6\u76D1\u542C\u5668: ${e}`);let r=c(o=>{try{t(o)}catch(n){throw this.emit("error",n),n}finally{this.offEvent(e,r)}},"onceListener");return this.on(e,r)}offEvent(e,t){return this.logger.debug(`\u79FB\u9664\u4E8B\u4EF6\u76D1\u542C\u5668: ${e}`),this.off(e,t)}updateEventStats(e){let t=this.eventStats.get(e)||{count:0,lastEmitted:new Date};t.count++,t.lastEmitted=new Date,this.eventStats.set(e,t)}getEventStats(){let e={};for(let[t,r]of this.eventStats)e[t]={...r};return e}getListenerStats(){let e={};for(let t of this.eventNames())e[t]=this.listenerCount(t);return e}clearEventStats(){this.eventStats.clear(),this.logger.info("\u4E8B\u4EF6\u7EDF\u8BA1\u5DF2\u6E05\u7406")}getStatus(){return{totalEvents:this.eventStats.size,totalListeners:Object.values(this.getListenerStats()).reduce((e,t)=>e+t,0),eventStats:this.getEventStats(),listenerStats:this.getListenerStats()}}destroy(){this.removeAllListeners(),this.eventStats.clear(),this.logger.info("EventBus \u5DF2\u9500\u6BC1")}},G=null;function T(){return G||(G=new Q),G}c(T,"getEventBus");import{isModelScopeURL as Ie}from "../config/index.js";import{configManager as h}from "../config/index.js";var d={};Ce(d,{CozeApiService:()=>y,config:()=>N,createCozeClient:()=>D});var N={zh:{COZE_BASE_URL:"https://api.coze.cn",COZE_BASE_WS_URL:"wss://ws.coze.cn"},en:{COZE_BASE_URL:"https://api.coze.com",COZE_BASE_WS_URL:"wss://ws.coze.com"}};R(d,St);import*as St from"@coze/api";function D(s,e="zh"){if(!s||typeof s!="string"||s.trim()==="")throw new Error("\u6263\u5B50 API Token \u4E0D\u80FD\u4E3A\u7A7A");let t=N[e]||N.zh;return new d.CozeAPI({baseURL:t.COZE_BASE_URL,token:s.trim(),baseWsURL:t.COZE_BASE_WS_URL,debug:!1})}c(D,"createCozeClient");import be from"node-cache";var y=class{static{c(this,"CozeApiService")}cache;token;client;constructor(e){this.token=e.trim(),this.client=D(this.token),this.cache=new be({stdTTL:300})}async getWorkspaces(){let e="workspaces",t=this.cache.get(e);if(t)return t;let{workspaces:r=[]}=await this.client.workspaces.list();return this.cache.set(e,r,1800),r}async getWorkflows(e){let{workspace_id:t,page_num:r=1,page_size:o=20}=e;if(!t||typeof t!="string")throw new Error("\u5DE5\u4F5C\u7A7A\u95F4ID\u4E0D\u80FD\u4E3A\u7A7A");let n=`workflows:${t}:${r}:${o}`,i=this.cache.get(n);if(i)return i;let l=(await this.client.get("/v1/workflows",{workspace_id:t,page_num:r,page_size:o,workflow_mode:"workflow"})).data;return this.cache.set(n,l),l}callWorkflow(e,t){return this.client.workflows.runs.create({workflow_id:e,parameters:t})}clearCache(e){if(!e){this.cache.flushAll();return}let r=this.cache.keys().filter(o=>o.startsWith(e));this.cache.del(r)}getCacheStats(){let e=this.cache.getStats(),t=this.cache.keys(),r=e.hits+e.misses,o=r>0?e.hits/r:0;return{size:e.keys,keys:t,hits:e.hits,misses:e.misses,hitRate:o,ksize:e.ksize,vsize:e.vsize}}};var $=(r=>(r.STDIO="stdio",r.SSE="sse",r.STREAMABLE_HTTP="streamable-http",r))($||{});function we(s){return typeof s=="object"&&s!==null&&"type"in s&&s.type==="object"}c(we,"isValidToolJSONSchema");function oe(s){return we(s)?s:{type:"object",properties:{},required:[],additionalProperties:!0}}c(oe,"ensureToolJSONSchema");var S=class extends Error{constructor(t,r,o){super(r);this.code=t;this.data=o;this.name="ToolCallError"}static{c(this,"ToolCallError")}};import{createHash as Ee}from"crypto";function f(s,e){let t=Ee("md5").update(JSON.stringify(e||{})).digest("hex");return`${s}_${t}`}c(f,"generateCacheKey");function Z(s,e){let t=new Date(s).getTime();return Date.now()-t>e}c(Z,"isCacheExpired");function k(s){let e=Date.now(),t=new Date(s.timestamp).getTime();return!!(s.consumed&&e-t>6e4||e-t>s.ttl||s.status==="failed")}c(k,"shouldCleanupCache");var z={TIMEOUT:8e3,CACHE_TTL:3e5,CLEANUP_INTERVAL:6e4,MAX_CACHE_SIZE:1e3,ENABLE_ONE_TIME_CACHE:!0};var I=class s extends Error{static{c(this,"TimeoutError")}name="TimeoutError";constructor(e){super(e),this.name="TimeoutError",Error.captureStackTrace(this,s)}toJSON(){return{name:this.name,message:this.message,stack:this.stack}}};function se(s,e){return{content:[{type:"text",text:e?Re(e,s):ne(s)}],isError:!1,taskId:s,status:"timeout",message:"\u5DE5\u5177\u8C03\u7528\u8D85\u65F6\uFF0C\u6B63\u5728\u540E\u53F0\u5904\u7406\u4E2D",nextAction:"\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u7B49\u5F85\u4EFB\u52A1\u5B8C\u6210"}}c(se,"createTimeoutResponse");function Re(s,e){let t={coze_workflow:`\u23F1\uFE0F \u6263\u5B50\u5DE5\u4F5C\u6D41\u6267\u884C\u8D85\u65F6\uFF0C\u6B63\u5728\u540E\u53F0\u5904\u7406\u4E2D...
|
|
3
3
|
|
|
4
4
|
\u{1F4CB} \u4EFB\u52A1\u4FE1\u606F\uFF1A
|
|
5
5
|
- \u4EFB\u52A1ID: ${e}
|
|
@@ -10,7 +10,7 @@ var q=Object.defineProperty;var Ee=Object.getOwnPropertyDescriptor;var Re=Object
|
|
|
10
10
|
\u{1F504} \u540E\u7EED\u64CD\u4F5C\uFF1A
|
|
11
11
|
1. \u4F7F\u7528\u76F8\u540C\u53C2\u6570\u91CD\u65B0\u8C03\u7528\u5DE5\u5177
|
|
12
12
|
2. \u7CFB\u7EDF\u4F1A\u81EA\u52A8\u8FD4\u56DE\u5DF2\u5B8C\u6210\u7684\u4EFB\u52A1\u7ED3\u679C
|
|
13
|
-
3. \u590D\u6742\u5DE5\u4F5C\u6D41\u53EF\u80FD\u9700\u8981\u66F4\u957F\u65F6\u95F4\u5904\u7406`,default:
|
|
13
|
+
3. \u590D\u6742\u5DE5\u4F5C\u6D41\u53EF\u80FD\u9700\u8981\u66F4\u957F\u65F6\u95F4\u5904\u7406`,default:ne(e)};return t[s]||t.default}c(Re,"getToolSpecificTimeoutMessage");function ne(s){return`\u23F1\uFE0F \u5DE5\u5177\u8C03\u7528\u8D85\u65F6\uFF0C\u6B63\u5728\u540E\u53F0\u5904\u7406\u4E2D...
|
|
14
14
|
|
|
15
15
|
\u{1F4CB} \u4EFB\u52A1\u4FE1\u606F\uFF1A
|
|
16
16
|
- \u4EFB\u52A1ID: ${s}
|
|
@@ -20,8 +20,8 @@ var q=Object.defineProperty;var Ee=Object.getOwnPropertyDescriptor;var Re=Object
|
|
|
20
20
|
\u{1F504} \u540E\u7EED\u64CD\u4F5C\uFF1A
|
|
21
21
|
1. \u4F7F\u7528\u76F8\u540C\u7684\u53C2\u6570\u91CD\u65B0\u8C03\u7528\u5DE5\u5177
|
|
22
22
|
2. \u7CFB\u7EDF\u4F1A\u81EA\u52A8\u8FD4\u56DE\u5DF2\u5B8C\u6210\u7684\u4EFB\u52A1\u7ED3\u679C
|
|
23
|
-
3. \u5982\u679C\u957F\u65F6\u95F4\u672A\u5B8C\u6210\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458`}
|
|
23
|
+
3. \u5982\u679C\u957F\u65F6\u95F4\u672A\u5B8C\u6210\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458`}c(ne,"getDefaultTimeoutMessage");import{configManager as ie}from "../config/index.js";function ae(s){return s.type==="proxy"}c(ae,"isProxyHandler");var O=class{static{c(this,"CustomMCPHandler")}logger;tools=new Map;cacheManager;mcpServiceManager;TIMEOUT=z.TIMEOUT;CACHE_TTL=z.CACHE_TTL;constructor(e,t){this.logger=v,this.cacheManager=e||new b,this.mcpServiceManager=t,this.setupEventListeners()}getCozeApiService(){let e=ie.getConfig().platforms?.coze?.token;if(!e)throw new Error("Coze Token \u914D\u7F6E\u4E0D\u5B58\u5728");return new y(e)}setupEventListeners(){T().onEvent("config:updated",async t=>{if(t.type==="customMCP"){this.logger.info("[CustomMCP] \u68C0\u6D4B\u5230\u914D\u7F6E\u66F4\u65B0\uFF0C\u91CD\u65B0\u521D\u59CB\u5316...");try{this.reinitialize()}catch(r){this.logger.error("[CustomMCP] \u914D\u7F6E\u66F4\u65B0\u5904\u7406\u5931\u8D25:",r)}}})}initialize(e){this.logger.debug("[CustomMCP] \u521D\u59CB\u5316 CustomMCP \u5904\u7406\u5668...");try{let t=e||ie.getCustomMCPTools();this.tools.clear();for(let r of t)if(ae(r.handler)&&r.handler.platform==="coze")this.tools.set(r.name,r),this.logger.debug(`[CustomMCP] \u5DF2\u52A0\u8F7D Coze \u5DE5\u5177: ${r.name} (workflow_id: ${r.handler.config.workflow_id})`);else{let o=ae(r.handler)?`/${r.handler.platform}`:"";this.logger.warn(`[CustomMCP] \u8DF3\u8FC7\u4E0D\u652F\u6301\u7684\u5DE5\u5177\u7C7B\u578B: ${r.name} (${r.handler.type}${o})`)}this.logger.debug(`[CustomMCP] \u521D\u59CB\u5316\u5B8C\u6210\uFF0C\u5171\u52A0\u8F7D ${this.tools.size} \u4E2A Coze \u5DE5\u5177`)}catch(t){throw this.logger.error("[CustomMCP] \u521D\u59CB\u5316\u5931\u8D25:",t),t}}getTools(){return Array.from(this.tools.values()).map(e=>({name:e.name,description:e.description,inputSchema:oe(e.inputSchema)}))}hasTool(e){return this.tools.has(e)}getToolCount(){return this.tools.size}getToolNames(){return Array.from(this.tools.keys())}getToolInfo(e){return this.tools.get(e)}reinitialize(){this.logger.debug("[CustomMCP] \u91CD\u65B0\u521D\u59CB\u5316 CustomMCP \u5904\u7406\u5668..."),this.initialize()}async callTool(e,t,r){let o=this.tools.get(e);if(!o)throw new Error(`\u672A\u627E\u5230\u5DE5\u5177: ${e}`);let n=await this.getCompletedResult(e,t);if(n)return this.logger.debug(`[CustomMCP] \u8FD4\u56DE\u5DF2\u5B8C\u6210\u7684\u4EFB\u52A1\u7ED3\u679C: ${e}`),await this.clearConsumedCache(e,t),n;try{let i=r?.timeout||this.TIMEOUT,a=await Promise.race([this.callCozeWorkflow(o,t),this.createTimeoutPromise(e,i)]);return await this.cacheResult(e,t,a),a}catch(i){if(i instanceof I){let a=await this.generateTaskId(e,t);return this.logger.info(`[CustomMCP] \u5DE5\u5177\u8D85\u65F6\uFF0C\u8FD4\u56DE\u53CB\u597D\u63D0\u793A: ${e}, taskId: ${a}`),se(a,e)}throw i}}async createTimeoutPromise(e,t){return new Promise((r,o)=>{setTimeout(()=>{o(new I(`\u5DE5\u5177\u8C03\u7528\u8D85\u65F6: ${e}`))},t)})}async getCompletedResult(e,t){try{let r=this.generateCacheKey(e,t),o=await this.loadExtendedCache();if(!o.customMCPResults||!o.customMCPResults[r])return null;let n=o.customMCPResults[r];return n.status==="completed"&&!n.consumed&&!Z(n.timestamp,n.ttl)?n.result:null}catch(r){return this.logger.warn(`[CustomMCP] \u83B7\u53D6\u7F13\u5B58\u5931\u8D25: ${r}`),null}}processWorkflowResponse(e,t){try{let r=t.data||t;return typeof r=="string"?{content:[{type:"text",text:r}],isError:!1}:{content:[{type:"text",text:JSON.stringify(r,null,2)}],isError:!1}}catch(r){return this.logger.error(`[CustomMCP] \u5904\u7406\u5DE5\u4F5C\u6D41\u54CD\u5E94\u5931\u8D25: ${e}`,r),{content:[{type:"text",text:`\u5904\u7406\u54CD\u5E94\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async callCozeWorkflow(e,t){let o=e.handler.config;this.logger.info(`[CustomMCP] \u8C03\u7528 Coze \u5DE5\u4F5C\u6D41: ${e.name}`,{workflow_id:o.workflow_id});try{let n=this.getCozeApiService();if(!o.workflow_id)throw new Error("\u5DE5\u4F5C\u6D41ID\u672A\u914D\u7F6E");let i=await n.callWorkflow(o.workflow_id,t);return this.logger.info(`[CustomMCP] Coze \u5DE5\u4F5C\u6D41\u8C03\u7528\u6210\u529F: ${e.name}`),this.processWorkflowResponse(e.name,i)}catch(n){return this.logger.error(`[CustomMCP] Coze \u5DE5\u4F5C\u6D41\u8C03\u7528\u5931\u8D25: ${e.name}`,n),{content:[{type:"text",text:`Coze \u5DE5\u4F5C\u6D41\u8C03\u7528\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`}],isError:!0}}}async clearConsumedCache(e,t){try{let r=this.generateCacheKey(e,t),o=await this.loadExtendedCache();if(o.customMCPResults?.[r]){o.customMCPResults[r].consumed=!0;let n=o.customMCPResults[r];k(n)&&delete o.customMCPResults[r],await this.saveCache(o),this.logger.debug(`[CustomMCP] \u6E05\u7406\u5DF2\u6D88\u8D39\u7F13\u5B58: ${r}`)}}catch(r){this.logger.warn(`[CustomMCP] \u6E05\u7406\u7F13\u5B58\u5931\u8D25: ${r}`)}}async generateTaskId(e,t){return f(e,t)}generateCacheKey(e,t){return f(e,t)}async loadExtendedCache(){try{return await this.cacheManager.loadExistingCache()}catch{return{version:"1.0.0",mcpServers:{},metadata:{lastGlobalUpdate:new Date().toISOString(),totalWrites:0,createdAt:new Date().toISOString()},customMCPResults:{}}}}async updateCacheWithResult(e,t){try{let r=await this.loadExtendedCache();r.customMCPResults||(r.customMCPResults={}),r.customMCPResults[e]=t,await this.saveCache(r)}catch(r){this.logger.warn(`[CustomMCP] \u66F4\u65B0\u7F13\u5B58\u5931\u8D25: ${r}`)}}async cacheResult(e,t,r){try{let o=this.generateCacheKey(e,t),n={result:r,timestamp:new Date().toISOString(),ttl:this.CACHE_TTL,status:"completed",consumed:!1,retryCount:0};await this.updateCacheWithResult(o,n),this.logger.debug(`[CustomMCP] \u7F13\u5B58\u5DE5\u5177\u7ED3\u679C: ${e}`)}catch(o){this.logger.warn(`[CustomMCP] \u7F13\u5B58\u7ED3\u679C\u5931\u8D25: ${o}`)}}async saveCache(e){try{await this.cacheManager.saveCache(e)}catch(t){this.logger.warn(`[CustomMCP] \u4FDD\u5B58\u7F13\u5B58\u5931\u8D25: ${t}`)}}cleanup(){this.logger.info("[CustomMCP] \u6E05\u7406 CustomMCP \u5904\u7406\u5668\u8D44\u6E90"),this.tools.clear(),this.cacheManager.cleanup()}};import*as w from"fs";import*as M from"path";import{tmpdir as xe}from"os";var H=class{static{c(this,"PathUtils")}static getConfigDir(){return process.env.XIAOZHI_CONFIG_DIR||process.cwd()}static getTempDir(){return process.env.TMPDIR||process.env.TEMP||xe()}static getHomeDir(){return process.env.HOME||process.env.USERPROFILE||""}};import F from"pino";var j=class{static{c(this,"ToolCallLogger")}pinoLogger;maxRecords;logFilePath;constructor(e,t){if(this.maxRecords=e?.maxRecords??100,e?.logFilePath)this.logFilePath=M.resolve(M.normalize(e.logFilePath));else{let r=t||H.getTempDir();this.logFilePath=M.join(M.normalize(r),"tool-calls.jsonl")}this.pinoLogger=this.createPinoLogger(this.logFilePath)}createPinoLogger(e){let t=[];t.push({level:"info",stream:{write:c(r=>{try{let o=JSON.parse(r),n=this.formatConsoleMessage(o)}catch{}},"write")}});try{t.push({level:"info",stream:F.destination({dest:e,sync:!0,append:!0,mkdir:!0})})}catch{}return F({level:"info",timestamp:F.stdTimeFunctions?.isoTime||(()=>`,"time":${Date.now()}`),formatters:{level:c((r,o)=>({level:o}),"level")},base:null},F.multistream(t,{dedupe:!0}))}formatConsoleMessage(e){let t=e.toolName||"\u672A\u77E5\u5DE5\u5177",r=e.success!==!1,o=e.duration?` (${e.duration}ms)`:"";return`${r?"\u2705":"\u274C"} ${t}${o}`}async cleanupOldRecords(){try{if(!w.existsSync(this.logFilePath))return;let t=w.readFileSync(this.logFilePath,"utf8").trim().split(`
|
|
24
24
|
`).filter(i=>i.trim()!=="");if(t.length<=this.maxRecords)return;let r=t.length-this.maxRecords+1,o=t.slice(r),n=o.join(`
|
|
25
25
|
`)+(o.length>0?`
|
|
26
|
-
`:"");$.writeFileSync(this.logFilePath,n,"utf8")}catch{}}async recordToolCall(e){try{await this.cleanupOldRecords(),this.pinoLogger.info(e,e.toolName)}catch{}}getLogFilePath(){return this.logFilePath}getMaxRecords(){return this.maxRecords}};var V=class{static{a(this,"MCPMessageHandler")}logger;serviceManager;constructor(e){this.serviceManager=e,this.logger=v}async handleMessage(e){this.logger.debug(`\u5904\u7406 MCP \u6D88\u606F: ${e.method}`,e);try{let t=e.id===void 0;switch(e.method){case"initialize":return await this.handleInitialize(e.params,e.id);case"notifications/initialized":return await this.handleInitializedNotification(e.params);case"tools/list":return await this.handleToolsList(e.id);case"tools/call":return await this.handleToolCall(e.params,e.id);case"resources/list":return await this.handleResourcesList(e.id);case"prompts/list":return await this.handlePromptsList(e.id);case"ping":return await this.handlePing(e.id);default:if(t)return this.logger.warn(`\u6536\u5230\u672A\u77E5\u7684\u901A\u77E5\u6D88\u606F: ${e.method}`,e),null;throw new Error(`\u672A\u77E5\u7684\u65B9\u6CD5: ${e.method}`)}}catch(t){return this.logger.error(`\u5904\u7406\u6D88\u606F\u65F6\u51FA\u9519: ${e.method}`,t),e.id===void 0?null:this.createErrorResponse(t,e.id)}}async handleInitialize(e,t){this.logger.debug("\u5904\u7406 initialize \u8BF7\u6C42",e);let r=["2024-11-05","2025-06-18"],o=e.protocolVersion,n=r.includes(o)?o:"2024-11-05";return this.logger.debug(`\u534F\u8BAE\u7248\u672C\u534F\u5546: \u5BA2\u6237\u7AEF=${o}, \u670D\u52A1\u5668\u54CD\u5E94=${n}`),{jsonrpc:"2.0",result:{serverInfo:{name:"xiaozhi-mcp-server",version:"1.0.0"},capabilities:{tools:{},logging:{}},protocolVersion:n},id:t!==void 0?t:1}}async handleInitializedNotification(e){return this.logger.debug("\u6536\u5230 initialized \u901A\u77E5\uFF0C\u5BA2\u6237\u7AEF\u521D\u59CB\u5316\u5B8C\u6210",e),null}async handleToolsList(e){this.logger.debug("\u5904\u7406 tools/list \u8BF7\u6C42");try{return{jsonrpc:"2.0",result:{tools:this.serviceManager.getAllTools().map(o=>({name:o.name,description:o.description,inputSchema:o.inputSchema}))},id:e!==void 0?e:1}}catch(t){throw this.logger.error("\u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25",t),t}}async handleToolCall(e,t){try{let r=Ce(e),o=await this.serviceManager.callTool(r.name,r.arguments||{});return{jsonrpc:"2.0",result:{content:o.content,isError:o.isError||!1},id:t!==void 0?t:1}}catch(r){throw this.logger.error(`\u5DE5\u5177\u8C03\u7528\u5931\u8D25: ${e.name}`,r),r}}async handlePing(e){return this.logger.debug("\u5904\u7406 ping \u8BF7\u6C42"),{jsonrpc:"2.0",result:{status:"ok",timestamp:new Date().toISOString()},id:e!==void 0?e:1}}async handleResourcesList(e){this.logger.debug("\u5904\u7406 resources/list \u8BF7\u6C42");let t=[];return this.logger.debug(`\u8FD4\u56DE ${t.length} \u4E2A\u8D44\u6E90`),{jsonrpc:"2.0",result:{resources:t},id:e!==void 0?e:1}}async handlePromptsList(e){this.logger.debug("\u5904\u7406 prompts/list \u8BF7\u6C42");let t=[];return this.logger.debug(`\u8FD4\u56DE ${t.length} \u4E2A\u63D0\u793A\u6A21\u677F`),{jsonrpc:"2.0",result:{prompts:t},id:e!==void 0?e:1}}createErrorResponse(e,t){let r=-32603;return e.message.includes("\u672A\u627E\u5230\u5DE5\u5177")||e.message.includes("\u672A\u77E5\u7684\u65B9\u6CD5")?r=-32601:(e.message.includes("\u53C2\u6570")||e.message.includes("\u4E0D\u80FD\u4E3A\u7A7A"))&&(r=-32602),{jsonrpc:"2.0",error:{code:r,message:e.message,data:{stack:e.stack}},id:t!==void 0?t:1}}getServiceManager(){return this.serviceManager}};import Kr,{WebSocketServer as Vr}from"ws";var G=class extends Qe{static{a(this,"MCPServiceManager")}services=new Map;configs={};tools=new Map;customMCPHandler;cacheManager;eventBus=S();toolCallLogger;retryTimers=new Map;failedServices=new Set;transportAdapters=new Map;messageHandler;isRunning=!1;config;constructor(e){super(),e&&this.isUnifiedServerConfig(e)?(this.config={name:"MCPServiceManager",enableLogging:!0,logLevel:"info",...e},this.configs=e.configs||{}):(this.config={name:"MCPServiceManager",enableLogging:!0,logLevel:"info"},this.configs=e||{});let r=process.env.NODE_ENV==="test"||process.env.VITEST==="true"?`/tmp/xiaozhi-test-${Date.now()}-${Math.random().toString(36).substring(2,11)}/xiaozhi.cache.json`:void 0;this.cacheManager=new I(r),this.customMCPHandler=new W(this.cacheManager,this);let o=m.getToolCallLogConfig(),n=m.getConfigDir();this.toolCallLogger=new K(o,n),this.setupEventListeners(),this.messageHandler=new V(this)}setupEventListeners(){this.eventBus.onEvent("mcp:service:connected",async e=>{await this.handleServiceConnected(e)}),this.eventBus.onEvent("mcp:service:disconnected",async e=>{await this.handleServiceDisconnected(e)}),this.eventBus.onEvent("mcp:service:connection:failed",async e=>{await this.handleServiceConnectionFailed(e)})}async handleServiceConnected(e){try{this.services.get(e.serviceName)&&await this.refreshCustomMCPHandlerPublic()}catch{}}async handleServiceDisconnected(e){try{await this.refreshToolsCache(),await this.refreshCustomMCPHandlerPublic()}catch{}}async handleServiceConnectionFailed(e){try{await this.refreshCustomMCPHandlerPublic()}catch{}}async startAllServices(){try{this.customMCPHandler.initialize()}catch{}let e=Object.entries(this.configs);if(e.length===0)return;let t=e.map(async([c])=>{try{return await this.startService(c),{serviceName:c,success:!0,error:null}}catch(l){return{serviceName:c,success:!1,error:l instanceof Error?l.message:String(l)}}}),r=await Promise.allSettled(t),o=0,n=0,i=[];for(let c of r)c.status==="fulfilled"?c.value.success?o++:(n++,i.push(c.value.serviceName)):n++;i.length>0&&e.length,i.length>0&&this.scheduleFailedServicesRetry(i)}async startService(e){let t=this.configs[e];if(!t)throw new Error(`\u672A\u627E\u5230\u670D\u52A1\u914D\u7F6E: ${e}`);try{this.services.has(e)&&await this.stopService(e);let r=new Q(t);await r.connect(),this.services.set(e,r),await this.refreshToolsCache();let o=r.getTools()}catch(r){throw this.services.delete(e),r}}async stopService(e){let t=this.services.get(e);if(t)try{await t.disconnect(),this.services.delete(e),await this.refreshToolsCache()}catch(r){throw r}}async refreshToolsCache(){this.tools.clear();for(let[e,t]of this.services)if(t.isConnected()){let r=t.getTools(),o=this.configs[e];o&&this.cacheManager.writeCacheEntry(e,r,o).then(()=>{}).catch(n=>{});for(let n of r){let i=`${e}__${n.name}`;this.tools.set(i,{serviceName:e,originalName:n.name,tool:n})}}await this.syncToolsConfigToFile()}getAllTools(){let e=[];for(let[r,o]of this.services)try{if(o.isConnected()){let n=o.getTools();for(let i of n)try{if(!m.isToolEnabled(r,i.name))continue;let l=`${r}__${i.name}`;e.push({name:l,description:i.description||"",inputSchema:i.inputSchema,serviceName:r,originalName:i.name})}catch{}}}catch{}let t=[];try{t=this.customMCPHandler.getTools()}catch{t=[]}for(let r of t)try{e.push({name:r.name,description:r.description||"",inputSchema:r.inputSchema,serviceName:this.getServiceNameForTool(r),originalName:r.name})}catch{}return e}getServiceNameForTool(e){return e.handler?.type==="mcp"&&e.handler.config?.serviceName||"customMCP"}getLogServerName(e){if(!e?.handler)return"custom";switch(e.handler.type){case"mcp":return e.handler.config?.serviceName||"customMCP";case"coze":return"coze";case"dify":return"dify";case"n8n":return"n8n";default:return"custom"}}getOriginalToolName(e,t,r){return t?t.handler?.type==="mcp"&&t.handler.config?.toolName||e:r?.originalName||e}async callTool(e,t,r){let o=Date.now(),n="unknown",i=e;try{let c;if(this.customMCPHandler.hasTool(e)){let l=this.customMCPHandler.getToolInfo(e);l&&(n=this.getLogServerName(l),i=this.getOriginalToolName(e,l)),l?.handler?.type==="mcp"?(c=await this.callMCPTool(e,l.handler.config,t),this.updateToolStatsSafe(e,l.handler.config.serviceName,l.handler.config.toolName,!0)):(c=await this.customMCPHandler.callTool(e,t,r),this.updateToolStatsSafe(e,"customMCP",e,!0))}else{let l=this.tools.get(e);if(!l)throw new Error(`\u672A\u627E\u5230\u5DE5\u5177: ${e}`);n=l.serviceName,i=l.originalName;let u=this.services.get(l.serviceName);if(!u)throw new Error(`\u670D\u52A1 ${l.serviceName} \u4E0D\u53EF\u7528`);if(!u.isConnected())throw new Error(`\u670D\u52A1 ${l.serviceName} \u672A\u8FDE\u63A5`);c=await u.callTool(l.originalName,t||{}),this.updateToolStatsSafe(e,l.serviceName,l.originalName,!0)}return this.toolCallLogger.recordToolCall({toolName:i,serverName:n,arguments:t,result:c,success:c.isError!==!0,duration:Date.now()-o}),c}catch(c){if(this.toolCallLogger.recordToolCall({toolName:i,serverName:n,arguments:t,result:null,success:!1,duration:Date.now()-o,error:c instanceof Error?c.message:String(c)}),this.customMCPHandler.hasTool(e)){let l=this.customMCPHandler.getToolInfo(e);l?.handler?.type==="mcp"?this.updateToolStatsSafe(e,l.handler.config.serviceName,l.handler.config.toolName,!1):this.updateToolStatsSafe(e,"customMCP",e,!1)}else{let l=this.tools.get(e);l&&this.updateToolStatsSafe(e,l.serviceName,l.originalName,!1)}throw c}}async updateToolStats(e,t,r,o){try{let n=new Date().toISOString();o?(await this.updateCustomMCPToolStats(e,n),t!=="customMCP"&&await this.updateMCPServerToolStats(t,r,n)):(await this.updateCustomMCPToolLastUsedTime(e,n),t!=="customMCP"&&await this.updateMCPServerToolLastUsedTime(t,r,n))}catch(n){throw n}}async updateToolStatsSafe(e,t,r,o){try{await this.updateToolStats(e,t,r,o)}catch{let i=o?"\u7EDF\u8BA1\u4FE1\u606F":"\u5931\u8D25\u7EDF\u8BA1\u4FE1\u606F"}}async updateCustomMCPToolStats(e,t){try{await m.updateToolUsageStatsWithLock(e,!0)}catch(r){throw r}}async updateCustomMCPToolLastUsedTime(e,t){try{await m.updateToolUsageStatsWithLock(e,!1)}catch(r){throw r}}async updateMCPServerToolStats(e,t,r){try{await m.updateMCPServerToolStatsWithLock(e,t,r,!0)}catch(o){throw o}}async updateMCPServerToolLastUsedTime(e,t,r){try{await m.updateMCPServerToolStatsWithLock(e,t,r,!1)}catch(o){throw o}}async callMCPTool(e,t,r){let{serviceName:o,toolName:n}=t,i=this.services.get(o);if(!i)throw new Error(`\u670D\u52A1 ${o} \u4E0D\u53EF\u7528`);if(!i.isConnected())throw new Error(`\u670D\u52A1 ${o} \u672A\u8FDE\u63A5`);try{return await i.callTool(n,r||{})}catch(c){throw c}}hasTool(e){return this.customMCPHandler.hasTool(e)?!0:this.tools.has(e)}async stopAllServices(){this.stopAllServiceRetries();for(let[e,t]of this.services)try{await t.disconnect()}catch{}try{this.customMCPHandler.cleanup()}catch{}try{m.clearAllStatsUpdateLocks()}catch{}this.services.clear(),this.tools.clear()}getStatus(){return this.getUnifiedStatus()}getStatsUpdateInfo(){try{let e=m.getStatsUpdateLocks();return{activeLocks:e,totalLocks:e.length}}catch{return{activeLocks:[],totalLocks:0}}}getService(e){return this.services.get(e)}getConnectedServices(){let e=[];for(let[t,r]of this.services)r.isConnected()&&e.push(t);return e}async refreshCustomMCPHandler(){try{this.customMCPHandler.initialize()}catch(e){throw e}}async refreshCustomMCPHandlerPublic(){return this.refreshCustomMCPHandler()}getAllServices(){return new Map(this.services)}getCustomMCPHandler(){return this.customMCPHandler}hasCustomMCPTool(e){try{return this.customMCPHandler.hasTool(e)}catch{return!1}}getCustomMCPTools(){try{return this.customMCPHandler.getTools()}catch{return[]}}isModelScopeService(e){return e.url?ve(e.url):!1}handleModelScopeAuth(e,t){if(e.headers?.Authorization)return;let o=m.getModelScopeApiKey();if(o){t.apiKey=o;return}let n=e.url||"\u672A\u77E5",i=e.name||"\u672A\u77E5";throw new Error(`ModelScope \u670D\u52A1 "${i}" \u9700\u8981\u8BA4\u8BC1\u4FE1\u606F\uFF0C\u4F46\u672A\u627E\u5230\u6709\u6548\u7684\u8BA4\u8BC1\u914D\u7F6E\u3002\u670D\u52A1 URL: ${n}\u8BF7\u9009\u62E9\u4EE5\u4E0B\u4EFB\u4E00\u65B9\u5F0F\u914D\u7F6E\u8BA4\u8BC1\uFF1A1. \u5728\u670D\u52A1\u914D\u7F6E\u4E2D\u6DFB\u52A0 headers.Authorization2. \u6216\u8005\u5728\u5168\u5C40\u914D\u7F6E\u4E2D\u8BBE\u7F6E modelscope.apiKey3. \u6216\u8005\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF MODELSCOPE_API_TOKEN\u83B7\u53D6 ModelScope API Key: https://modelscope.cn/my?myInfo=true`)}enhanceServiceConfig(e){let t={...e};try{return this.isModelScopeService(e)&&this.handleModelScopeAuth(e,t),t}catch(r){throw r}}addServiceConfig(e,t){let r,o;if(typeof e=="string"&&t)o=e,r=t;else if(typeof e=="object")o=e.name,r=e;else throw new Error("Invalid arguments for addServiceConfig");let n=this.enhanceServiceConfig(r);this.configs[o]=n}updateServiceConfig(e,t){let r=this.enhanceServiceConfig(t);this.configs[e]=r}removeServiceConfig(e){delete this.configs[e]}async syncToolsConfigToFile(){try{let e=m.getMcpServerConfig();for(let[t,r]of this.services){if(!r.isConnected())continue;let o=r.getTools();if(o.length===0)continue;let n=e[t]?.tools||{},i={};for(let g of o){let P=n[g.name];P?i[g.name]={...P,description:g.description||P.description||""}:i[g.name]={description:g.description||"",enable:!0}}let c=o.map(g=>g.name),u=Object.keys(n).filter(g=>!c.includes(g));if(u.length>0,this.hasToolsConfigChanged(n,i)){m.updateServerToolsConfig(t,i);let g=Object.keys(i).filter(y=>!n[y]),P=Object.keys(i).filter(y=>{let b=n[y],we=i[y];return b&&b.description!==we.description});g.length>0,P.length>0,u.length>0}}}catch{}}hasToolsConfigChanged(e,t){let r=Object.keys(e),o=Object.keys(t);if(r.length!==o.length)return!0;let n=o.filter(c=>!r.includes(c)),i=r.filter(c=>!o.includes(c));if(n.length>0||i.length>0)return!0;for(let c of r){let l=e[c],u=t[c];if(l.description!==u.description)return!0}return!1}scheduleFailedServicesRetry(e){if(e.length===0)return;let t=3e4;for(let r of e)this.failedServices.add(r),this.scheduleServiceRetry(r,t)}scheduleServiceRetry(e,t){let r=this.retryTimers.get(e);r&&(clearTimeout(r),this.retryTimers.delete(e));let o=setTimeout(async()=>{this.retryTimers.delete(e),await this.retryFailedService(e)},t);this.retryTimers.set(e,o)}async retryFailedService(e){if(this.failedServices.has(e))try{await this.startService(e),this.failedServices.delete(e);try{await this.refreshCustomMCPHandlerPublic()}catch{}}catch{let r=this.getRetryDelay(e),o=Math.min(r*2,3e5);this.scheduleServiceRetry(e,o)}}getRetryDelay(e){return 3e4+e.split("").reduce((r,o)=>r+o.charCodeAt(0),0)%6e4}stopServiceRetry(e){let t=this.retryTimers.get(e);t&&(clearTimeout(t),this.retryTimers.delete(e)),this.failedServices.delete(e)}stopAllServiceRetries(){for(let[e,t]of this.retryTimers)clearTimeout(t);this.retryTimers.clear(),this.failedServices.clear()}getFailedServices(){return Array.from(this.failedServices)}isServiceFailed(e){return this.failedServices.has(e)}getRetryStats(){return{failedServices:Array.from(this.failedServices),activeRetries:Array.from(this.retryTimers.keys()),totalFailed:this.failedServices.size,totalActiveRetries:this.retryTimers.size}}async registerTransport(e,t){if(this.transportAdapters.has(e))throw new Error(`\u4F20\u8F93\u9002\u914D\u5668 ${e} \u5DF2\u5B58\u5728`);try{await t.initialize(),this.transportAdapters.set(e,t),this.emit("transportRegistered",{name:e,adapter:t})}catch(r){throw r}}async startTransports(){let e=[],t=[];for(let[r,o]of this.transportAdapters)try{await o.start(),e.push(r)}catch{t.push(r)}if(e.length===0&&t.length>0){let r=`\u6240\u6709\u4F20\u8F93\u9002\u914D\u5668\u542F\u52A8\u5931\u8D25\uFF0C\u5931\u8D25\u7684\u9002\u914D\u5668: ${t.join(", ")}`;throw new Error(r)}t.length>0}async stopTransports(){try{for(let[e,t]of this.transportAdapters)try{await t.stop()}catch{}}catch(e){throw e}}getTransportAdapters(){return new Map(this.transportAdapters)}getMessageHandler(){return this.messageHandler}async start(){if(this.isRunning)throw new Error("\u670D\u52A1\u5668\u5DF2\u5728\u8FD0\u884C");try{await this.startAllServices(),await this.startTransports(),this.isRunning=!0,this.emit("started")}catch(e){throw e}}async stop(){if(this.isRunning)try{await this.stopTransports(),await this.stopAllServices(),this.isRunning=!1,this.emit("stopped")}catch(e){throw e}}getAllConnections(){let e=[];for(let[t,r]of this.services)r.isConnected()&&e.push({id:`service-${t}`,name:t,state:"connected"});for(let[t,r]of this.transportAdapters)e.push({id:r.getConnectionId(),name:t,state:r.getState()});return e}getActiveConnectionCount(){return this.getAllConnections().filter(e=>e.state==="connected").length}getUnifiedStatus(){let e=this.getServiceManagerStatus();return{isRunning:this.isRunning,serviceStatus:e,transportCount:this.getTransportAdapters().size,activeConnections:this.getActiveConnectionCount(),config:this.config,services:e.services,totalTools:e.totalTools,availableTools:e.availableTools}}getServiceManagerStatus(){let e=0,t=[];try{e=this.customMCPHandler.getToolCount(),t=this.customMCPHandler.getToolNames()}catch{e=0,t=[]}let r=this.tools.size+e,n=[...Array.from(this.tools.keys()),...t],i={services:{},totalTools:r,availableTools:n};for(let[c,l]of this.services){let u=l.getStatus();i.services[c]={connected:u.connected,clientName:`xiaozhi-${c}-client`}}return e>0&&(i.services.customMCP={connected:!0,clientName:"xiaozhi-customMCP-handler"}),i}isServerRunning(){return this.isRunning}isUnifiedServerConfig(e){return e!==null&&typeof e=="object"&&"configs"in e}async routeMessage(e){let t=await this.messageHandler.handleMessage(e);return t===null?null:{jsonrpc:"2.0",method:"response",params:t,id:t.id}}async initialize(){await this.start()}getToolRegistry(){return this}getConnectionManager(){return this}};import{Client as ct}from"@modelcontextprotocol/sdk/client/index.js";import{SSEClientTransport as Ze}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as qe}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as Ye}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{EventSource as Xe}from"eventsource";typeof global<"u"&&!global.EventSource&&(global.EventSource=Xe);function et(s){switch(s.type){case"stdio":return tt(s);case"sse":return rt(s);case"streamable-http":return ot(s);default:throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${s.type}`)}}a(et,"createTransport");function tt(s){if(!s.command)throw new Error("stdio transport \u9700\u8981 command \u914D\u7F6E");return new qe({command:s.command,args:s.args||[],env:s.env})}a(tt,"createStdioTransport");function rt(s){if(!s.url)throw new Error("SSE transport \u9700\u8981 URL \u914D\u7F6E");let e=new URL(s.url),t=nt(s);return new Ze(e,t)}a(rt,"createSSETransport");function ot(s){if(!s.url)throw new Error("StreamableHTTP transport \u9700\u8981 URL \u914D\u7F6E");let e=new URL(s.url),t=st(s);return new Ye(e,t)}a(ot,"createStreamableHTTPTransport");function nt(s){let e={};return s.apiKey?e.requestInit={headers:{Authorization:`Bearer ${s.apiKey}`,...s.headers}}:s.headers&&(e.requestInit={headers:s.headers}),e}a(nt,"createSSEOptions");function st(s){let e={};return s.apiKey?e.requestInit={headers:{Authorization:`Bearer ${s.apiKey}`,...s.headers}}:s.headers&&(e.requestInit={headers:s.headers}),e}a(st,"createStreamableHTTPOptions");function it(s){if(!s.name||typeof s.name!="string")throw new Error("\u914D\u7F6E\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 name \u5B57\u6BB5");if(s.type&&!Object.values(N).includes(s.type))throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${s.type}`);if(!s.type)throw new Error("\u4F20\u8F93\u7C7B\u578B\u672A\u8BBE\u7F6E\uFF0C\u8FD9\u5E94\u8BE5\u5728 inferTransportType \u4E2D\u5904\u7406");switch(s.type){case"stdio":if(!s.command)throw new Error("stdio \u7C7B\u578B\u9700\u8981 command \u5B57\u6BB5");break;case"sse":if(s.url===void 0||s.url===null)throw new Error(`${s.type} \u7C7B\u578B\u9700\u8981 url \u5B57\u6BB5`);break;case"streamable-http":if(s.url===void 0||s.url===null)throw new Error(`${s.type} \u7C7B\u578B\u9700\u8981 url \u5B57\u6BB5`);break;default:throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${s.type}`)}}a(it,"validateConfig");function at(){return["stdio","sse","streamable-http"]}a(at,"getSupportedTypes");var ce={create:et,validateConfig:it,getSupportedTypes:at};var Q=class{static{a(this,"MCPService")}config;client=null;transport=null;tools=new Map;connectionState="disconnected";connectionTimeout=null;initialized=!1;eventBus=S();constructor(e){this.config=fe(e),this.validateConfig()}validateConfig(){ce.validateConfig(this.config)}async connect(){if(this.connectionState==="connecting")throw new Error("\u8FDE\u63A5\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u8FDE\u63A5\u5B8C\u6210");return this.cleanupConnection(),this.attemptConnection()}async attemptConnection(){return this.connectionState="connecting",new Promise((e,t)=>{this.connectionTimeout=setTimeout(()=>{let r=new Error(`\u8FDE\u63A5\u8D85\u65F6 (${this.config.timeout||1e4}ms)`);this.handleConnectionError(r),t(r)},this.config.timeout||1e4);try{this.client=new ct({name:`xiaozhi-${this.config.name}-client`,version:"1.0.0"},{capabilities:{}}),this.transport=ce.create(this.config),this.client.connect(this.transport).then(async()=>{this.handleConnectionSuccess(),await this.refreshTools(),this.eventBus.emitEvent("mcp:service:connected",{serviceName:this.config.name,tools:this.getTools(),connectionTime:new Date}),e()}).catch(r=>{this.handleConnectionError(r),t(r)})}catch(r){this.handleConnectionError(r),t(r)}})}handleConnectionSuccess(){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.connectionState="connected",this.initialized=!0}handleConnectionError(e){this.connectionState="disconnected",this.initialized=!1,this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.cleanupConnection(),this.eventBus.emitEvent("mcp:service:connection:failed",{serviceName:this.config.name,error:e,attempt:0})}cleanupConnection(){if(this.client){try{this.client.close().catch(()=>{})}catch{}this.client=null}this.transport=null,this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.initialized=!1}async refreshTools(){if(!this.client)throw new Error("\u5BA2\u6237\u7AEF\u672A\u521D\u59CB\u5316");try{let t=(await this.client.listTools()).tools||[];this.tools.clear();for(let r of t)this.tools.set(r.name,r)}catch(e){throw e}}async disconnect(){this.cleanupConnection(),this.connectionState="disconnected",this.eventBus.emitEvent("mcp:service:disconnected",{serviceName:this.config.name,reason:"\u624B\u52A8\u65AD\u5F00",disconnectionTime:new Date})}getTools(){return Array.from(this.tools.values())}async callTool(e,t){if(!this.client)throw new Error(`\u670D\u52A1 ${this.config.name} \u672A\u8FDE\u63A5`);if(!this.tools.has(e))throw new Error(`\u5DE5\u5177 ${e} \u5728\u670D\u52A1 ${this.config.name} \u4E2D\u4E0D\u5B58\u5728`);try{return await this.client.callTool({name:e,arguments:t||{}})}catch(r){throw r}}getConfig(){return this.config}getStatus(){return{name:this.config.name,connected:this.connectionState==="connected",initialized:this.initialized,transportType:this.config.type||"streamable-http",toolCount:this.tools.size,connectionState:this.connectionState}}isConnected(){return this.connectionState==="connected"&&this.initialized}};import{createHash as lt}from"crypto";import{existsSync as H,mkdirSync as ut,readFileSync as ye,renameSync as gt,writeFileSync as be}from"fs";import{dirname as mt,resolve as Te}from"path";import{Hono as ko}from"hono";import pt from"dayjs";var I=class{static{a(this,"MCPCacheManager")}cachePath;logger;CACHE_VERSION="1.0.0";CACHE_ENTRY_VERSION="1.0.0";cleanupInterval;CLEANUP_INTERVAL=6e4;constructor(e){this.logger=v,this.cachePath=e||this.getCacheFilePath(),this.startCleanupTimer()}formatTimestamp(){return pt().format("YYYY-MM-DD HH:mm:ss")}getCacheFilePath(){try{let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return Te(e,"xiaozhi.cache.json")}catch{let t=process.env.XIAOZHI_CONFIG_DIR||"/tmp";return Te(t,"xiaozhi.cache.json")}}async ensureCacheFile(){try{if(!H(this.cachePath)){let e=mt(this.cachePath);H(e)||(ut(e,{recursive:!0}),this.logger.debug(`[CacheManager] \u5DF2\u521B\u5EFA\u7F13\u5B58\u76EE\u5F55: ${e}`)),this.logger.debug("[CacheManager] \u7F13\u5B58\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u521B\u5EFA\u521D\u59CB\u7F13\u5B58\u6587\u4EF6");let t=await this.createInitialCache();await this.saveCache(t),this.logger.info(`[CacheManager] \u5DF2\u521B\u5EFA\u7F13\u5B58\u6587\u4EF6: ${this.cachePath}`)}}catch(e){this.logger.warn(`[CacheManager] \u521B\u5EFA\u7F13\u5B58\u6587\u4EF6\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}async createInitialCache(){let e=this.formatTimestamp();return{version:this.CACHE_VERSION,mcpServers:{},metadata:{lastGlobalUpdate:e,totalWrites:0,createdAt:e}}}async writeCacheEntry(e,t,r){try{this.logger.debug(`[CacheManager] \u5F00\u59CB\u5199\u5165\u7F13\u5B58: ${e}`),await this.ensureCacheFile();let o=await this.loadExistingCache(),n=this.generateConfigHash(r),i={tools:t.map(c=>({name:c.name,description:c.description||"",inputSchema:c.inputSchema})),lastUpdated:this.formatTimestamp(),serverConfig:{...r},configHash:n,version:this.CACHE_ENTRY_VERSION};o.mcpServers[e]=i,o.metadata.lastGlobalUpdate=this.formatTimestamp(),o.metadata.totalWrites+=1,await this.saveCache(o),this.logger.debug(`[CacheManager] \u7F13\u5B58\u5199\u5165\u6210\u529F: ${e}, \u5DE5\u5177\u6570\u91CF: ${t.length}`)}catch(o){this.logger.warn(`[CacheManager] \u7F13\u5B58\u5199\u5165\u5931\u8D25: ${e}, \u9519\u8BEF: ${o instanceof Error?o.message:String(o)}`)}}async loadExistingCache(){try{if(!H(this.cachePath))return await this.createInitialCache();let e=ye(this.cachePath,"utf8"),t=JSON.parse(e);return this.validateCacheStructure(t)?t:(this.logger.warn("[CacheManager] \u7F13\u5B58\u6587\u4EF6\u7ED3\u6784\u65E0\u6548\uFF0C\u91CD\u65B0\u521B\u5EFA"),await this.createInitialCache())}catch(e){return this.logger.warn(`[CacheManager] \u52A0\u8F7D\u7F13\u5B58\u5931\u8D25\uFF0C\u521B\u5EFA\u65B0\u7F13\u5B58: ${e instanceof Error?e.message:String(e)}`),await this.createInitialCache()}}async saveCache(e){let t=JSON.stringify(e,null,2);await this.atomicWrite(this.cachePath,t)}async atomicWrite(e,t){let r=`${e}.tmp`;try{be(r,t,"utf8"),gt(r,e)}catch(o){try{H(r)&&be(r,"","utf8")}catch{}throw o}}generateConfigHash(e){try{return lt("sha256").update(JSON.stringify(e)).digest("hex")}catch(t){return this.logger.warn(`[CacheManager] \u751F\u6210\u914D\u7F6E\u54C8\u5E0C\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`),""}}validateCacheStructure(e){try{if(!e||typeof e!="object")return!1;let t=e,r=t.metadata;return typeof t.version=="string"&&typeof t.mcpServers=="object"&&t.mcpServers!==null&&t.metadata!==null&&t.metadata!==void 0&&typeof r=="object"&&r!==null&&typeof r.lastGlobalUpdate=="string"&&typeof r.totalWrites=="number"&&typeof r.createdAt=="string"}catch{return!1}}async getStats(){try{let e=await this.loadExistingCache();return{totalWrites:e.metadata.totalWrites,lastUpdate:e.metadata.lastGlobalUpdate,serverCount:Object.keys(e.mcpServers).length,cacheFileSize:H(this.cachePath)?ye(this.cachePath,"utf8").length:0}}catch(e){return this.logger.warn(`[CacheManager] \u83B7\u53D6\u7F13\u5B58\u7EDF\u8BA1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),null}}getFilePath(){return this.cachePath}async getAllCachedTools(){try{let e=await this.loadExistingCache(),t=[];for(let[r,o]of Object.entries(e.mcpServers))for(let n of o.tools)t.push({...n,name:`${r}__${n.name}`});return this.logger.debug(`[CacheManager] \u83B7\u53D6\u5230\u6240\u6709\u7F13\u5B58\u5DE5\u5177\uFF0C\u5171 ${t.length} \u4E2A`),t}catch(e){return this.logger.warn(`[CacheManager] \u83B7\u53D6\u6240\u6709\u7F13\u5B58\u5DE5\u5177\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),[]}}async writeCustomMCPResult(e,t,r,o="completed",n,i=3e5){try{let c=await this.loadExtendedCache(),l=C(e,t),u={result:r,timestamp:new Date().toISOString(),ttl:i,status:o,consumed:!1,taskId:n,retryCount:0};c.customMCPResults||(c.customMCPResults={}),c.customMCPResults[l]=u,await this.saveExtendedCache(c),this.logger.debug(`[CacheManager] \u5199\u5165CustomMCP\u7ED3\u679C\u7F13\u5B58: ${e}, \u72B6\u6001: ${o}`)}catch(c){this.logger.warn(`[CacheManager] \u5199\u5165CustomMCP\u7ED3\u679C\u7F13\u5B58\u5931\u8D25: ${c instanceof Error?c.message:String(c)}`)}}async readCustomMCPResult(e,t){try{let r=await this.loadExtendedCache(),o=C(e,t);if(!r.customMCPResults||!r.customMCPResults[o])return null;let n=r.customMCPResults[o],i=Date.now(),c=new Date(n.timestamp).getTime();return i-c>n.ttl?(this.logger.debug(`[CacheManager] \u7F13\u5B58\u5DF2\u8FC7\u671F: ${e}`),null):n}catch(r){return this.logger.warn(`[CacheManager] \u8BFB\u53D6CustomMCP\u7ED3\u679C\u7F13\u5B58\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`),null}}async updateCustomMCPStatus(e,t,r,o,n){try{let i=await this.loadExtendedCache(),c=C(e,t);if(!i.customMCPResults||!i.customMCPResults[c])return!1;let l=i.customMCPResults[c],u=l.status;return l.status=r,l.timestamp=new Date().toISOString(),o&&(l.result=o),n&&r==="failed"&&(l.result={content:[{type:"text",text:`\u4EFB\u52A1\u5931\u8D25: ${n}`}]},l.consumed=!0),r==="completed"&&(l.consumed=!1),await this.saveExtendedCache(i),this.logger.debug(`[CacheManager] \u66F4\u65B0\u7F13\u5B58\u72B6\u6001: ${e} ${u} -> ${r}`),!0}catch(i){return this.logger.warn(`[CacheManager] \u66F4\u65B0CustomMCP\u7F13\u5B58\u72B6\u6001\u5931\u8D25: ${i instanceof Error?i.message:String(i)}`),!1}}async markCustomMCPAsConsumed(e,t){try{let r=await this.loadExtendedCache(),o=C(e,t);if(!r.customMCPResults||!r.customMCPResults[o])return!1;let n=r.customMCPResults[o];return n.consumed||(n.consumed=!0,n.timestamp=new Date().toISOString(),await this.saveExtendedCache(r),this.logger.debug(`[CacheManager] \u6807\u8BB0\u7F13\u5B58\u4E3A\u5DF2\u6D88\u8D39: ${e}`)),!0}catch(r){return this.logger.warn(`[CacheManager] \u6807\u8BB0CustomMCP\u7F13\u5B58\u4E3A\u5DF2\u6D88\u8D39\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`),!1}}async deleteCustomMCPResult(e,t){try{let r=await this.loadExtendedCache(),o=C(e,t);return!r.customMCPResults||!r.customMCPResults[o]?!1:(delete r.customMCPResults[o],await this.saveExtendedCache(r),this.logger.debug(`[CacheManager] \u5220\u9664\u7F13\u5B58\u6761\u76EE: ${e}`),!0)}catch(r){return this.logger.warn(`[CacheManager] \u5220\u9664CustomMCP\u7F13\u5B58\u6761\u76EE\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`),!1}}async cleanupCustomMCPResults(){try{let e=await this.loadExtendedCache();if(!e.customMCPResults)return{cleaned:0,total:0};let t=Object.entries(e.customMCPResults),r=0;for(let[o,n]of t)z(n)&&(delete e.customMCPResults[o],r++);return r>0&&(await this.saveExtendedCache(e),this.logger.info(`[CacheManager] \u6E05\u7406CustomMCP\u7F13\u5B58: ${r}/${t.length}`)),{cleaned:r,total:t.length}}catch(e){return this.logger.warn(`[CacheManager] \u6E05\u7406CustomMCP\u7F13\u5B58\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),{cleaned:0,total:0}}}async getCustomMCPStatistics(){try{let e=await this.loadExtendedCache();if(!e.customMCPResults)return{totalEntries:0,pendingTasks:0,completedTasks:0,failedTasks:0,consumedEntries:0,cacheHitRate:0,lastCleanupTime:new Date().toISOString(),memoryUsage:0};let t=Object.values(e.customMCPResults),r=t.length,o=t.filter(h=>h.status==="pending").length,n=t.filter(h=>h.status==="completed").length,i=t.filter(h=>h.status==="failed").length,c=t.filter(h=>h.consumed).length,l=n>0?c/n*100:0,u=JSON.stringify(e.customMCPResults).length;return{totalEntries:r,pendingTasks:o,completedTasks:n,failedTasks:i,consumedEntries:c,cacheHitRate:l,lastCleanupTime:new Date().toISOString(),memoryUsage:u}}catch(e){return this.logger.warn(`[CacheManager] \u83B7\u53D6CustomMCP\u7F13\u5B58\u7EDF\u8BA1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),{totalEntries:0,pendingTasks:0,completedTasks:0,failedTasks:0,consumedEntries:0,cacheHitRate:0,lastCleanupTime:new Date().toISOString(),memoryUsage:0}}}async loadExtendedCache(){try{return await this.loadExistingCache()}catch(e){return this.logger.warn(`[CacheManager] \u52A0\u8F7D\u6269\u5C55\u7F13\u5B58\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),{version:this.CACHE_VERSION,mcpServers:{},metadata:{lastGlobalUpdate:this.formatTimestamp(),totalWrites:0,createdAt:this.formatTimestamp()},customMCPResults:{}}}}async saveExtendedCache(e){await this.saveCache(e)}startCleanupTimer(){this.cleanupInterval=setInterval(()=>{this.cleanupCustomMCPResults().catch(e=>{this.logger.warn(`[CacheManager] \u81EA\u52A8\u6E05\u7406\u5931\u8D25: ${e}`)})},this.CLEANUP_INTERVAL),this.logger.debug(`[CacheManager] \u542F\u52A8\u6E05\u7406\u5B9A\u65F6\u5668\uFF0C\u95F4\u9694: ${this.CLEANUP_INTERVAL}ms`)}stopCleanupTimer(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=void 0,this.logger.debug("[CacheManager] \u505C\u6B62\u6E05\u7406\u5B9A\u65F6\u5668"))}cleanup(){this.stopCleanupTimer(),this.logger.debug("[CacheManager] \u6E05\u7406\u8D44\u6E90\u5B8C\u6210")}};var Z=class s{static{a(this,"MCPServiceManagerSingleton")}static instance=null;static getInstance(){if(!s.instance){let e=m.getMcpServers();s.instance=new G(e)}return s.instance}static reset(){s.instance=null}},un=Z.getInstance(),gn=Z;export{gn as default,un as mcpServiceManager};
|
|
26
|
+
`:"");w.writeFileSync(this.logFilePath,n,"utf8")}catch{}}async recordToolCall(e){try{await this.cleanupOldRecords(),this.pinoLogger.info(e,e.toolName)}catch{}}getLogFilePath(){return this.logFilePath}getMaxRecords(){return this.maxRecords}};var W=class{static{c(this,"MCPMessageHandler")}logger;serviceManager;constructor(e){this.serviceManager=e,this.logger=v}async handleMessage(e){this.logger.debug(`\u5904\u7406 MCP \u6D88\u606F: ${e.method}`,e);try{let t=e.id===void 0;switch(e.method){case"initialize":return await this.handleInitialize(e.params,e.id);case"notifications/initialized":return await this.handleInitializedNotification(e.params);case"tools/list":return await this.handleToolsList(e.id);case"tools/call":return await this.handleToolCall(e.params,e.id);case"resources/list":return await this.handleResourcesList(e.id);case"prompts/list":return await this.handlePromptsList(e.id);case"ping":return await this.handlePing(e.id);default:if(t)return this.logger.warn(`\u6536\u5230\u672A\u77E5\u7684\u901A\u77E5\u6D88\u606F: ${e.method}`,e),null;throw new Error(`\u672A\u77E5\u7684\u65B9\u6CD5: ${e.method}`)}}catch(t){return this.logger.error(`\u5904\u7406\u6D88\u606F\u65F6\u51FA\u9519: ${e.method}`,t),e.id===void 0?null:this.createErrorResponse(t,e.id)}}async handleInitialize(e,t){this.logger.debug("\u5904\u7406 initialize \u8BF7\u6C42",e);let r=["2024-11-05","2025-06-18"],o=e.protocolVersion,n=r.includes(o)?o:"2024-11-05";return this.logger.debug(`\u534F\u8BAE\u7248\u672C\u534F\u5546: \u5BA2\u6237\u7AEF=${o}, \u670D\u52A1\u5668\u54CD\u5E94=${n}`),{jsonrpc:"2.0",result:{serverInfo:{name:"xiaozhi-mcp-server",version:"1.0.0"},capabilities:{tools:{},logging:{}},protocolVersion:n},id:t!==void 0?t:1}}async handleInitializedNotification(e){return this.logger.debug("\u6536\u5230 initialized \u901A\u77E5\uFF0C\u5BA2\u6237\u7AEF\u521D\u59CB\u5316\u5B8C\u6210",e),null}async handleToolsList(e){this.logger.debug("\u5904\u7406 tools/list \u8BF7\u6C42");try{return{jsonrpc:"2.0",result:{tools:this.serviceManager.getAllTools().map(o=>({name:o.name,description:o.description,inputSchema:o.inputSchema}))},id:e!==void 0?e:1}}catch(t){throw this.logger.error("\u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25",t),t}}async handleToolCall(e,t){try{let r=ce(e),o=await this.serviceManager.callTool(r.name,r.arguments||{});return{jsonrpc:"2.0",result:{content:o.content,isError:o.isError||!1},id:t!==void 0?t:1}}catch(r){throw this.logger.error(`\u5DE5\u5177\u8C03\u7528\u5931\u8D25: ${e.name}`,r),r}}async handlePing(e){return this.logger.debug("\u5904\u7406 ping \u8BF7\u6C42"),{jsonrpc:"2.0",result:{status:"ok",timestamp:new Date().toISOString()},id:e!==void 0?e:1}}async handleResourcesList(e){this.logger.debug("\u5904\u7406 resources/list \u8BF7\u6C42");let t=[];return this.logger.debug(`\u8FD4\u56DE ${t.length} \u4E2A\u8D44\u6E90`),{jsonrpc:"2.0",result:{resources:t},id:e!==void 0?e:1}}async handlePromptsList(e){this.logger.debug("\u5904\u7406 prompts/list \u8BF7\u6C42");let t=[];return this.logger.debug(`\u8FD4\u56DE ${t.length} \u4E2A\u63D0\u793A\u6A21\u677F`),{jsonrpc:"2.0",result:{prompts:t},id:e!==void 0?e:1}}createErrorResponse(e,t){let r=-32603;return e.message.includes("\u672A\u627E\u5230\u5DE5\u5177")||e.message.includes("\u672A\u77E5\u7684\u65B9\u6CD5")?r=-32601:(e.message.includes("\u53C2\u6570")||e.message.includes("\u4E0D\u80FD\u4E3A\u7A7A"))&&(r=-32602),{jsonrpc:"2.0",error:{code:r,message:e.message,data:{stack:e.stack}},id:t!==void 0?t:1}}getServiceManager(){return this.serviceManager}};import rr,{WebSocketServer as or}from"ws";var U=class extends ke{static{c(this,"MCPServiceManager")}services=new Map;configs={};tools=new Map;customMCPHandler;cacheManager;eventBus=T();toolCallLogger;retryTimers=new Map;failedServices=new Set;transportAdapters=new Map;messageHandler;isRunning=!1;config;constructor(e){super(),e&&this.isUnifiedServerConfig(e)?(this.config={name:"MCPServiceManager",enableLogging:!0,logLevel:"info",...e},this.configs=e.configs||{}):(this.config={name:"MCPServiceManager",enableLogging:!0,logLevel:"info"},this.configs=e||{});let r=process.env.NODE_ENV==="test"||process.env.VITEST==="true"?`/tmp/xiaozhi-test-${Date.now()}-${Math.random().toString(36).substring(2,11)}/xiaozhi.cache.json`:void 0;this.cacheManager=new b(r),this.customMCPHandler=new O(this.cacheManager,this);let o=h.getToolCallLogConfig(),n=h.getConfigDir();this.toolCallLogger=new j(o,n),this.setupEventListeners(),this.messageHandler=new W(this)}setupEventListeners(){this.eventBus.onEvent("mcp:service:connected",async e=>{await this.handleServiceConnected(e)}),this.eventBus.onEvent("mcp:service:disconnected",async e=>{await this.handleServiceDisconnected(e)}),this.eventBus.onEvent("mcp:service:connection:failed",async e=>{await this.handleServiceConnectionFailed(e)})}async handleServiceConnected(e){try{this.services.get(e.serviceName)&&await this.refreshCustomMCPHandlerPublic()}catch{}}async handleServiceDisconnected(e){try{await this.refreshToolsCache(),await this.refreshCustomMCPHandlerPublic()}catch{}}async handleServiceConnectionFailed(e){try{await this.refreshCustomMCPHandlerPublic()}catch{}}async startAllServices(){try{this.customMCPHandler.initialize()}catch{}let e=Object.entries(this.configs);if(e.length===0)return;let t=e.map(async([a])=>{try{return await this.startService(a),{serviceName:a,success:!0,error:null}}catch(l){return{serviceName:a,success:!1,error:l instanceof Error?l.message:String(l)}}}),r=await Promise.allSettled(t),o=0,n=0,i=[];for(let a of r)a.status==="fulfilled"?a.value.success?o++:(n++,i.push(a.value.serviceName)):n++;i.length>0&&e.length,i.length>0&&this.scheduleFailedServicesRetry(i)}async startService(e){let t=this.configs[e];if(!t)throw new Error(`\u672A\u627E\u5230\u670D\u52A1\u914D\u7F6E: ${e}`);try{this.services.has(e)&&await this.stopService(e);let r=new _(t);await r.connect(),this.services.set(e,r),await this.refreshToolsCache();let o=r.getTools()}catch(r){throw this.services.delete(e),r}}async stopService(e){let t=this.services.get(e);if(t)try{await t.disconnect(),this.services.delete(e),await this.refreshToolsCache()}catch(r){throw r}}async refreshToolsCache(){this.tools.clear();for(let[e,t]of this.services)if(t.isConnected()){let r=t.getTools(),o=this.configs[e];o&&this.cacheManager.writeCacheEntry(e,r,o).then(()=>{}).catch(n=>{});for(let n of r){let i=`${e}__${n.name}`;this.tools.set(i,{serviceName:e,originalName:n.name,tool:n})}}await this.syncToolsConfigToFile()}getAllTools(){let e=[];for(let[r,o]of this.services)try{if(o.isConnected()){let n=o.getTools();for(let i of n)try{if(!h.isToolEnabled(r,i.name))continue;let l=`${r}__${i.name}`;e.push({name:l,description:i.description||"",inputSchema:i.inputSchema,serviceName:r,originalName:i.name})}catch{}}}catch{}let t=[];try{t=this.customMCPHandler.getTools()}catch{t=[]}for(let r of t)try{e.push({name:r.name,description:r.description||"",inputSchema:r.inputSchema,serviceName:this.getServiceNameForTool(r),originalName:r.name})}catch{}return e}getServiceNameForTool(e){return e.handler?.type==="mcp"&&e.handler.config?.serviceName||"customMCP"}getLogServerName(e){if(!e?.handler)return"custom";switch(e.handler.type){case"mcp":return e.handler.config?.serviceName||"customMCP";case"coze":return"coze";case"dify":return"dify";case"n8n":return"n8n";default:return"custom"}}getOriginalToolName(e,t,r){return t?t.handler?.type==="mcp"&&t.handler.config?.toolName||e:r?.originalName||e}async callTool(e,t,r){let o=Date.now(),n="unknown",i=e;try{let a;if(this.customMCPHandler.hasTool(e)){let l=this.customMCPHandler.getToolInfo(e);l&&(n=this.getLogServerName(l),i=this.getOriginalToolName(e,l)),l?.handler?.type==="mcp"?(a=await this.callMCPTool(e,l.handler.config,t),this.updateToolStatsSafe(e,l.handler.config.serviceName,l.handler.config.toolName,!0)):(a=await this.customMCPHandler.callTool(e,t,r),this.updateToolStatsSafe(e,"customMCP",e,!0))}else{let l=this.tools.get(e);if(!l)throw new Error(`\u672A\u627E\u5230\u5DE5\u5177: ${e}`);n=l.serviceName,i=l.originalName;let m=this.services.get(l.serviceName);if(!m)throw new Error(`\u670D\u52A1 ${l.serviceName} \u4E0D\u53EF\u7528`);if(!m.isConnected())throw new Error(`\u670D\u52A1 ${l.serviceName} \u672A\u8FDE\u63A5`);a=await m.callTool(l.originalName,t||{}),this.updateToolStatsSafe(e,l.serviceName,l.originalName,!0)}return this.toolCallLogger.recordToolCall({toolName:i,serverName:n,arguments:t,result:a,success:a.isError!==!0,duration:Date.now()-o}),a}catch(a){if(this.toolCallLogger.recordToolCall({toolName:i,serverName:n,arguments:t,result:null,success:!1,duration:Date.now()-o,error:a instanceof Error?a.message:String(a)}),this.customMCPHandler.hasTool(e)){let l=this.customMCPHandler.getToolInfo(e);l?.handler?.type==="mcp"?this.updateToolStatsSafe(e,l.handler.config.serviceName,l.handler.config.toolName,!1):this.updateToolStatsSafe(e,"customMCP",e,!1)}else{let l=this.tools.get(e);l&&this.updateToolStatsSafe(e,l.serviceName,l.originalName,!1)}throw a}}async updateToolStats(e,t,r,o){try{let n=new Date().toISOString();o?(await this.updateCustomMCPToolStats(e,n),t!=="customMCP"&&await this.updateMCPServerToolStats(t,r,n)):(await this.updateCustomMCPToolLastUsedTime(e,n),t!=="customMCP"&&await this.updateMCPServerToolLastUsedTime(t,r,n))}catch(n){throw n}}async updateToolStatsSafe(e,t,r,o){try{await this.updateToolStats(e,t,r,o)}catch{let i=o?"\u7EDF\u8BA1\u4FE1\u606F":"\u5931\u8D25\u7EDF\u8BA1\u4FE1\u606F"}}async updateCustomMCPToolStats(e,t){try{await h.updateToolUsageStatsWithLock(e,!0)}catch(r){throw r}}async updateCustomMCPToolLastUsedTime(e,t){try{await h.updateToolUsageStatsWithLock(e,!1)}catch(r){throw r}}async updateMCPServerToolStats(e,t,r){try{await h.updateMCPServerToolStatsWithLock(e,t,r,!0)}catch(o){throw o}}async updateMCPServerToolLastUsedTime(e,t,r){try{await h.updateMCPServerToolStatsWithLock(e,t,r,!1)}catch(o){throw o}}async callMCPTool(e,t,r){let{serviceName:o,toolName:n}=t,i=this.services.get(o);if(!i)throw new Error(`\u670D\u52A1 ${o} \u4E0D\u53EF\u7528`);if(!i.isConnected())throw new Error(`\u670D\u52A1 ${o} \u672A\u8FDE\u63A5`);try{return await i.callTool(n,r||{})}catch(a){throw a}}hasTool(e){return this.customMCPHandler.hasTool(e)?!0:this.tools.has(e)}async stopAllServices(){this.stopAllServiceRetries();for(let[e,t]of this.services)try{await t.disconnect()}catch{}try{this.customMCPHandler.cleanup()}catch{}try{h.clearAllStatsUpdateLocks()}catch{}this.services.clear(),this.tools.clear()}getStatus(){return this.getUnifiedStatus()}getStatsUpdateInfo(){try{let e=h.getStatsUpdateLocks();return{activeLocks:e,totalLocks:e.length}}catch{return{activeLocks:[],totalLocks:0}}}getService(e){return this.services.get(e)}getConnectedServices(){let e=[];for(let[t,r]of this.services)r.isConnected()&&e.push(t);return e}async refreshCustomMCPHandler(){try{this.customMCPHandler.initialize()}catch(e){throw e}}async refreshCustomMCPHandlerPublic(){return this.refreshCustomMCPHandler()}getAllServices(){return new Map(this.services)}getCustomMCPHandler(){return this.customMCPHandler}hasCustomMCPTool(e){try{return this.customMCPHandler.hasTool(e)}catch{return!1}}getCustomMCPTools(){try{return this.customMCPHandler.getTools()}catch{return[]}}isModelScopeService(e){return e.url?Ie(e.url):!1}handleModelScopeAuth(e,t){if(e.headers?.Authorization)return;let o=h.getModelScopeApiKey();if(o){t.apiKey=o;return}let n=e.url||"\u672A\u77E5",i=e.name||"\u672A\u77E5";throw new Error(`ModelScope \u670D\u52A1 "${i}" \u9700\u8981\u8BA4\u8BC1\u4FE1\u606F\uFF0C\u4F46\u672A\u627E\u5230\u6709\u6548\u7684\u8BA4\u8BC1\u914D\u7F6E\u3002\u670D\u52A1 URL: ${n}\u8BF7\u9009\u62E9\u4EE5\u4E0B\u4EFB\u4E00\u65B9\u5F0F\u914D\u7F6E\u8BA4\u8BC1\uFF1A1. \u5728\u670D\u52A1\u914D\u7F6E\u4E2D\u6DFB\u52A0 headers.Authorization2. \u6216\u8005\u5728\u5168\u5C40\u914D\u7F6E\u4E2D\u8BBE\u7F6E modelscope.apiKey3. \u6216\u8005\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF MODELSCOPE_API_TOKEN\u83B7\u53D6 ModelScope API Key: https://modelscope.cn/my?myInfo=true`)}enhanceServiceConfig(e){let t={...e};try{return this.isModelScopeService(e)&&this.handleModelScopeAuth(e,t),t}catch(r){throw r}}addServiceConfig(e,t){let r,o;if(typeof e=="string"&&t)o=e,r=t;else if(typeof e=="object")o=e.name,r=e;else throw new Error("Invalid arguments for addServiceConfig");let n=this.enhanceServiceConfig(r);this.configs[o]=n}updateServiceConfig(e,t){let r=this.enhanceServiceConfig(t);this.configs[e]=r}removeServiceConfig(e){delete this.configs[e]}async syncToolsConfigToFile(){try{let e=h.getMcpServerConfig();for(let[t,r]of this.services){if(!r.isConnected())continue;let o=r.getTools();if(o.length===0)continue;let n=e[t]?.tools||{},i={};for(let p of o){let E=n[p.name];E?i[p.name]={...E,description:p.description||E.description||""}:i[p.name]={description:p.description||"",enable:!0}}let a=o.map(p=>p.name),m=Object.keys(n).filter(p=>!a.includes(p));if(m.length>0,this.hasToolsConfigChanged(n,i)){h.updateServerToolsConfig(t,i);let p=Object.keys(i).filter(A=>!n[A]),E=Object.keys(i).filter(A=>{let te=n[A],he=i[A];return te&&te.description!==he.description});p.length>0,E.length>0,m.length>0}}}catch{}}hasToolsConfigChanged(e,t){let r=Object.keys(e),o=Object.keys(t);if(r.length!==o.length)return!0;let n=o.filter(a=>!r.includes(a)),i=r.filter(a=>!o.includes(a));if(n.length>0||i.length>0)return!0;for(let a of r){let l=e[a],m=t[a];if(l.description!==m.description)return!0}return!1}scheduleFailedServicesRetry(e){if(e.length===0)return;let t=3e4;for(let r of e)this.failedServices.add(r),this.scheduleServiceRetry(r,t)}scheduleServiceRetry(e,t){let r=this.retryTimers.get(e);r&&(clearTimeout(r),this.retryTimers.delete(e));let o=setTimeout(async()=>{this.retryTimers.delete(e),await this.retryFailedService(e)},t);this.retryTimers.set(e,o)}async retryFailedService(e){if(this.failedServices.has(e))try{await this.startService(e),this.failedServices.delete(e);try{await this.refreshCustomMCPHandlerPublic()}catch{}}catch{let r=this.getRetryDelay(e),o=Math.min(r*2,3e5);this.scheduleServiceRetry(e,o)}}getRetryDelay(e){return 3e4+e.split("").reduce((r,o)=>r+o.charCodeAt(0),0)%6e4}stopServiceRetry(e){let t=this.retryTimers.get(e);t&&(clearTimeout(t),this.retryTimers.delete(e)),this.failedServices.delete(e)}stopAllServiceRetries(){for(let[e,t]of this.retryTimers)clearTimeout(t);this.retryTimers.clear(),this.failedServices.clear()}getFailedServices(){return Array.from(this.failedServices)}isServiceFailed(e){return this.failedServices.has(e)}getRetryStats(){return{failedServices:Array.from(this.failedServices),activeRetries:Array.from(this.retryTimers.keys()),totalFailed:this.failedServices.size,totalActiveRetries:this.retryTimers.size}}async registerTransport(e,t){if(this.transportAdapters.has(e))throw new Error(`\u4F20\u8F93\u9002\u914D\u5668 ${e} \u5DF2\u5B58\u5728`);try{await t.initialize(),this.transportAdapters.set(e,t),this.emit("transportRegistered",{name:e,adapter:t})}catch(r){throw r}}async startTransports(){let e=[],t=[];for(let[r,o]of this.transportAdapters)try{await o.start(),e.push(r)}catch{t.push(r)}if(e.length===0&&t.length>0){let r=`\u6240\u6709\u4F20\u8F93\u9002\u914D\u5668\u542F\u52A8\u5931\u8D25\uFF0C\u5931\u8D25\u7684\u9002\u914D\u5668: ${t.join(", ")}`;throw new Error(r)}t.length>0}async stopTransports(){try{for(let[e,t]of this.transportAdapters)try{await t.stop()}catch{}}catch(e){throw e}}getTransportAdapters(){return new Map(this.transportAdapters)}getMessageHandler(){return this.messageHandler}async start(){if(this.isRunning)throw new Error("\u670D\u52A1\u5668\u5DF2\u5728\u8FD0\u884C");try{await this.startAllServices(),await this.startTransports(),this.isRunning=!0,this.emit("started")}catch(e){throw e}}async stop(){if(this.isRunning)try{await this.stopTransports(),await this.stopAllServices(),this.isRunning=!1,this.emit("stopped")}catch(e){throw e}}getAllConnections(){let e=[];for(let[t,r]of this.services)r.isConnected()&&e.push({id:`service-${t}`,name:t,state:"connected"});for(let[t,r]of this.transportAdapters)e.push({id:r.getConnectionId(),name:t,state:r.getState()});return e}getActiveConnectionCount(){return this.getAllConnections().filter(e=>e.state==="connected").length}getUnifiedStatus(){let e=this.getServiceManagerStatus();return{isRunning:this.isRunning,serviceStatus:e,transportCount:this.getTransportAdapters().size,activeConnections:this.getActiveConnectionCount(),config:this.config,services:e.services,totalTools:e.totalTools,availableTools:e.availableTools}}getServiceManagerStatus(){let e=0,t=[];try{e=this.customMCPHandler.getToolCount(),t=this.customMCPHandler.getToolNames()}catch{e=0,t=[]}let r=this.tools.size+e,n=[...Array.from(this.tools.keys()),...t],i={services:{},totalTools:r,availableTools:n};for(let[a,l]of this.services){let m=l.getStatus();i.services[a]={connected:m.connected,clientName:`xiaozhi-${a}-client`}}return e>0&&(i.services.customMCP={connected:!0,clientName:"xiaozhi-customMCP-handler"}),i}isServerRunning(){return this.isRunning}isUnifiedServerConfig(e){return e!==null&&typeof e=="object"&&"configs"in e}async routeMessage(e){let t=await this.messageHandler.handleMessage(e);return t===null?null:{jsonrpc:"2.0",method:"response",params:t,id:t.id}}async initialize(){await this.start()}getToolRegistry(){return this}getConnectionManager(){return this}};import{Client as Ve}from"@modelcontextprotocol/sdk/client/index.js";import{SSEClientTransport as Le}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as Ae}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as De}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{EventSource as ze}from"eventsource";typeof global<"u"&&!global.EventSource&&(global.EventSource=ze);function Oe(s){switch(s.type){case"stdio":return He(s);case"sse":return Fe(s);case"streamable-http":return je(s);default:throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${s.type}`)}}c(Oe,"createTransport");function He(s){if(!s.command)throw new Error("stdio transport \u9700\u8981 command \u914D\u7F6E");return new Ae({command:s.command,args:s.args||[],env:s.env})}c(He,"createStdioTransport");function Fe(s){if(!s.url)throw new Error("SSE transport \u9700\u8981 URL \u914D\u7F6E");let e=new URL(s.url),t=We(s);return new Le(e,t)}c(Fe,"createSSETransport");function je(s){if(!s.url)throw new Error("StreamableHTTP transport \u9700\u8981 URL \u914D\u7F6E");let e=new URL(s.url),t=Ue(s);return new De(e,t)}c(je,"createStreamableHTTPTransport");function We(s){let e={};return s.apiKey?e.requestInit={headers:{Authorization:`Bearer ${s.apiKey}`,...s.headers}}:s.headers&&(e.requestInit={headers:s.headers}),e}c(We,"createSSEOptions");function Ue(s){let e={};return s.apiKey?e.requestInit={headers:{Authorization:`Bearer ${s.apiKey}`,...s.headers}}:s.headers&&(e.requestInit={headers:s.headers}),e}c(Ue,"createStreamableHTTPOptions");function _e(s){if(!s.name||typeof s.name!="string")throw new Error("\u914D\u7F6E\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 name \u5B57\u6BB5");if(s.type&&!Object.values($).includes(s.type))throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${s.type}`);if(!s.type)throw new Error("\u4F20\u8F93\u7C7B\u578B\u672A\u8BBE\u7F6E\uFF0C\u8FD9\u5E94\u8BE5\u5728 inferTransportType \u4E2D\u5904\u7406");switch(s.type){case"stdio":if(!s.command)throw new Error("stdio \u7C7B\u578B\u9700\u8981 command \u5B57\u6BB5");break;case"sse":if(s.url===void 0||s.url===null)throw new Error(`${s.type} \u7C7B\u578B\u9700\u8981 url \u5B57\u6BB5`);break;case"streamable-http":if(s.url===void 0||s.url===null)throw new Error(`${s.type} \u7C7B\u578B\u9700\u8981 url \u5B57\u6BB5`);break;default:throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${s.type}`)}}c(_e,"validateConfig");function Be(){return["stdio","sse","streamable-http"]}c(Be,"getSupportedTypes");var X={create:Oe,validateConfig:_e,getSupportedTypes:Be};var ee;(t=>{function s(r){if(!r||typeof r!="object")return r;let o=JSON.parse(JSON.stringify(r));if(!("type"in o))return o;let n=o.type;if(n==="sse"||n==="streamable-http")return o;let i;return n==="streamableHttp"||n==="streamable_http"?i="streamable-http":n==="s_se"||n==="s-se"?i="sse":i=e(n),(i==="sse"||i==="streamable-http")&&(o.type=i),o}t.normalizeTypeField=s,c(s,"normalizeTypeField");function e(r){return r.replace(/([a-z])([A-Z])/g,"$1-$2").replace(/_/g,"-").toLowerCase()}c(e,"convertToKebabCase")})(ee||={});function Ke(s,e){try{let r=new URL(s).pathname;return r.endsWith("/sse")?"sse":r.endsWith("/mcp")?"streamable-http":(e?.serviceName,"streamable-http")}catch{return e?.serviceName,"streamable-http"}}c(Ke,"inferTransportTypeFromUrl");function le(s){if(s.type)return ee.normalizeTypeField(s);if(s.command)return{...s,type:"stdio"};if(s.url!==void 0&&s.url!==null){let e=Ke(s.url,{serviceName:s.name});return{...s,type:e}}throw new Error(`\u65E0\u6CD5\u4E3A\u670D\u52A1 ${s.name} \u63A8\u65AD\u4F20\u8F93\u7C7B\u578B\u3002\u8BF7\u663E\u5F0F\u6307\u5B9A type \u5B57\u6BB5\uFF0C\u6216\u63D0\u4F9B command/url \u914D\u7F6E`)}c(le,"inferTransportTypeFromConfig");function ce(s,e){let t={validateName:!0,validateArguments:!0,allowEmptyArguments:!0,...e};if(!s||typeof s!="object")throw new S(-32602,"\u8BF7\u6C42\u53C2\u6570\u5FC5\u987B\u662F\u5BF9\u8C61");let r=s;if(t.validateName&&(!r.name||typeof r.name!="string"))throw new S(-32602,"\u5DE5\u5177\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(t.validateArguments&&r.arguments!==void 0&&r.arguments!==null&&(typeof r.arguments!="object"||Array.isArray(r.arguments)))throw new S(-32602,"\u5DE5\u5177\u53C2\u6570\u5FC5\u987B\u662F\u5BF9\u8C61");if(!t.allowEmptyArguments&&r.arguments!==void 0&&r.arguments!==null){let o=r.arguments;if(Object.keys(o).length===0)throw new S(-32602,"\u5DE5\u5177\u53C2\u6570\u4E0D\u80FD\u4E3A\u7A7A")}if(t.customValidator){let o=t.customValidator(r);if(o)throw new S(-32602,o)}return{name:r.name,arguments:r.arguments}}c(ce,"validateToolCallParams");var _=class{static{c(this,"MCPService")}config;client=null;transport=null;tools=new Map;connectionState="disconnected";connectionTimeout=null;initialized=!1;eventBus=T();constructor(e){this.config=le(e),this.validateConfig()}validateConfig(){X.validateConfig(this.config)}async connect(){if(this.connectionState==="connecting")throw new Error("\u8FDE\u63A5\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u8FDE\u63A5\u5B8C\u6210");return this.cleanupConnection(),this.attemptConnection()}async attemptConnection(){return this.connectionState="connecting",new Promise((e,t)=>{this.connectionTimeout=setTimeout(()=>{let r=new Error(`\u8FDE\u63A5\u8D85\u65F6 (${this.config.timeout||1e4}ms)`);this.handleConnectionError(r),t(r)},this.config.timeout||1e4);try{this.client=new Ve({name:`xiaozhi-${this.config.name}-client`,version:"1.0.0"},{capabilities:{}}),this.transport=X.create(this.config),this.client.connect(this.transport).then(async()=>{this.handleConnectionSuccess(),await this.refreshTools(),this.eventBus.emitEvent("mcp:service:connected",{serviceName:this.config.name,tools:this.getTools(),connectionTime:new Date}),e()}).catch(r=>{this.handleConnectionError(r),t(r)})}catch(r){this.handleConnectionError(r),t(r)}})}handleConnectionSuccess(){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.connectionState="connected",this.initialized=!0}handleConnectionError(e){this.connectionState="disconnected",this.initialized=!1,this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.cleanupConnection(),this.eventBus.emitEvent("mcp:service:connection:failed",{serviceName:this.config.name,error:e,attempt:0})}cleanupConnection(){if(this.client){try{this.client.close().catch(()=>{})}catch{}this.client=null}this.transport=null,this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.initialized=!1}async refreshTools(){if(!this.client)throw new Error("\u5BA2\u6237\u7AEF\u672A\u521D\u59CB\u5316");try{let t=(await this.client.listTools()).tools||[];this.tools.clear();for(let r of t)this.tools.set(r.name,r)}catch(e){throw e}}async disconnect(){this.cleanupConnection(),this.connectionState="disconnected",this.eventBus.emitEvent("mcp:service:disconnected",{serviceName:this.config.name,reason:"\u624B\u52A8\u65AD\u5F00",disconnectionTime:new Date})}getTools(){return Array.from(this.tools.values())}async callTool(e,t){if(!this.client)throw new Error(`\u670D\u52A1 ${this.config.name} \u672A\u8FDE\u63A5`);if(!this.tools.has(e))throw new Error(`\u5DE5\u5177 ${e} \u5728\u670D\u52A1 ${this.config.name} \u4E2D\u4E0D\u5B58\u5728`);try{return await this.client.callTool({name:e,arguments:t||{}})}catch(r){throw r}}getConfig(){return this.config}getStatus(){return{name:this.config.name,connected:this.connectionState==="connected",initialized:this.initialized,transportType:this.config.type||"streamable-http",toolCount:this.tools.size,connectionState:this.connectionState}}isConnected(){return this.connectionState==="connected"&&this.initialized}};import{createHash as Je}from"crypto";import{existsSync as L,mkdirSync as Ge,readFileSync as me,renameSync as Qe,writeFileSync as ue}from"fs";import{dirname as Ze,resolve as ge}from"path";import{Hono as Vr}from"hono";import qe from"dayjs";var b=class{static{c(this,"MCPCacheManager")}cachePath;logger;CACHE_VERSION="1.0.0";CACHE_ENTRY_VERSION="1.0.0";cleanupInterval;CLEANUP_INTERVAL=6e4;constructor(e){this.logger=v,this.cachePath=e||this.getCacheFilePath(),this.startCleanupTimer()}formatTimestamp(){return qe().format("YYYY-MM-DD HH:mm:ss")}getCacheFilePath(){try{let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return ge(e,"xiaozhi.cache.json")}catch{let t=process.env.XIAOZHI_CONFIG_DIR||"/tmp";return ge(t,"xiaozhi.cache.json")}}async ensureCacheFile(){try{if(!L(this.cachePath)){let e=Ze(this.cachePath);L(e)||(Ge(e,{recursive:!0}),this.logger.debug(`[CacheManager] \u5DF2\u521B\u5EFA\u7F13\u5B58\u76EE\u5F55: ${e}`)),this.logger.debug("[CacheManager] \u7F13\u5B58\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u521B\u5EFA\u521D\u59CB\u7F13\u5B58\u6587\u4EF6");let t=await this.createInitialCache();await this.saveCache(t),this.logger.info(`[CacheManager] \u5DF2\u521B\u5EFA\u7F13\u5B58\u6587\u4EF6: ${this.cachePath}`)}}catch(e){this.logger.warn(`[CacheManager] \u521B\u5EFA\u7F13\u5B58\u6587\u4EF6\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}async createInitialCache(){let e=this.formatTimestamp();return{version:this.CACHE_VERSION,mcpServers:{},metadata:{lastGlobalUpdate:e,totalWrites:0,createdAt:e}}}async writeCacheEntry(e,t,r){try{this.logger.debug(`[CacheManager] \u5F00\u59CB\u5199\u5165\u7F13\u5B58: ${e}`),await this.ensureCacheFile();let o=await this.loadExistingCache(),n=this.generateConfigHash(r),i={tools:t.map(a=>({name:a.name,description:a.description||"",inputSchema:a.inputSchema})),lastUpdated:this.formatTimestamp(),serverConfig:{...r},configHash:n,version:this.CACHE_ENTRY_VERSION};o.mcpServers[e]=i,o.metadata.lastGlobalUpdate=this.formatTimestamp(),o.metadata.totalWrites+=1,await this.saveCache(o),this.logger.debug(`[CacheManager] \u7F13\u5B58\u5199\u5165\u6210\u529F: ${e}, \u5DE5\u5177\u6570\u91CF: ${t.length}`)}catch(o){this.logger.warn(`[CacheManager] \u7F13\u5B58\u5199\u5165\u5931\u8D25: ${e}, \u9519\u8BEF: ${o instanceof Error?o.message:String(o)}`)}}async loadExistingCache(){try{if(!L(this.cachePath))return await this.createInitialCache();let e=me(this.cachePath,"utf8"),t=JSON.parse(e);return this.validateCacheStructure(t)?t:(this.logger.warn("[CacheManager] \u7F13\u5B58\u6587\u4EF6\u7ED3\u6784\u65E0\u6548\uFF0C\u91CD\u65B0\u521B\u5EFA"),await this.createInitialCache())}catch(e){return this.logger.warn(`[CacheManager] \u52A0\u8F7D\u7F13\u5B58\u5931\u8D25\uFF0C\u521B\u5EFA\u65B0\u7F13\u5B58: ${e instanceof Error?e.message:String(e)}`),await this.createInitialCache()}}async saveCache(e){let t=JSON.stringify(e,null,2);await this.atomicWrite(this.cachePath,t)}async atomicWrite(e,t){let r=`${e}.tmp`;try{ue(r,t,"utf8"),Qe(r,e)}catch(o){try{L(r)&&ue(r,"","utf8")}catch{}throw o}}generateConfigHash(e){try{return Je("sha256").update(JSON.stringify(e)).digest("hex")}catch(t){return this.logger.warn(`[CacheManager] \u751F\u6210\u914D\u7F6E\u54C8\u5E0C\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`),""}}validateCacheStructure(e){try{if(!e||typeof e!="object")return!1;let t=e,r=t.metadata;return typeof t.version=="string"&&typeof t.mcpServers=="object"&&t.mcpServers!==null&&t.metadata!==null&&t.metadata!==void 0&&typeof r=="object"&&r!==null&&typeof r.lastGlobalUpdate=="string"&&typeof r.totalWrites=="number"&&typeof r.createdAt=="string"}catch{return!1}}async getStats(){try{let e=await this.loadExistingCache();return{totalWrites:e.metadata.totalWrites,lastUpdate:e.metadata.lastGlobalUpdate,serverCount:Object.keys(e.mcpServers).length,cacheFileSize:L(this.cachePath)?me(this.cachePath,"utf8").length:0}}catch(e){return this.logger.warn(`[CacheManager] \u83B7\u53D6\u7F13\u5B58\u7EDF\u8BA1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),null}}getFilePath(){return this.cachePath}async getAllCachedTools(){try{let e=await this.loadExistingCache(),t=[];for(let[r,o]of Object.entries(e.mcpServers))for(let n of o.tools)t.push({...n,name:`${r}__${n.name}`});return this.logger.debug(`[CacheManager] \u83B7\u53D6\u5230\u6240\u6709\u7F13\u5B58\u5DE5\u5177\uFF0C\u5171 ${t.length} \u4E2A`),t}catch(e){return this.logger.warn(`[CacheManager] \u83B7\u53D6\u6240\u6709\u7F13\u5B58\u5DE5\u5177\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),[]}}async writeCustomMCPResult(e,t,r,o="completed",n,i=3e5){try{let a=await this.loadExtendedCache(),l=f(e,t),m={result:r,timestamp:new Date().toISOString(),ttl:i,status:o,consumed:!1,taskId:n,retryCount:0};a.customMCPResults||(a.customMCPResults={}),a.customMCPResults[l]=m,await this.saveExtendedCache(a),this.logger.debug(`[CacheManager] \u5199\u5165CustomMCP\u7ED3\u679C\u7F13\u5B58: ${e}, \u72B6\u6001: ${o}`)}catch(a){this.logger.warn(`[CacheManager] \u5199\u5165CustomMCP\u7ED3\u679C\u7F13\u5B58\u5931\u8D25: ${a instanceof Error?a.message:String(a)}`)}}async readCustomMCPResult(e,t){try{let r=await this.loadExtendedCache(),o=f(e,t);if(!r.customMCPResults||!r.customMCPResults[o])return null;let n=r.customMCPResults[o],i=Date.now(),a=new Date(n.timestamp).getTime();return i-a>n.ttl?(this.logger.debug(`[CacheManager] \u7F13\u5B58\u5DF2\u8FC7\u671F: ${e}`),null):n}catch(r){return this.logger.warn(`[CacheManager] \u8BFB\u53D6CustomMCP\u7ED3\u679C\u7F13\u5B58\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`),null}}async updateCustomMCPStatus(e,t,r,o,n){try{let i=await this.loadExtendedCache(),a=f(e,t);if(!i.customMCPResults||!i.customMCPResults[a])return!1;let l=i.customMCPResults[a],m=l.status;return l.status=r,l.timestamp=new Date().toISOString(),o&&(l.result=o),n&&r==="failed"&&(l.result={content:[{type:"text",text:`\u4EFB\u52A1\u5931\u8D25: ${n}`}]},l.consumed=!0),r==="completed"&&(l.consumed=!1),await this.saveExtendedCache(i),this.logger.debug(`[CacheManager] \u66F4\u65B0\u7F13\u5B58\u72B6\u6001: ${e} ${m} -> ${r}`),!0}catch(i){return this.logger.warn(`[CacheManager] \u66F4\u65B0CustomMCP\u7F13\u5B58\u72B6\u6001\u5931\u8D25: ${i instanceof Error?i.message:String(i)}`),!1}}async markCustomMCPAsConsumed(e,t){try{let r=await this.loadExtendedCache(),o=f(e,t);if(!r.customMCPResults||!r.customMCPResults[o])return!1;let n=r.customMCPResults[o];return n.consumed||(n.consumed=!0,n.timestamp=new Date().toISOString(),await this.saveExtendedCache(r),this.logger.debug(`[CacheManager] \u6807\u8BB0\u7F13\u5B58\u4E3A\u5DF2\u6D88\u8D39: ${e}`)),!0}catch(r){return this.logger.warn(`[CacheManager] \u6807\u8BB0CustomMCP\u7F13\u5B58\u4E3A\u5DF2\u6D88\u8D39\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`),!1}}async deleteCustomMCPResult(e,t){try{let r=await this.loadExtendedCache(),o=f(e,t);return!r.customMCPResults||!r.customMCPResults[o]?!1:(delete r.customMCPResults[o],await this.saveExtendedCache(r),this.logger.debug(`[CacheManager] \u5220\u9664\u7F13\u5B58\u6761\u76EE: ${e}`),!0)}catch(r){return this.logger.warn(`[CacheManager] \u5220\u9664CustomMCP\u7F13\u5B58\u6761\u76EE\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`),!1}}async cleanupCustomMCPResults(){try{let e=await this.loadExtendedCache();if(!e.customMCPResults)return{cleaned:0,total:0};let t=Object.entries(e.customMCPResults),r=0;for(let[o,n]of t)k(n)&&(delete e.customMCPResults[o],r++);return r>0&&(await this.saveExtendedCache(e),this.logger.info(`[CacheManager] \u6E05\u7406CustomMCP\u7F13\u5B58: ${r}/${t.length}`)),{cleaned:r,total:t.length}}catch(e){return this.logger.warn(`[CacheManager] \u6E05\u7406CustomMCP\u7F13\u5B58\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),{cleaned:0,total:0}}}async getCustomMCPStatistics(){try{let e=await this.loadExtendedCache();if(!e.customMCPResults)return{totalEntries:0,pendingTasks:0,completedTasks:0,failedTasks:0,consumedEntries:0,cacheHitRate:0,lastCleanupTime:new Date().toISOString(),memoryUsage:0};let t=Object.values(e.customMCPResults),r=t.length,o=t.filter(C=>C.status==="pending").length,n=t.filter(C=>C.status==="completed").length,i=t.filter(C=>C.status==="failed").length,a=t.filter(C=>C.consumed).length,l=n>0?a/n*100:0,m=JSON.stringify(e.customMCPResults).length;return{totalEntries:r,pendingTasks:o,completedTasks:n,failedTasks:i,consumedEntries:a,cacheHitRate:l,lastCleanupTime:new Date().toISOString(),memoryUsage:m}}catch(e){return this.logger.warn(`[CacheManager] \u83B7\u53D6CustomMCP\u7F13\u5B58\u7EDF\u8BA1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),{totalEntries:0,pendingTasks:0,completedTasks:0,failedTasks:0,consumedEntries:0,cacheHitRate:0,lastCleanupTime:new Date().toISOString(),memoryUsage:0}}}async loadExtendedCache(){try{return await this.loadExistingCache()}catch(e){return this.logger.warn(`[CacheManager] \u52A0\u8F7D\u6269\u5C55\u7F13\u5B58\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),{version:this.CACHE_VERSION,mcpServers:{},metadata:{lastGlobalUpdate:this.formatTimestamp(),totalWrites:0,createdAt:this.formatTimestamp()},customMCPResults:{}}}}async saveExtendedCache(e){await this.saveCache(e)}startCleanupTimer(){this.cleanupInterval=setInterval(()=>{this.cleanupCustomMCPResults().catch(e=>{this.logger.warn(`[CacheManager] \u81EA\u52A8\u6E05\u7406\u5931\u8D25: ${e}`)})},this.CLEANUP_INTERVAL),this.logger.debug(`[CacheManager] \u542F\u52A8\u6E05\u7406\u5B9A\u65F6\u5668\uFF0C\u95F4\u9694: ${this.CLEANUP_INTERVAL}ms`)}stopCleanupTimer(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=void 0,this.logger.debug("[CacheManager] \u505C\u6B62\u6E05\u7406\u5B9A\u65F6\u5668"))}cleanup(){this.stopCleanupTimer(),this.logger.debug("[CacheManager] \u6E05\u7406\u8D44\u6E90\u5B8C\u6210")}};import{configManager as Ye}from "../config/index.js";var B=class s{static{c(this,"MCPServiceManagerSingleton")}static instance=null;static getInstance(){if(!s.instance){let e=Ye.getMcpServers();s.instance=new U(e)}return s.instance}static reset(){s.instance=null}},Eo=B.getInstance(),Ro=B;export{Ro as default,Eo as mcpServiceManager};
|
|
27
27
|
//# sourceMappingURL=MCPServiceManagerSingleton.js.map
|