@timmy_hu/plugin-middleware 1.0.2 → 1.0.3
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/.xpertai-plugin/plugin.json +2 -2
- package/index.js +281 -36
- package/package.json +2 -2
- package/src/middlewares/plugin-middleware.middleware.ts +194 -8
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "插件中间件",
|
|
3
3
|
"code": "plugin-middleware",
|
|
4
|
-
"version": "1.0.
|
|
5
|
-
"description": "自动发现 XpertAI
|
|
4
|
+
"version": "1.0.3",
|
|
5
|
+
"description": "自动发现 XpertAI 平台上所有已安装的中间件类型插件,展示加载状态,提供插件绑定指导和诊断工具。注意:插件需要在 XpertAI 平台 UI 中手动绑定到智能体。",
|
|
6
6
|
"createdBy": "fpi",
|
|
7
7
|
"platform": "http://10.161.48.53:3300",
|
|
8
8
|
"category": "middleware",
|
package/index.js
CHANGED
|
@@ -15,8 +15,8 @@ class PluginMiddleware {
|
|
|
15
15
|
zh_Hans: "插件中间件管理器"
|
|
16
16
|
},
|
|
17
17
|
description: {
|
|
18
|
-
en_US: "Discovers all middleware-type plugins installed on the XpertAI platform, shows their load status, and
|
|
19
|
-
zh_Hans: "自动发现 XpertAI
|
|
18
|
+
en_US: "Discovers all middleware-type plugins installed on the XpertAI platform, shows their load status, and provides guidance on binding plugins to agents. Note: Plugins must be manually bound to agents in the XpertAI platform UI.",
|
|
19
|
+
zh_Hans: "自动发现 XpertAI 平台上所有已安装的中间件类型插件,展示加载状态,并提供插件绑定指导。注意:插件需要在 XpertAI 平台 UI 中手动绑定到智能体。"
|
|
20
20
|
},
|
|
21
21
|
configSchema: {
|
|
22
22
|
type: "object",
|
|
@@ -61,17 +61,15 @@ class PluginMiddleware {
|
|
|
61
61
|
const organizationId = options.organizationId || "";
|
|
62
62
|
const cacheTtlSeconds = options.cacheTtlSeconds || 300;
|
|
63
63
|
|
|
64
|
-
// In-memory state
|
|
65
64
|
const state = {
|
|
66
|
-
allPlugins: [],
|
|
67
|
-
middlewarePlugins: [],
|
|
65
|
+
allPlugins: [],
|
|
66
|
+
middlewarePlugins: [],
|
|
68
67
|
lastRefresh: null,
|
|
69
68
|
cacheTtl: cacheTtlSeconds * 1000,
|
|
70
69
|
token: null,
|
|
71
70
|
tokenExpiry: null
|
|
72
71
|
};
|
|
73
72
|
|
|
74
|
-
// ======== 登录:调用 /api/auth/login 获取 token ========
|
|
75
73
|
async function loginAndGetToken() {
|
|
76
74
|
const now = Date.now();
|
|
77
75
|
if (state.token && state.tokenExpiry && now < state.tokenExpiry) {
|
|
@@ -107,7 +105,6 @@ class PluginMiddleware {
|
|
|
107
105
|
return h;
|
|
108
106
|
}
|
|
109
107
|
|
|
110
|
-
// ======== 获取所有已安装插件(GET /api/plugin) ========
|
|
111
108
|
async function fetchAllPlugins() {
|
|
112
109
|
const now = Date.now();
|
|
113
110
|
if (state.lastRefresh && (now - state.lastRefresh) < state.cacheTtl && state.allPlugins.length > 0) {
|
|
@@ -126,8 +123,7 @@ class PluginMiddleware {
|
|
|
126
123
|
const newToken = await loginAndGetToken();
|
|
127
124
|
const retry = await fetch(`${platformUrl}/api/plugin`, { method: "GET", headers: authHeaders(newToken), timeout: 15000 });
|
|
128
125
|
if (!retry.ok) throw new Error(`Platform API returned ${retry.status}`);
|
|
129
|
-
|
|
130
|
-
return processPluginList(retryData);
|
|
126
|
+
return processPluginList(await retry.json());
|
|
131
127
|
}
|
|
132
128
|
throw new Error(`Platform API returned ${resp.status}: ${resp.statusText}`);
|
|
133
129
|
}
|
|
@@ -146,7 +142,6 @@ class PluginMiddleware {
|
|
|
146
142
|
return state.allPlugins;
|
|
147
143
|
}
|
|
148
144
|
|
|
149
|
-
// ======== 格式化中间件插件信息 ========
|
|
150
145
|
function formatMiddlewarePlugin(p) {
|
|
151
146
|
const meta = p.meta || {};
|
|
152
147
|
return {
|
|
@@ -168,11 +163,12 @@ class PluginMiddleware {
|
|
|
168
163
|
canUpdate: p.canUpdate || false,
|
|
169
164
|
hasUpdate: p.hasUpdate || false,
|
|
170
165
|
effectiveInCurrentScope: p.effectiveInCurrentScope !== false,
|
|
166
|
+
scopeRelation: p.scopeRelation || "unknown",
|
|
171
167
|
componentSummary: p.componentSummary || { total: 0, skills: 0, mcpServers: 0, apps: 0, hooks: 0 }
|
|
172
168
|
};
|
|
173
169
|
}
|
|
174
170
|
|
|
175
|
-
//
|
|
171
|
+
// Tool 1: list_middleware_plugins
|
|
176
172
|
const listMiddlewarePlugins = tool(
|
|
177
173
|
async (input) => {
|
|
178
174
|
try {
|
|
@@ -194,7 +190,8 @@ class PluginMiddleware {
|
|
|
194
190
|
totalAllPlugins: state.allPlugins.length,
|
|
195
191
|
totalMiddleware: state.middlewarePlugins.length,
|
|
196
192
|
filter,
|
|
197
|
-
plugins: filtered.map(formatMiddlewarePlugin)
|
|
193
|
+
plugins: filtered.map(formatMiddlewarePlugin),
|
|
194
|
+
note: "⚠️ 插件已安装并加载,但需要在 XpertAI 平台 UI 中手动绑定到智能体才能使用其工具。请使用 get_binding_guidance 工具获取绑定指导。"
|
|
198
195
|
};
|
|
199
196
|
} catch (err) {
|
|
200
197
|
return { success: false, error: err.message, plugins: [] };
|
|
@@ -202,7 +199,7 @@ class PluginMiddleware {
|
|
|
202
199
|
},
|
|
203
200
|
{
|
|
204
201
|
name: "list_middleware_plugins",
|
|
205
|
-
description: "
|
|
202
|
+
description: "列出平台上所有已安装的中间件类型插件。注意:插件需要在 XpertAI 平台 UI 中手动绑定到智能体。",
|
|
206
203
|
schema: z.object({
|
|
207
204
|
filter: z.enum(["all", "loaded", "error", "updatable"]).optional().default("all")
|
|
208
205
|
.describe("过滤条件:all=全部, loaded=已加载, error=加载出错, updatable=有可用更新")
|
|
@@ -210,7 +207,7 @@ class PluginMiddleware {
|
|
|
210
207
|
}
|
|
211
208
|
);
|
|
212
209
|
|
|
213
|
-
//
|
|
210
|
+
// Tool 2: get_middleware_plugin_detail
|
|
214
211
|
const getMiddlewarePluginDetail = tool(
|
|
215
212
|
async (input) => {
|
|
216
213
|
try {
|
|
@@ -236,7 +233,6 @@ class PluginMiddleware {
|
|
|
236
233
|
|
|
237
234
|
const detail = formatMiddlewarePlugin(found);
|
|
238
235
|
|
|
239
|
-
// 尝试获取组件信息
|
|
240
236
|
try {
|
|
241
237
|
const token = await loginAndGetToken();
|
|
242
238
|
const fetch = (await import("node-fetch")).default;
|
|
@@ -251,6 +247,13 @@ class PluginMiddleware {
|
|
|
251
247
|
detail.components = [];
|
|
252
248
|
}
|
|
253
249
|
|
|
250
|
+
// 添加绑定状态提示
|
|
251
|
+
if (detail.componentSummary.total === 0) {
|
|
252
|
+
detail.bindingWarning = "⚠️ 该插件没有暴露任何组件(工具/技能/MCP服务器)。请检查插件实现是否正确注册了中间件策略。";
|
|
253
|
+
} else if (!detail.effectiveInCurrentScope) {
|
|
254
|
+
detail.bindingWarning = "⚠️ 该插件在当前作用域中未生效。请在 XpertAI 平台 UI 中将此插件绑定到当前智能体。";
|
|
255
|
+
}
|
|
256
|
+
|
|
254
257
|
return { success: true, plugin: detail };
|
|
255
258
|
} catch (err) {
|
|
256
259
|
return { success: false, error: err.message };
|
|
@@ -258,7 +261,7 @@ class PluginMiddleware {
|
|
|
258
261
|
},
|
|
259
262
|
{
|
|
260
263
|
name: "get_middleware_plugin_detail",
|
|
261
|
-
description: "
|
|
264
|
+
description: "查询指定中间件插件的详细信息,包括加载状态、配置状态、组件列表、版本信息和绑定状态。",
|
|
262
265
|
schema: z.object({
|
|
263
266
|
pluginNameOrPackage: z.string().min(1)
|
|
264
267
|
.describe("插件名称、packageName 或 displayName,例如 'echarts-generator' 或 '@timmy_hu/bulk-email-sender'")
|
|
@@ -266,7 +269,7 @@ class PluginMiddleware {
|
|
|
266
269
|
}
|
|
267
270
|
);
|
|
268
271
|
|
|
269
|
-
//
|
|
272
|
+
// Tool 3: install_middleware_plugin
|
|
270
273
|
const installMiddlewarePlugin = tool(
|
|
271
274
|
async (input) => {
|
|
272
275
|
const packageName = input.packageName;
|
|
@@ -288,8 +291,6 @@ class PluginMiddleware {
|
|
|
288
291
|
}
|
|
289
292
|
|
|
290
293
|
const result = await resp.json();
|
|
291
|
-
|
|
292
|
-
// 刷新缓存
|
|
293
294
|
state.lastRefresh = null;
|
|
294
295
|
|
|
295
296
|
return {
|
|
@@ -300,7 +301,14 @@ class PluginMiddleware {
|
|
|
300
301
|
packageName: result.packageName || packageName,
|
|
301
302
|
version: result.currentVersion || version,
|
|
302
303
|
organizationId: result.organizationId || organizationId
|
|
303
|
-
}
|
|
304
|
+
},
|
|
305
|
+
nextSteps: [
|
|
306
|
+
"1. 插件已安装并加载到平台",
|
|
307
|
+
"2. 请在 XpertAI 平台 UI 中进入智能体编排页面",
|
|
308
|
+
"3. 点击\"添加中间件\"按钮",
|
|
309
|
+
"4. 在列表中找到刚安装的插件并添加",
|
|
310
|
+
"5. 保存智能体配置后,插件的工具即可使用"
|
|
311
|
+
]
|
|
304
312
|
};
|
|
305
313
|
} catch (err) {
|
|
306
314
|
return {
|
|
@@ -313,7 +321,7 @@ class PluginMiddleware {
|
|
|
313
321
|
},
|
|
314
322
|
{
|
|
315
323
|
name: "install_middleware_plugin",
|
|
316
|
-
description: "从 npm 安装一个新的中间件插件到 XpertAI
|
|
324
|
+
description: "从 npm 安装一个新的中间件插件到 XpertAI 平台。安装后需要在平台 UI 中手动绑定到智能体。",
|
|
317
325
|
schema: z.object({
|
|
318
326
|
packageName: z.string().min(1).describe("npm 包名,例如 '@timmy_hu/bulk-email-sender'"),
|
|
319
327
|
version: z.string().optional().default("latest").describe("版本号,默认为 latest")
|
|
@@ -321,7 +329,7 @@ class PluginMiddleware {
|
|
|
321
329
|
}
|
|
322
330
|
);
|
|
323
331
|
|
|
324
|
-
//
|
|
332
|
+
// Tool 4: refresh_plugin_list
|
|
325
333
|
const refreshPluginList = tool(
|
|
326
334
|
async (input) => {
|
|
327
335
|
state.lastRefresh = null;
|
|
@@ -347,7 +355,7 @@ class PluginMiddleware {
|
|
|
347
355
|
}
|
|
348
356
|
);
|
|
349
357
|
|
|
350
|
-
//
|
|
358
|
+
// Tool 5: check_login_status
|
|
351
359
|
const checkLoginStatus = tool(
|
|
352
360
|
async (input) => {
|
|
353
361
|
try {
|
|
@@ -380,7 +388,7 @@ class PluginMiddleware {
|
|
|
380
388
|
}
|
|
381
389
|
);
|
|
382
390
|
|
|
383
|
-
//
|
|
391
|
+
// Tool 6: search_middleware_plugins
|
|
384
392
|
const searchMiddlewarePlugins = tool(
|
|
385
393
|
async (input) => {
|
|
386
394
|
try {
|
|
@@ -414,33 +422,26 @@ class PluginMiddleware {
|
|
|
414
422
|
}
|
|
415
423
|
);
|
|
416
424
|
|
|
417
|
-
//
|
|
425
|
+
// Tool 7: get_plugin_statistics
|
|
418
426
|
const getPluginStatistics = tool(
|
|
419
427
|
async (input) => {
|
|
420
428
|
try {
|
|
421
429
|
await fetchAllPlugins();
|
|
422
430
|
|
|
423
|
-
// 按 category 统计
|
|
424
431
|
const categoryStats = {};
|
|
425
432
|
for (const p of state.allPlugins) {
|
|
426
433
|
const cat = (p.meta || {}).category || "unknown";
|
|
427
434
|
categoryStats[cat] = (categoryStats[cat] || 0) + 1;
|
|
428
435
|
}
|
|
429
436
|
|
|
430
|
-
// 按 loadStatus 统计中间件
|
|
431
437
|
const loadStatusStats = {};
|
|
432
438
|
for (const p of state.middlewarePlugins) {
|
|
433
439
|
const ls = p.loadStatus || "unknown";
|
|
434
440
|
loadStatusStats[ls] = (loadStatusStats[ls] || 0) + 1;
|
|
435
441
|
}
|
|
436
442
|
|
|
437
|
-
// 有更新的插件
|
|
438
443
|
const updatable = state.middlewarePlugins.filter(p => p.hasUpdate === true);
|
|
439
|
-
|
|
440
|
-
// 有配置错误的插件
|
|
441
444
|
const configErrors = state.middlewarePlugins.filter(p => p.configurationError);
|
|
442
|
-
|
|
443
|
-
// 有加载错误的插件
|
|
444
445
|
const loadErrors = state.middlewarePlugins.filter(p => p.loadError);
|
|
445
446
|
|
|
446
447
|
return {
|
|
@@ -470,6 +471,248 @@ class PluginMiddleware {
|
|
|
470
471
|
}
|
|
471
472
|
);
|
|
472
473
|
|
|
474
|
+
// Tool 8: get_binding_guidance (NEW)
|
|
475
|
+
const getBindingGuidance = tool(
|
|
476
|
+
async (input) => {
|
|
477
|
+
const pluginName = input.pluginName;
|
|
478
|
+
|
|
479
|
+
try {
|
|
480
|
+
await fetchAllPlugins();
|
|
481
|
+
|
|
482
|
+
const plugin = state.middlewarePlugins.find(p => {
|
|
483
|
+
const meta = p.meta || {};
|
|
484
|
+
return p.name === pluginName
|
|
485
|
+
|| meta.name === pluginName
|
|
486
|
+
|| p.packageName === pluginName
|
|
487
|
+
|| meta.displayName === pluginName;
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
if (!plugin) {
|
|
491
|
+
return {
|
|
492
|
+
success: false,
|
|
493
|
+
error: `未找到名为 "${pluginName}" 的中间件插件`,
|
|
494
|
+
guidance: "请先使用 list_middleware_plugins 查看所有可用的中间件插件"
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const meta = plugin.meta || {};
|
|
499
|
+
const detail = formatMiddlewarePlugin(plugin);
|
|
500
|
+
|
|
501
|
+
const guidance = {
|
|
502
|
+
pluginName: detail.displayName,
|
|
503
|
+
packageName: detail.packageName,
|
|
504
|
+
version: detail.version,
|
|
505
|
+
loadStatus: detail.loadStatus,
|
|
506
|
+
componentSummary: detail.componentSummary,
|
|
507
|
+
steps: [
|
|
508
|
+
{
|
|
509
|
+
step: 1,
|
|
510
|
+
action: "打开 XpertAI 平台",
|
|
511
|
+
url: platformUrl,
|
|
512
|
+
description: "登录到 XpertAI 平台"
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
step: 2,
|
|
516
|
+
action: "进入智能体编排页面",
|
|
517
|
+
description: "找到并编辑需要使用该插件的智能体"
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
step: 3,
|
|
521
|
+
action: "添加中间件",
|
|
522
|
+
description: `点击"添加中间件"按钮,在列表中找到 "${detail.displayName}" (${detail.packageName})`
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
step: 4,
|
|
526
|
+
action: "配置插件(如需要)",
|
|
527
|
+
description: detail.canConfigure ? "根据插件要求填写配置参数" : "该插件无需额外配置"
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
step: 5,
|
|
531
|
+
action: "保存智能体",
|
|
532
|
+
description: "保存智能体配置,插件的工具将立即可用"
|
|
533
|
+
}
|
|
534
|
+
],
|
|
535
|
+
troubleshooting: []
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
// 诊断问题
|
|
539
|
+
if (detail.loadStatus !== "loaded") {
|
|
540
|
+
guidance.troubleshooting.push({
|
|
541
|
+
issue: "插件未加载",
|
|
542
|
+
status: detail.loadStatus,
|
|
543
|
+
error: detail.loadError,
|
|
544
|
+
solution: "插件加载失败,请检查插件是否正确安装,或联系插件作者"
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (detail.componentSummary.total === 0) {
|
|
549
|
+
guidance.troubleshooting.push({
|
|
550
|
+
issue: "插件没有暴露任何组件",
|
|
551
|
+
componentSummary: detail.componentSummary,
|
|
552
|
+
solution: "插件实现可能有问题,没有正确注册中间件策略或工具。请联系插件作者检查插件代码。"
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (!detail.effectiveInCurrentScope) {
|
|
557
|
+
guidance.troubleshooting.push({
|
|
558
|
+
issue: "插件在当前作用域未生效",
|
|
559
|
+
scopeRelation: detail.scopeRelation,
|
|
560
|
+
solution: "请在智能体编排页面中手动添加此中间件到智能体"
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (detail.configurationError) {
|
|
565
|
+
guidance.troubleshooting.push({
|
|
566
|
+
issue: "插件配置错误",
|
|
567
|
+
error: detail.configurationError,
|
|
568
|
+
solution: "请检查并修正插件配置"
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return {
|
|
573
|
+
success: true,
|
|
574
|
+
guidance
|
|
575
|
+
};
|
|
576
|
+
} catch (err) {
|
|
577
|
+
return {
|
|
578
|
+
success: false,
|
|
579
|
+
error: err.message
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
name: "get_binding_guidance",
|
|
585
|
+
description: "获取将指定中间件插件绑定到智能体的详细步骤指导,包括诊断插件状态和提供故障排除建议。",
|
|
586
|
+
schema: z.object({
|
|
587
|
+
pluginName: z.string().min(1)
|
|
588
|
+
.describe("插件名称、packageName 或 displayName,例如 '@timmy_hu/bulk-email-sender'")
|
|
589
|
+
})
|
|
590
|
+
}
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
// Tool 9: diagnose_plugin_availability (NEW)
|
|
594
|
+
const diagnosePluginAvailability = tool(
|
|
595
|
+
async (input) => {
|
|
596
|
+
const pluginName = input.pluginName;
|
|
597
|
+
|
|
598
|
+
try {
|
|
599
|
+
await fetchAllPlugins();
|
|
600
|
+
|
|
601
|
+
const plugin = state.middlewarePlugins.find(p => {
|
|
602
|
+
const meta = p.meta || {};
|
|
603
|
+
return p.name === pluginName
|
|
604
|
+
|| meta.name === pluginName
|
|
605
|
+
|| p.packageName === pluginName
|
|
606
|
+
|| meta.displayName === pluginName;
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
if (!plugin) {
|
|
610
|
+
return {
|
|
611
|
+
success: false,
|
|
612
|
+
error: `未找到名为 "${pluginName}" 的中间件插件`,
|
|
613
|
+
diagnosis: "插件未安装",
|
|
614
|
+
solution: "使用 install_middleware_plugin 工具安装该插件"
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const meta = plugin.meta || {};
|
|
619
|
+
const detail = formatMiddlewarePlugin(plugin);
|
|
620
|
+
|
|
621
|
+
const checks = [];
|
|
622
|
+
let allPassed = true;
|
|
623
|
+
|
|
624
|
+
// Check 1: 插件是否加载
|
|
625
|
+
const loadCheck = {
|
|
626
|
+
name: "插件加载状态",
|
|
627
|
+
passed: detail.loadStatus === "loaded",
|
|
628
|
+
status: detail.loadStatus,
|
|
629
|
+
error: detail.loadError
|
|
630
|
+
};
|
|
631
|
+
checks.push(loadCheck);
|
|
632
|
+
if (!loadCheck.passed) allPassed = false;
|
|
633
|
+
|
|
634
|
+
// Check 2: 是否有组件
|
|
635
|
+
const componentCheck = {
|
|
636
|
+
name: "组件暴露",
|
|
637
|
+
passed: detail.componentSummary.total > 0,
|
|
638
|
+
total: detail.componentSummary.total,
|
|
639
|
+
breakdown: detail.componentSummary
|
|
640
|
+
};
|
|
641
|
+
checks.push(componentCheck);
|
|
642
|
+
if (!componentCheck.passed) allPassed = false;
|
|
643
|
+
|
|
644
|
+
// Check 3: 配置状态
|
|
645
|
+
const configCheck = {
|
|
646
|
+
name: "配置状态",
|
|
647
|
+
passed: !detail.configurationError,
|
|
648
|
+
status: detail.configurationStatus,
|
|
649
|
+
error: detail.configurationError
|
|
650
|
+
};
|
|
651
|
+
checks.push(configCheck);
|
|
652
|
+
if (!configCheck.passed) allPassed = false;
|
|
653
|
+
|
|
654
|
+
// Check 4: 作用域生效
|
|
655
|
+
const scopeCheck = {
|
|
656
|
+
name: "作用域生效",
|
|
657
|
+
passed: detail.effectiveInCurrentScope,
|
|
658
|
+
scopeRelation: detail.scopeRelation
|
|
659
|
+
};
|
|
660
|
+
checks.push(scopeCheck);
|
|
661
|
+
if (!scopeCheck.passed) allPassed = false;
|
|
662
|
+
|
|
663
|
+
const diagnosis = {
|
|
664
|
+
pluginName: detail.displayName,
|
|
665
|
+
packageName: detail.packageName,
|
|
666
|
+
version: detail.version,
|
|
667
|
+
allChecksPassed: allPassed,
|
|
668
|
+
checks,
|
|
669
|
+
summary: allPassed
|
|
670
|
+
? "✅ 插件状态正常,应该可以在智能体中使用。如果仍无法使用,请确保已在智能体编排页面中添加了该中间件。"
|
|
671
|
+
: "❌ 插件存在问题,需要修复后才能使用",
|
|
672
|
+
recommendations: []
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
if (!loadCheck.passed) {
|
|
676
|
+
diagnosis.recommendations.push("插件加载失败,请检查插件代码或联系插件作者");
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if (!componentCheck.passed) {
|
|
680
|
+
diagnosis.recommendations.push("插件没有暴露任何工具或组件。这通常意味着插件代码没有正确实现中间件策略。请联系插件作者检查代码。");
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
if (!configCheck.passed) {
|
|
684
|
+
diagnosis.recommendations.push(`插件配置错误: ${detail.configurationError}`);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (!scopeCheck.passed) {
|
|
688
|
+
diagnosis.recommendations.push("插件在当前作用域未生效。请在 XpertAI 平台 UI 的智能体编排页面中手动添加此中间件。");
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
if (allPassed) {
|
|
692
|
+
diagnosis.recommendations.push("插件状态正常。如果工具仍不可用,请确保:1) 已在智能体编排页面添加了该中间件;2) 已保存智能体配置;3) 刷新了智能体页面。");
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
return {
|
|
696
|
+
success: true,
|
|
697
|
+
diagnosis
|
|
698
|
+
};
|
|
699
|
+
} catch (err) {
|
|
700
|
+
return {
|
|
701
|
+
success: false,
|
|
702
|
+
error: err.message
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
name: "diagnose_plugin_availability",
|
|
708
|
+
description: "诊断指定中间件插件为什么其工具不可用。检查加载状态、组件暴露、配置状态和作用域生效情况,并提供修复建议。",
|
|
709
|
+
schema: z.object({
|
|
710
|
+
pluginName: z.string().min(1)
|
|
711
|
+
.describe("插件名称、packageName 或 displayName,例如 '@timmy_hu/bulk-email-sender'")
|
|
712
|
+
})
|
|
713
|
+
}
|
|
714
|
+
);
|
|
715
|
+
|
|
473
716
|
return {
|
|
474
717
|
name: MIDDLEWARE_PROVIDER,
|
|
475
718
|
tools: [
|
|
@@ -479,7 +722,9 @@ class PluginMiddleware {
|
|
|
479
722
|
refreshPluginList,
|
|
480
723
|
checkLoginStatus,
|
|
481
724
|
searchMiddlewarePlugins,
|
|
482
|
-
getPluginStatistics
|
|
725
|
+
getPluginStatistics,
|
|
726
|
+
getBindingGuidance,
|
|
727
|
+
diagnosePluginAvailability
|
|
483
728
|
]
|
|
484
729
|
};
|
|
485
730
|
}
|
|
@@ -493,12 +738,12 @@ class PluginModule {}
|
|
|
493
738
|
const plugin = {
|
|
494
739
|
meta: {
|
|
495
740
|
name: "@timmy_hu/plugin-middleware",
|
|
496
|
-
version: "1.0.
|
|
741
|
+
version: "1.0.3",
|
|
497
742
|
level: "organization",
|
|
498
743
|
category: "middleware",
|
|
499
744
|
displayName: "插件中间件",
|
|
500
|
-
description: "自动发现 XpertAI
|
|
501
|
-
keywords: ["middleware", "plugin", "discovery", "install", "
|
|
745
|
+
description: "自动发现 XpertAI 平台上所有已安装的中间件类型插件,展示加载状态,提供插件绑定指导和诊断工具。注意:插件需要在 XpertAI 平台 UI 中手动绑定到智能体。",
|
|
746
|
+
keywords: ["middleware", "plugin", "discovery", "install", "binding", "diagnosis", "agent"],
|
|
502
747
|
author: "fpi"
|
|
503
748
|
},
|
|
504
749
|
register(ctx) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timmy_hu/plugin-middleware",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "自动发现 XpertAI 平台上所有已安装的中间件类型插件,展示加载状态,提供插件绑定指导和诊断工具。注意:插件需要在 XpertAI 平台 UI 中手动绑定到智能体。",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "echo 'No build step required for CJS plugin'",
|
|
@@ -15,8 +15,8 @@ export class PluginMiddleware {
|
|
|
15
15
|
zh_Hans: "插件中间件管理器"
|
|
16
16
|
},
|
|
17
17
|
description: {
|
|
18
|
-
en_US: "Discovers all middleware-type plugins installed on the XpertAI platform, shows their load status, and
|
|
19
|
-
zh_Hans: "自动发现 XpertAI
|
|
18
|
+
en_US: "Discovers all middleware-type plugins installed on the XpertAI platform, shows their load status, and provides guidance on binding plugins to agents. Note: Plugins must be manually bound to agents in the XpertAI platform UI.",
|
|
19
|
+
zh_Hans: "自动发现 XpertAI 平台上所有已安装的中间件类型插件,展示加载状态,并提供插件绑定指导。注意:插件需要在 XpertAI 平台 UI 中手动绑定到智能体。"
|
|
20
20
|
},
|
|
21
21
|
configSchema: {
|
|
22
22
|
type: "object",
|
|
@@ -156,6 +156,7 @@ export class PluginMiddleware {
|
|
|
156
156
|
canUpdate: p.canUpdate || false,
|
|
157
157
|
hasUpdate: p.hasUpdate || false,
|
|
158
158
|
effectiveInCurrentScope: p.effectiveInCurrentScope !== false,
|
|
159
|
+
scopeRelation: p.scopeRelation || "unknown",
|
|
159
160
|
componentSummary: p.componentSummary || { total: 0, skills: 0, mcpServers: 0, apps: 0, hooks: 0 }
|
|
160
161
|
};
|
|
161
162
|
}
|
|
@@ -175,7 +176,8 @@ export class PluginMiddleware {
|
|
|
175
176
|
totalAllPlugins: state.allPlugins.length,
|
|
176
177
|
totalMiddleware: state.middlewarePlugins.length,
|
|
177
178
|
filter,
|
|
178
|
-
plugins: filtered.map(formatMiddlewarePlugin)
|
|
179
|
+
plugins: filtered.map(formatMiddlewarePlugin),
|
|
180
|
+
note: "⚠️ 插件已安装并加载,但需要在 XpertAI 平台 UI 中手动绑定到智能体才能使用其工具。请使用 get_binding_guidance 工具获取绑定指导。"
|
|
179
181
|
};
|
|
180
182
|
} catch (err: any) {
|
|
181
183
|
return { success: false, error: err.message, plugins: [] };
|
|
@@ -183,7 +185,7 @@ export class PluginMiddleware {
|
|
|
183
185
|
},
|
|
184
186
|
{
|
|
185
187
|
name: "list_middleware_plugins",
|
|
186
|
-
description: "
|
|
188
|
+
description: "列出平台上所有已安装的中间件类型插件。注意:插件需要在 XpertAI 平台 UI 中手动绑定到智能体。",
|
|
187
189
|
schema: z.object({
|
|
188
190
|
filter: z.enum(["all", "loaded", "error", "updatable"]).optional().default("all")
|
|
189
191
|
.describe("过滤条件:all=全部, loaded=已加载, error=加载出错, updatable=有可用更新")
|
|
@@ -223,6 +225,11 @@ export class PluginMiddleware {
|
|
|
223
225
|
} catch (e) {
|
|
224
226
|
detail.components = [];
|
|
225
227
|
}
|
|
228
|
+
if (detail.componentSummary.total === 0) {
|
|
229
|
+
detail.bindingWarning = "⚠️ 该插件没有暴露任何组件(工具/技能/MCP服务器)。请检查插件实现是否正确注册了中间件策略。";
|
|
230
|
+
} else if (!detail.effectiveInCurrentScope) {
|
|
231
|
+
detail.bindingWarning = "⚠️ 该插件在当前作用域中未生效。请在 XpertAI 平台 UI 中将此插件绑定到当前智能体。";
|
|
232
|
+
}
|
|
226
233
|
return { success: true, plugin: detail };
|
|
227
234
|
} catch (err: any) {
|
|
228
235
|
return { success: false, error: err.message };
|
|
@@ -230,7 +237,7 @@ export class PluginMiddleware {
|
|
|
230
237
|
},
|
|
231
238
|
{
|
|
232
239
|
name: "get_middleware_plugin_detail",
|
|
233
|
-
description: "
|
|
240
|
+
description: "查询指定中间件插件的详细信息,包括加载状态、配置状态、组件列表、版本信息和绑定状态。",
|
|
234
241
|
schema: z.object({
|
|
235
242
|
pluginNameOrPackage: z.string().min(1)
|
|
236
243
|
.describe("插件名称、packageName 或 displayName,例如 'echarts-generator' 或 '@timmy_hu/bulk-email-sender'")
|
|
@@ -265,7 +272,14 @@ export class PluginMiddleware {
|
|
|
265
272
|
packageName: result.packageName || packageName,
|
|
266
273
|
version: result.currentVersion || version,
|
|
267
274
|
organizationId: result.organizationId || organizationId
|
|
268
|
-
}
|
|
275
|
+
},
|
|
276
|
+
nextSteps: [
|
|
277
|
+
"1. 插件已安装并加载到平台",
|
|
278
|
+
"2. 请在 XpertAI 平台 UI 中进入智能体编排页面",
|
|
279
|
+
"3. 点击"添加中间件"按钮",
|
|
280
|
+
"4. 在列表中找到刚安装的插件并添加",
|
|
281
|
+
"5. 保存智能体配置后,插件的工具即可使用"
|
|
282
|
+
]
|
|
269
283
|
};
|
|
270
284
|
} catch (err: any) {
|
|
271
285
|
return { success: false, error: err.message, packageName, version };
|
|
@@ -273,7 +287,7 @@ export class PluginMiddleware {
|
|
|
273
287
|
},
|
|
274
288
|
{
|
|
275
289
|
name: "install_middleware_plugin",
|
|
276
|
-
description: "从 npm 安装一个新的中间件插件到 XpertAI
|
|
290
|
+
description: "从 npm 安装一个新的中间件插件到 XpertAI 平台。安装后需要在平台 UI 中手动绑定到智能体。",
|
|
277
291
|
schema: z.object({
|
|
278
292
|
packageName: z.string().min(1).describe("npm 包名,例如 '@timmy_hu/bulk-email-sender'"),
|
|
279
293
|
version: z.string().optional().default("latest").describe("版本号,默认为 latest")
|
|
@@ -408,6 +422,176 @@ export class PluginMiddleware {
|
|
|
408
422
|
}
|
|
409
423
|
);
|
|
410
424
|
|
|
425
|
+
const getBindingGuidance = tool(
|
|
426
|
+
async (input) => {
|
|
427
|
+
const pluginName = input.pluginName;
|
|
428
|
+
try {
|
|
429
|
+
await fetchAllPlugins();
|
|
430
|
+
const plugin = state.middlewarePlugins.find((p: any) => {
|
|
431
|
+
const meta = p.meta || {};
|
|
432
|
+
return p.name === pluginName || meta.name === pluginName || p.packageName === pluginName || meta.displayName === pluginName;
|
|
433
|
+
});
|
|
434
|
+
if (!plugin) {
|
|
435
|
+
return {
|
|
436
|
+
success: false,
|
|
437
|
+
error: `未找到名为 "${pluginName}" 的中间件插件`,
|
|
438
|
+
guidance: "请先使用 list_middleware_plugins 查看所有可用的中间件插件"
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
const meta = plugin.meta || {};
|
|
442
|
+
const detail = formatMiddlewarePlugin(plugin);
|
|
443
|
+
const guidance = {
|
|
444
|
+
pluginName: detail.displayName,
|
|
445
|
+
packageName: detail.packageName,
|
|
446
|
+
version: detail.version,
|
|
447
|
+
loadStatus: detail.loadStatus,
|
|
448
|
+
componentSummary: detail.componentSummary,
|
|
449
|
+
steps: [
|
|
450
|
+
{ step: 1, action: "打开 XpertAI 平台", url: platformUrl, description: "登录到 XpertAI 平台" },
|
|
451
|
+
{ step: 2, action: "进入智能体编排页面", description: "找到并编辑需要使用该插件的智能体" },
|
|
452
|
+
{ step: 3, action: "添加中间件", description: `点击"添加中间件"按钮,在列表中找到 "${detail.displayName}" (${detail.packageName})` },
|
|
453
|
+
{ step: 4, action: "配置插件(如需要)", description: detail.canConfigure ? "根据插件要求填写配置参数" : "该插件无需额外配置" },
|
|
454
|
+
{ step: 5, action: "保存智能体", description: "保存智能体配置,插件的工具将立即可用" }
|
|
455
|
+
],
|
|
456
|
+
troubleshooting: [] as any[]
|
|
457
|
+
};
|
|
458
|
+
if (detail.loadStatus !== "loaded") {
|
|
459
|
+
guidance.troubleshooting.push({
|
|
460
|
+
issue: "插件未加载",
|
|
461
|
+
status: detail.loadStatus,
|
|
462
|
+
error: detail.loadError,
|
|
463
|
+
solution: "插件加载失败,请检查插件是否正确安装,或联系插件作者"
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
if (detail.componentSummary.total === 0) {
|
|
467
|
+
guidance.troubleshooting.push({
|
|
468
|
+
issue: "插件没有暴露任何组件",
|
|
469
|
+
componentSummary: detail.componentSummary,
|
|
470
|
+
solution: "插件实现可能有问题,没有正确注册中间件策略或工具。请联系插件作者检查插件代码。"
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
if (!detail.effectiveInCurrentScope) {
|
|
474
|
+
guidance.troubleshooting.push({
|
|
475
|
+
issue: "插件在当前作用域未生效",
|
|
476
|
+
scopeRelation: detail.scopeRelation,
|
|
477
|
+
solution: "请在智能体编排页面中手动添加此中间件到智能体"
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
if (detail.configurationError) {
|
|
481
|
+
guidance.troubleshooting.push({
|
|
482
|
+
issue: "插件配置错误",
|
|
483
|
+
error: detail.configurationError,
|
|
484
|
+
solution: "请检查并修正插件配置"
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
return { success: true, guidance };
|
|
488
|
+
} catch (err: any) {
|
|
489
|
+
return { success: false, error: err.message };
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
name: "get_binding_guidance",
|
|
494
|
+
description: "获取将指定中间件插件绑定到智能体的详细步骤指导,包括诊断插件状态和提供故障排除建议。",
|
|
495
|
+
schema: z.object({
|
|
496
|
+
pluginName: z.string().min(1)
|
|
497
|
+
.describe("插件名称、packageName 或 displayName,例如 '@timmy_hu/bulk-email-sender'")
|
|
498
|
+
})
|
|
499
|
+
}
|
|
500
|
+
);
|
|
501
|
+
|
|
502
|
+
const diagnosePluginAvailability = tool(
|
|
503
|
+
async (input) => {
|
|
504
|
+
const pluginName = input.pluginName;
|
|
505
|
+
try {
|
|
506
|
+
await fetchAllPlugins();
|
|
507
|
+
const plugin = state.middlewarePlugins.find((p: any) => {
|
|
508
|
+
const meta = p.meta || {};
|
|
509
|
+
return p.name === pluginName || meta.name === pluginName || p.packageName === pluginName || meta.displayName === pluginName;
|
|
510
|
+
});
|
|
511
|
+
if (!plugin) {
|
|
512
|
+
return {
|
|
513
|
+
success: false,
|
|
514
|
+
error: `未找到名为 "${pluginName}" 的中间件插件`,
|
|
515
|
+
diagnosis: "插件未安装",
|
|
516
|
+
solution: "使用 install_middleware_plugin 工具安装该插件"
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
const meta = plugin.meta || {};
|
|
520
|
+
const detail = formatMiddlewarePlugin(plugin);
|
|
521
|
+
const checks = [];
|
|
522
|
+
let allPassed = true;
|
|
523
|
+
const loadCheck = {
|
|
524
|
+
name: "插件加载状态",
|
|
525
|
+
passed: detail.loadStatus === "loaded",
|
|
526
|
+
status: detail.loadStatus,
|
|
527
|
+
error: detail.loadError
|
|
528
|
+
};
|
|
529
|
+
checks.push(loadCheck);
|
|
530
|
+
if (!loadCheck.passed) allPassed = false;
|
|
531
|
+
const componentCheck = {
|
|
532
|
+
name: "组件暴露",
|
|
533
|
+
passed: detail.componentSummary.total > 0,
|
|
534
|
+
total: detail.componentSummary.total,
|
|
535
|
+
breakdown: detail.componentSummary
|
|
536
|
+
};
|
|
537
|
+
checks.push(componentCheck);
|
|
538
|
+
if (!componentCheck.passed) allPassed = false;
|
|
539
|
+
const configCheck = {
|
|
540
|
+
name: "配置状态",
|
|
541
|
+
passed: !detail.configurationError,
|
|
542
|
+
status: detail.configurationStatus,
|
|
543
|
+
error: detail.configurationError
|
|
544
|
+
};
|
|
545
|
+
checks.push(configCheck);
|
|
546
|
+
if (!configCheck.passed) allPassed = false;
|
|
547
|
+
const scopeCheck = {
|
|
548
|
+
name: "作用域生效",
|
|
549
|
+
passed: detail.effectiveInCurrentScope,
|
|
550
|
+
scopeRelation: detail.scopeRelation
|
|
551
|
+
};
|
|
552
|
+
checks.push(scopeCheck);
|
|
553
|
+
if (!scopeCheck.passed) allPassed = false;
|
|
554
|
+
const diagnosis = {
|
|
555
|
+
pluginName: detail.displayName,
|
|
556
|
+
packageName: detail.packageName,
|
|
557
|
+
version: detail.version,
|
|
558
|
+
allChecksPassed: allPassed,
|
|
559
|
+
checks,
|
|
560
|
+
summary: allPassed
|
|
561
|
+
? "✅ 插件状态正常,应该可以在智能体中使用。如果仍无法使用,请确保已在智能体编排页面中添加了该中间件。"
|
|
562
|
+
: "❌ 插件存在问题,需要修复后才能使用",
|
|
563
|
+
recommendations: [] as string[]
|
|
564
|
+
};
|
|
565
|
+
if (!loadCheck.passed) {
|
|
566
|
+
diagnosis.recommendations.push("插件加载失败,请检查插件代码或联系插件作者");
|
|
567
|
+
}
|
|
568
|
+
if (!componentCheck.passed) {
|
|
569
|
+
diagnosis.recommendations.push("插件没有暴露任何工具或组件。这通常意味着插件代码没有正确实现中间件策略。请联系插件作者检查代码。");
|
|
570
|
+
}
|
|
571
|
+
if (!configCheck.passed) {
|
|
572
|
+
diagnosis.recommendations.push(`插件配置错误: ${detail.configurationError}`);
|
|
573
|
+
}
|
|
574
|
+
if (!scopeCheck.passed) {
|
|
575
|
+
diagnosis.recommendations.push("插件在当前作用域未生效。请在 XpertAI 平台 UI 的智能体编排页面中手动添加此中间件。");
|
|
576
|
+
}
|
|
577
|
+
if (allPassed) {
|
|
578
|
+
diagnosis.recommendations.push("插件状态正常。如果工具仍不可用,请确保:1) 已在智能体编排页面添加了该中间件;2) 已保存智能体配置;3) 刷新了智能体页面。");
|
|
579
|
+
}
|
|
580
|
+
return { success: true, diagnosis };
|
|
581
|
+
} catch (err: any) {
|
|
582
|
+
return { success: false, error: err.message };
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
name: "diagnose_plugin_availability",
|
|
587
|
+
description: "诊断指定中间件插件为什么其工具不可用。检查加载状态、组件暴露、配置状态和作用域生效情况,并提供修复建议。",
|
|
588
|
+
schema: z.object({
|
|
589
|
+
pluginName: z.string().min(1)
|
|
590
|
+
.describe("插件名称、packageName 或 displayName,例如 '@timmy_hu/bulk-email-sender'")
|
|
591
|
+
})
|
|
592
|
+
}
|
|
593
|
+
);
|
|
594
|
+
|
|
411
595
|
return {
|
|
412
596
|
name: MIDDLEWARE_PROVIDER,
|
|
413
597
|
tools: [
|
|
@@ -417,7 +601,9 @@ export class PluginMiddleware {
|
|
|
417
601
|
refreshPluginList,
|
|
418
602
|
checkLoginStatus,
|
|
419
603
|
searchMiddlewarePlugins,
|
|
420
|
-
getPluginStatistics
|
|
604
|
+
getPluginStatistics,
|
|
605
|
+
getBindingGuidance,
|
|
606
|
+
diagnosePluginAvailability
|
|
421
607
|
]
|
|
422
608
|
};
|
|
423
609
|
}
|