@timmy_hu/plugin-middleware 1.0.0
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 +10 -0
- package/README.md +201 -0
- package/examples/request.example.json +119 -0
- package/index.js +519 -0
- package/package.json +29 -0
- package/src/middlewares/plugin-middleware.middleware.ts +487 -0
- package/src/plugin-middleware.module.ts +15 -0
- package/src/schemas/config.schema.ts +34 -0
package/index.js
ADDED
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
require("reflect-metadata");
|
|
2
|
+
const { Injectable } = require("@nestjs/common");
|
|
3
|
+
const { AgentMiddlewareStrategy } = require("@xpert-ai/plugin-sdk");
|
|
4
|
+
const { tool } = require("@langchain/core/tools");
|
|
5
|
+
const { z } = require("zod");
|
|
6
|
+
|
|
7
|
+
const MIDDLEWARE_PROVIDER = "PluginMiddleware";
|
|
8
|
+
|
|
9
|
+
class PluginMiddleware {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.meta = {
|
|
12
|
+
name: MIDDLEWARE_PROVIDER,
|
|
13
|
+
label: {
|
|
14
|
+
en_US: "Plugin Middleware Manager",
|
|
15
|
+
zh_Hans: "插件中间件管理器"
|
|
16
|
+
},
|
|
17
|
+
description: {
|
|
18
|
+
en_US: "Discovers all middleware-type plugins and provides dynamic on-demand loading, unloading, and status query tools for agent orchestration.",
|
|
19
|
+
zh_Hans: "自动发现所有中间件类型插件,支持动态按需加载、卸载和状态查询,为智能体编排提供灵活的中间件管理能力。"
|
|
20
|
+
},
|
|
21
|
+
configSchema: {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {
|
|
24
|
+
platformUrl: {
|
|
25
|
+
type: "string",
|
|
26
|
+
title: {
|
|
27
|
+
en_US: "Platform URL",
|
|
28
|
+
zh_Hans: "平台地址"
|
|
29
|
+
},
|
|
30
|
+
description: "XpertAI platform base URL for plugin discovery API",
|
|
31
|
+
default: "http://10.161.48.53:3300"
|
|
32
|
+
},
|
|
33
|
+
organizationId: {
|
|
34
|
+
type: "string",
|
|
35
|
+
title: {
|
|
36
|
+
en_US: "Organization ID",
|
|
37
|
+
zh_Hans: "组织 ID"
|
|
38
|
+
},
|
|
39
|
+
description: "Organization ID for scoped plugin queries"
|
|
40
|
+
},
|
|
41
|
+
autoDiscover: {
|
|
42
|
+
type: "boolean",
|
|
43
|
+
title: {
|
|
44
|
+
en_US: "Auto Discover",
|
|
45
|
+
zh_Hans: "自动发现"
|
|
46
|
+
},
|
|
47
|
+
description: "Whether to automatically discover available middleware plugins on startup",
|
|
48
|
+
default: true
|
|
49
|
+
},
|
|
50
|
+
cacheTtlSeconds: {
|
|
51
|
+
type: "number",
|
|
52
|
+
title: {
|
|
53
|
+
en_US: "Cache TTL (seconds)",
|
|
54
|
+
zh_Hans: "缓存有效期(秒)"
|
|
55
|
+
},
|
|
56
|
+
description: "How long to cache the discovered plugin list before refreshing",
|
|
57
|
+
default: 300
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
required: ["platformUrl"]
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
createMiddleware(options = {}, context = {}) {
|
|
66
|
+
const platformUrl = options.platformUrl || "http://10.161.48.53:3300";
|
|
67
|
+
const organizationId = options.organizationId || "";
|
|
68
|
+
const autoDiscover = options.autoDiscover !== false;
|
|
69
|
+
const cacheTtlSeconds = options.cacheTtlSeconds || 300;
|
|
70
|
+
|
|
71
|
+
// In-memory registry for discovered middleware plugins
|
|
72
|
+
const registry = {
|
|
73
|
+
plugins: new Map(),
|
|
74
|
+
loadedPlugins: new Map(),
|
|
75
|
+
lastRefresh: null,
|
|
76
|
+
cacheTtl: cacheTtlSeconds * 1000
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Helper: fetch middleware plugins from platform API
|
|
80
|
+
async function fetchMiddlewarePlugins() {
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
if (registry.lastRefresh && (now - registry.lastRefresh) < registry.cacheTtl) {
|
|
83
|
+
return Array.from(registry.plugins.values());
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const fetch = (await import("node-fetch")).default;
|
|
88
|
+
const url = `${platformUrl}/api/plugin?category=middleware&organization-id=${encodeURIComponent(organizationId)}`;
|
|
89
|
+
const resp = await fetch(url, {
|
|
90
|
+
method: "GET",
|
|
91
|
+
headers: {
|
|
92
|
+
"Content-Type": "application/json",
|
|
93
|
+
...(organizationId ? { "organization-id": organizationId } : {})
|
|
94
|
+
},
|
|
95
|
+
timeout: 10000
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (!resp.ok) {
|
|
99
|
+
throw new Error(`Platform API returned ${resp.status}: ${resp.statusText}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const data = await resp.json();
|
|
103
|
+
const pluginList = Array.isArray(data) ? data : (data.data || data.items || data.plugins || []);
|
|
104
|
+
|
|
105
|
+
registry.plugins.clear();
|
|
106
|
+
for (const p of pluginList) {
|
|
107
|
+
const code = p.code || p.name || p.pluginName;
|
|
108
|
+
if (code) {
|
|
109
|
+
registry.plugins.set(code, {
|
|
110
|
+
code,
|
|
111
|
+
name: p.name || p.displayName || code,
|
|
112
|
+
version: p.version || "unknown",
|
|
113
|
+
description: p.description || "",
|
|
114
|
+
status: p.status || "available",
|
|
115
|
+
category: p.category || "middleware",
|
|
116
|
+
loaded: registry.loadedPlugins.has(code)
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
registry.lastRefresh = now;
|
|
122
|
+
return Array.from(registry.plugins.values());
|
|
123
|
+
} catch (err) {
|
|
124
|
+
// If API call fails, return cached data or empty list
|
|
125
|
+
if (registry.plugins.size > 0) {
|
|
126
|
+
return Array.from(registry.plugins.values());
|
|
127
|
+
}
|
|
128
|
+
throw new Error(`Failed to discover middleware plugins: ${err.message}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Tool 1: List all discovered middleware plugins
|
|
133
|
+
const listMiddlewarePlugins = tool(
|
|
134
|
+
async (input) => {
|
|
135
|
+
try {
|
|
136
|
+
const plugins = await fetchMiddlewarePlugins();
|
|
137
|
+
const filter = input.filter || "all";
|
|
138
|
+
|
|
139
|
+
let filtered = plugins;
|
|
140
|
+
if (filter === "loaded") {
|
|
141
|
+
filtered = plugins.filter(p => p.loaded || registry.loadedPlugins.has(p.code));
|
|
142
|
+
} else if (filter === "available") {
|
|
143
|
+
filtered = plugins.filter(p => !p.loaded && !registry.loadedPlugins.has(p.code));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
success: true,
|
|
148
|
+
total: filtered.length,
|
|
149
|
+
plugins: filtered.map(p => ({
|
|
150
|
+
code: p.code,
|
|
151
|
+
name: p.name,
|
|
152
|
+
version: p.version,
|
|
153
|
+
description: p.description,
|
|
154
|
+
status: registry.loadedPlugins.has(p.code) ? "loaded" : "available",
|
|
155
|
+
loadedAt: registry.loadedPlugins.has(p.code)
|
|
156
|
+
? registry.loadedPlugins.get(p.code).loadedAt
|
|
157
|
+
: null
|
|
158
|
+
}))
|
|
159
|
+
};
|
|
160
|
+
} catch (err) {
|
|
161
|
+
return {
|
|
162
|
+
success: false,
|
|
163
|
+
error: err.message,
|
|
164
|
+
plugins: []
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: "list_middleware_plugins",
|
|
170
|
+
description: "列出所有已发现的中间件类型插件,可按加载状态过滤。返回插件编码、名称、版本、描述和当前状态。",
|
|
171
|
+
schema: z.object({
|
|
172
|
+
filter: z.enum(["all", "loaded", "available"]).optional().default("all")
|
|
173
|
+
.describe("过滤条件:all=全部, loaded=已加载, available=可用未加载")
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
// Tool 2: Load a specific middleware plugin by code
|
|
179
|
+
const loadMiddlewarePlugin = tool(
|
|
180
|
+
async (input) => {
|
|
181
|
+
const pluginCode = input.pluginCode;
|
|
182
|
+
|
|
183
|
+
if (registry.loadedPlugins.has(pluginCode)) {
|
|
184
|
+
return {
|
|
185
|
+
success: true,
|
|
186
|
+
message: `插件 ${pluginCode} 已经处于加载状态`,
|
|
187
|
+
plugin: {
|
|
188
|
+
code: pluginCode,
|
|
189
|
+
loadedAt: registry.loadedPlugins.get(pluginCode).loadedAt,
|
|
190
|
+
status: "already_loaded"
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Discover if not yet known
|
|
196
|
+
const plugins = await fetchMiddlewarePlugins();
|
|
197
|
+
const target = plugins.find(p => p.code === pluginCode);
|
|
198
|
+
|
|
199
|
+
if (!target) {
|
|
200
|
+
return {
|
|
201
|
+
success: false,
|
|
202
|
+
error: `未找到编码为 ${pluginCode} 的中间件插件`,
|
|
203
|
+
availablePlugins: plugins.map(p => p.code)
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
// Attempt to load via platform API
|
|
209
|
+
const fetch = (await import("node-fetch")).default;
|
|
210
|
+
const loadUrl = `${platformUrl}/api/plugin/load`;
|
|
211
|
+
const resp = await fetch(loadUrl, {
|
|
212
|
+
method: "POST",
|
|
213
|
+
headers: {
|
|
214
|
+
"Content-Type": "application/json",
|
|
215
|
+
...(organizationId ? { "organization-id": organizationId } : {})
|
|
216
|
+
},
|
|
217
|
+
body: JSON.stringify({
|
|
218
|
+
pluginName: target.name || pluginCode,
|
|
219
|
+
version: target.version,
|
|
220
|
+
source: "npm"
|
|
221
|
+
}),
|
|
222
|
+
timeout: 30000
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
if (!resp.ok) {
|
|
226
|
+
const errText = await resp.text();
|
|
227
|
+
throw new Error(`Load API returned ${resp.status}: ${errText}`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const result = await resp.json();
|
|
231
|
+
|
|
232
|
+
registry.loadedPlugins.set(pluginCode, {
|
|
233
|
+
code: pluginCode,
|
|
234
|
+
name: target.name,
|
|
235
|
+
version: target.version,
|
|
236
|
+
loadedAt: new Date().toISOString(),
|
|
237
|
+
loadResult: result
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
success: true,
|
|
242
|
+
message: `插件 ${pluginCode} 加载成功`,
|
|
243
|
+
plugin: {
|
|
244
|
+
code: pluginCode,
|
|
245
|
+
name: target.name,
|
|
246
|
+
version: target.version,
|
|
247
|
+
loadedAt: registry.loadedPlugins.get(pluginCode).loadedAt,
|
|
248
|
+
status: "loaded"
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
} catch (err) {
|
|
252
|
+
// Even if API call fails, mark as locally loaded for demo/offline scenarios
|
|
253
|
+
registry.loadedPlugins.set(pluginCode, {
|
|
254
|
+
code: pluginCode,
|
|
255
|
+
name: target.name,
|
|
256
|
+
version: target.version,
|
|
257
|
+
loadedAt: new Date().toISOString(),
|
|
258
|
+
loadResult: { offline: true, error: err.message }
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
success: true,
|
|
263
|
+
message: `插件 ${pluginCode} 已标记为加载(离线模式)`,
|
|
264
|
+
plugin: {
|
|
265
|
+
code: pluginCode,
|
|
266
|
+
name: target.name,
|
|
267
|
+
version: target.version,
|
|
268
|
+
loadedAt: registry.loadedPlugins.get(pluginCode).loadedAt,
|
|
269
|
+
status: "loaded_offline",
|
|
270
|
+
warning: err.message
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
name: "load_middleware_plugin",
|
|
277
|
+
description: "按插件编码动态加载指定的中间件插件。加载后该插件的工具和能力将对智能体可用。",
|
|
278
|
+
schema: z.object({
|
|
279
|
+
pluginCode: z.string().min(1).describe("要加载的中间件插件编码,例如 'weather-query' 或 'pg-query-tool'")
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
// Tool 3: Unload a specific middleware plugin
|
|
285
|
+
const unloadMiddlewarePlugin = tool(
|
|
286
|
+
async (input) => {
|
|
287
|
+
const pluginCode = input.pluginCode;
|
|
288
|
+
|
|
289
|
+
if (!registry.loadedPlugins.has(pluginCode)) {
|
|
290
|
+
return {
|
|
291
|
+
success: false,
|
|
292
|
+
error: `插件 ${pluginCode} 当前未加载,无需卸载`,
|
|
293
|
+
loadedPlugins: Array.from(registry.loadedPlugins.keys())
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
const fetch = (await import("node-fetch")).default;
|
|
299
|
+
const unloadUrl = `${platformUrl}/api/plugin/unload`;
|
|
300
|
+
const resp = await fetch(unloadUrl, {
|
|
301
|
+
method: "POST",
|
|
302
|
+
headers: {
|
|
303
|
+
"Content-Type": "application/json",
|
|
304
|
+
...(organizationId ? { "organization-id": organizationId } : {})
|
|
305
|
+
},
|
|
306
|
+
body: JSON.stringify({ pluginCode }),
|
|
307
|
+
timeout: 15000
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
if (!resp.ok) {
|
|
311
|
+
const errText = await resp.text();
|
|
312
|
+
throw new Error(`Unload API returned ${resp.status}: ${errText}`);
|
|
313
|
+
}
|
|
314
|
+
} catch (err) {
|
|
315
|
+
// Continue with local unload even if API fails
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const removed = registry.loadedPlugins.get(pluginCode);
|
|
319
|
+
registry.loadedPlugins.delete(pluginCode);
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
success: true,
|
|
323
|
+
message: `插件 ${pluginCode} 已卸载`,
|
|
324
|
+
plugin: {
|
|
325
|
+
code: pluginCode,
|
|
326
|
+
name: removed.name,
|
|
327
|
+
unloadedAt: new Date().toISOString(),
|
|
328
|
+
status: "unloaded"
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
name: "unload_middleware_plugin",
|
|
334
|
+
description: "按插件编码卸载已加载的中间件插件。卸载后该插件的工具将不再对智能体可用。",
|
|
335
|
+
schema: z.object({
|
|
336
|
+
pluginCode: z.string().min(1).describe("要卸载的中间件插件编码")
|
|
337
|
+
})
|
|
338
|
+
}
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
// Tool 4: Query detailed status of a specific middleware plugin
|
|
342
|
+
const getMiddlewarePluginStatus = tool(
|
|
343
|
+
async (input) => {
|
|
344
|
+
const pluginCode = input.pluginCode;
|
|
345
|
+
const plugins = await fetchMiddlewarePlugins();
|
|
346
|
+
const target = plugins.find(p => p.code === pluginCode);
|
|
347
|
+
|
|
348
|
+
if (!target) {
|
|
349
|
+
return {
|
|
350
|
+
success: false,
|
|
351
|
+
error: `未找到编码为 ${pluginCode} 的中间件插件`
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const loaded = registry.loadedPlugins.has(pluginCode);
|
|
356
|
+
const loadInfo = loaded ? registry.loadedPlugins.get(pluginCode) : null;
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
success: true,
|
|
360
|
+
plugin: {
|
|
361
|
+
code: target.code,
|
|
362
|
+
name: target.name,
|
|
363
|
+
version: target.version,
|
|
364
|
+
description: target.description,
|
|
365
|
+
category: target.category,
|
|
366
|
+
status: loaded ? "loaded" : "available",
|
|
367
|
+
loadedAt: loadInfo ? loadInfo.loadedAt : null,
|
|
368
|
+
tools: loaded ? (loadInfo.tools || []) : [],
|
|
369
|
+
configRequired: target.configRequired || []
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
name: "get_middleware_plugin_status",
|
|
375
|
+
description: "查询指定中间件插件的详细状态信息,包括加载状态、版本、描述和可用工具列表。",
|
|
376
|
+
schema: z.object({
|
|
377
|
+
pluginCode: z.string().min(1).describe("要查询的中间件插件编码")
|
|
378
|
+
})
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
// Tool 5: Refresh the plugin discovery cache
|
|
383
|
+
const refreshPluginCache = tool(
|
|
384
|
+
async (input) => {
|
|
385
|
+
registry.lastRefresh = null;
|
|
386
|
+
try {
|
|
387
|
+
const plugins = await fetchMiddlewarePlugins();
|
|
388
|
+
return {
|
|
389
|
+
success: true,
|
|
390
|
+
message: `缓存已刷新,发现 ${plugins.length} 个中间件插件`,
|
|
391
|
+
total: plugins.length,
|
|
392
|
+
refreshedAt: new Date().toISOString()
|
|
393
|
+
};
|
|
394
|
+
} catch (err) {
|
|
395
|
+
return {
|
|
396
|
+
success: false,
|
|
397
|
+
error: `刷新缓存失败: ${err.message}`
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
name: "refresh_plugin_cache",
|
|
403
|
+
description: "刷新中间件插件发现缓存,强制从平台重新获取所有中间件类型插件列表。",
|
|
404
|
+
schema: z.object({})
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
// Tool 6: Batch load multiple middleware plugins
|
|
409
|
+
const batchLoadMiddlewarePlugins = tool(
|
|
410
|
+
async (input) => {
|
|
411
|
+
const pluginCodes = input.pluginCodes;
|
|
412
|
+
const results = [];
|
|
413
|
+
|
|
414
|
+
const plugins = await fetchMiddlewarePlugins();
|
|
415
|
+
|
|
416
|
+
for (const code of pluginCodes) {
|
|
417
|
+
if (registry.loadedPlugins.has(code)) {
|
|
418
|
+
results.push({
|
|
419
|
+
code,
|
|
420
|
+
status: "already_loaded",
|
|
421
|
+
success: true
|
|
422
|
+
});
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const target = plugins.find(p => p.code === code);
|
|
427
|
+
if (!target) {
|
|
428
|
+
results.push({
|
|
429
|
+
code,
|
|
430
|
+
status: "not_found",
|
|
431
|
+
success: false,
|
|
432
|
+
error: `未找到编码为 ${code} 的中间件插件`
|
|
433
|
+
});
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
registry.loadedPlugins.set(code, {
|
|
438
|
+
code,
|
|
439
|
+
name: target.name,
|
|
440
|
+
version: target.version,
|
|
441
|
+
loadedAt: new Date().toISOString(),
|
|
442
|
+
loadResult: { batch: true }
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
results.push({
|
|
446
|
+
code,
|
|
447
|
+
name: target.name,
|
|
448
|
+
version: target.version,
|
|
449
|
+
status: "loaded",
|
|
450
|
+
success: true,
|
|
451
|
+
loadedAt: registry.loadedPlugins.get(code).loadedAt
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return {
|
|
456
|
+
success: true,
|
|
457
|
+
total: pluginCodes.length,
|
|
458
|
+
loaded: results.filter(r => r.status === "loaded").length,
|
|
459
|
+
alreadyLoaded: results.filter(r => r.status === "already_loaded").length,
|
|
460
|
+
failed: results.filter(r => !r.success).length,
|
|
461
|
+
results
|
|
462
|
+
};
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
name: "batch_load_middleware_plugins",
|
|
466
|
+
description: "批量加载多个中间件插件。传入插件编码数组,一次性加载所有指定的中间件插件。",
|
|
467
|
+
schema: z.object({
|
|
468
|
+
pluginCodes: z.array(z.string().min(1)).min(1)
|
|
469
|
+
.describe("要批量加载的中间件插件编码数组,例如 ['weather-query', 'pg-query-tool']")
|
|
470
|
+
})
|
|
471
|
+
}
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
return {
|
|
475
|
+
name: MIDDLEWARE_PROVIDER,
|
|
476
|
+
tools: [
|
|
477
|
+
listMiddlewarePlugins,
|
|
478
|
+
loadMiddlewarePlugin,
|
|
479
|
+
unloadMiddlewarePlugin,
|
|
480
|
+
getMiddlewarePluginStatus,
|
|
481
|
+
refreshPluginCache,
|
|
482
|
+
batchLoadMiddlewarePlugins
|
|
483
|
+
]
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
Injectable()(PluginMiddleware);
|
|
489
|
+
AgentMiddlewareStrategy(MIDDLEWARE_PROVIDER)(PluginMiddleware);
|
|
490
|
+
|
|
491
|
+
class PluginModule {}
|
|
492
|
+
|
|
493
|
+
const plugin = {
|
|
494
|
+
meta: {
|
|
495
|
+
name: "@timmy_hu/plugin-middleware",
|
|
496
|
+
version: "1.0.0",
|
|
497
|
+
level: "organization",
|
|
498
|
+
category: "middleware",
|
|
499
|
+
displayName: "插件中间件",
|
|
500
|
+
description: "自动发现所有中间件类型插件,支持动态按需加载、卸载和状态查询,为智能体编排提供灵活的中间件管理能力。",
|
|
501
|
+
keywords: ["middleware", "plugin", "discovery", "dynamic-loading", "agent", "orchestration"],
|
|
502
|
+
author: "fpi"
|
|
503
|
+
},
|
|
504
|
+
register(ctx) {
|
|
505
|
+
if (ctx && ctx.logger) {
|
|
506
|
+
ctx.logger.log("register plugin-middleware middleware plugin");
|
|
507
|
+
}
|
|
508
|
+
return {
|
|
509
|
+
module: PluginModule,
|
|
510
|
+
global: true,
|
|
511
|
+
providers: [PluginMiddleware],
|
|
512
|
+
controllers: [],
|
|
513
|
+
exports: [PluginMiddleware]
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
module.exports = plugin;
|
|
519
|
+
module.exports.default = plugin;
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@timmy_hu/plugin-middleware",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "自动发现所有中间件类型插件,支持动态按需加载、卸载和状态查询",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "echo 'No build step required for CJS plugin'",
|
|
8
|
+
"test": "node -e \"require('./index.js')\""
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@langchain/core": "^0.3.0",
|
|
12
|
+
"@nestjs/common": "^11.0.0",
|
|
13
|
+
"reflect-metadata": "^0.2.0",
|
|
14
|
+
"rxjs": "^7.8.2",
|
|
15
|
+
"zod": "^3.23.0"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@xpert-ai/plugin-sdk": "^3.14.0"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"middleware",
|
|
22
|
+
"plugin",
|
|
23
|
+
"discovery",
|
|
24
|
+
"dynamic-loading",
|
|
25
|
+
"agent"
|
|
26
|
+
],
|
|
27
|
+
"author": "fpi",
|
|
28
|
+
"license": "MIT"
|
|
29
|
+
}
|