mm_os 4.2.8 → 4.3.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.
Files changed (3) hide show
  1. package/ai.js +130 -0
  2. package/core/plugin/index.js +297 -328
  3. package/package.json +3 -2
package/ai.js ADDED
@@ -0,0 +1,130 @@
1
+ /**
2
+ * ai.js
3
+ * AI模块管理类
4
+ * 负责加载并初始化mm_ai模块,桥接前后端AI对话
5
+ */
6
+
7
+ const path = require('path');
8
+ const fs = require('fs');
9
+
10
+ async function tryRequire() {
11
+ try {
12
+ return require('mm_ai');
13
+ } catch (error) {
14
+ console.log('mm_ai模块未安装,尝试安装...');
15
+ await require('npm').exec('npm i mm_ai');
16
+ return require('mm_ai');
17
+ }
18
+ }
19
+
20
+ /**
21
+ * 覆写 Agent.prototype.filterMessages,将消息中的 /file/ 路径转为 LLM 可读格式
22
+ * @param {Array} messages - 消息记录
23
+ * @returns {Array} 转换后的消息记录
24
+ */
25
+ function overrideFilterMessages(messages) {
26
+ if (!messages || !messages.length) {
27
+ return messages;
28
+ }
29
+ var result = [];
30
+ for (var i = 0; i < messages.length; i++) {
31
+ var msg = messages[i];
32
+ if (msg.role !== 'user' || typeof msg.content !== 'string') {
33
+ result.push(msg);
34
+ continue;
35
+ }
36
+ var content = msg.content;
37
+ var parts = [];
38
+ var last_idx = 0;
39
+ var file_re = /!?\[([^\]]*)\]\((\/file\/[^)]+)\)/g;
40
+ var match;
41
+ while ((match = file_re.exec(content)) !== null) {
42
+ if (match.index > last_idx) {
43
+ parts.push({ type: 'text', text: content.substring(last_idx, match.index) });
44
+ }
45
+ var alt = match[1] || '文件';
46
+ var file_url = match[2];
47
+ var rel_path = '.' + file_url;
48
+ var full_path = rel_path.fullname($.run_path);
49
+ if (fs.existsSync(full_path)) {
50
+ var ext = path.extname(full_path).toLowerCase();
51
+ var img_exts = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.svg'];
52
+ var text_exts = ['.txt', '.js', '.ts', '.py', '.json', '.md', '.css', '.html', '.xml',
53
+ '.yaml', '.yml', '.ini', '.cfg', '.conf', '.sh', '.bat', '.ps1', '.sql',
54
+ '.java', '.go', '.rs', '.rb', '.php', '.c', '.cpp', '.h', '.hpp',
55
+ '.log', '.csv', '.env', '.toml'];
56
+ if (img_exts.indexOf(ext) !== -1) {
57
+ try {
58
+ var img_data = fs.readFileSync(full_path);
59
+ var base64 = img_data.toString('base64');
60
+ var mime = 'image/' + (ext === '.jpg' ? 'jpeg' : ext.replace('.', ''));
61
+ parts.push({ type: 'image_url', image_url: { url: 'data:' + mime + ';base64,' + base64 } });
62
+ } catch (e) {
63
+ parts.push({ type: 'text', text: '[图片加载失败: ' + alt + ']' });
64
+ }
65
+ } else if (text_exts.indexOf(ext) !== -1) {
66
+ try {
67
+ var file_content = fs.readFileSync(full_path, 'utf-8');
68
+ parts.push({ type: 'text', text: '--- ' + alt + ' ---\n' + file_content + '\n---' });
69
+ } catch (e) {
70
+ parts.push({ type: 'text', text: '[文件读取失败: ' + alt + ']' });
71
+ }
72
+ } else {
73
+ parts.push({ type: 'text', text: '[文件: ' + alt + ']' });
74
+ }
75
+ } else {
76
+ parts.push({ type: 'text', text: match[0] });
77
+ }
78
+ last_idx = match.index + match[0].length;
79
+ }
80
+ if (last_idx < content.length) {
81
+ parts.push({ type: 'text', text: content.substring(last_idx) });
82
+ }
83
+ var user_content;
84
+ if (parts.length === 0) {
85
+ user_content = content;
86
+ } else if (parts.length === 1 && parts[0].type === 'text') {
87
+ user_content = parts[0].text;
88
+ } else {
89
+ user_content = parts;
90
+ }
91
+ result.push({ ...msg, content: user_content });
92
+ }
93
+ return result;
94
+ }
95
+
96
+ /**
97
+ * 初始化AI模块
98
+ * 创建MM_ai实例(mm_ai内部已注册chat:in事件处理)
99
+ * @param {object} server 服务器实例
100
+ */
101
+ async function initAI(server) {
102
+ // 检查AI开关
103
+ if (!server.config.sys || !server.config.sys.ai) {
104
+ return null;
105
+ }
106
+
107
+ try {
108
+ var mod = await tryRequire();
109
+ if (!mod || !mod.MM_ai) {
110
+ server.log('warn', 'mm_ai模块加载失败');
111
+ return null;
112
+ }
113
+
114
+ // 覆写 Agent.prototype.filterMessages 处理文件路径
115
+ var { Agent } = require('mm_ai/core/agent/index.js');
116
+ Agent.prototype.filterMessages = overrideFilterMessages;
117
+
118
+ var ai = new mod.MM_ai(server.config, server);
119
+ server.ai = ai;
120
+ await ai.run();
121
+ return ai;
122
+ } catch (error) {
123
+ server.log('error', 'AI模块加载失败', error);
124
+ return null;
125
+ }
126
+ }
127
+
128
+ module.exports = {
129
+ initAI
130
+ };
@@ -1,328 +1,297 @@
1
- const {
2
- Drive
3
- } = require('mm_machine');
4
-
5
- /**
6
- * 插件基类
7
- * 负责管理插件的生命周期、资源加载和依赖管理
8
- */
9
- class Plugin extends Drive {
10
- static config = {
11
- // 插件名称
12
- name: '',
13
- // 插件标题
14
- title: '插件',
15
- // 插件描述
16
- description: '介绍插件的作用',
17
- // 插件版本
18
- version: '1.0.0',
19
- // 用于什么应用
20
- app: 'tool',
21
- // 作者
22
- author: 'qww',
23
- // 主文件
24
- main: './index.js',
25
- // git仓库地址
26
- git: '',
27
- // 依赖的npm模块
28
- dependencies: []
29
- };
30
- /**
31
- * 构造函数
32
- * @param {object} config 配置参数
33
- * @param {object} parent 父对象
34
- */
35
- constructor(config, parent) {
36
- super({ ...Plugin.config, ...config || {} }, parent);
37
- this.options = {};
38
- }
39
- }
40
-
41
-
42
- /**
43
- * 获取模板目录
44
- * @returns {string} 模板目录
45
- */
46
- Plugin.prototype.getTplDir = function () {
47
- return __dirname;
48
- };
49
-
50
- /**
51
- * 初始化核心
52
- * @param {object} app 应用实例
53
- * @param {object} eventer 事件管理器
54
- * @param {object} logger 日志管理器
55
- * @private
56
- */
57
- Plugin.prototype._initCore = async function (app, eventer, logger) {
58
- // 初始化依赖项
59
- if (logger) {
60
- this.setLogger(logger);
61
- }
62
- if (eventer) {
63
- this.getEventer = function () {
64
- return eventer;
65
- };
66
- }
67
- if (app) {
68
- this.getApp = function () {
69
- return app;
70
- };
71
- this._db = app.db;
72
- this._cache = app.cache;
73
- this._filer = app.filer;
74
- }
75
- // // 初始化管理
76
- // await this._initManager();
77
- // // 加载资源
78
- // await this._loadSources();
79
- // // 初始化资源
80
- // await this._initSources();
81
- // 初始化配置
82
- this._initOptions();
83
- };
84
-
85
- /**
86
- * 获取应用实例
87
- * @returns {object} 应用实例
88
- */
89
- Plugin.prototype.getApp = function () {
90
- // 初始化资源
91
- return this.getParent();
92
- };
93
-
94
- /**
95
- * 获取插件配置
96
- * @returns {object} 插件配置
97
- */
98
- Plugin.prototype.getOptions = function () {
99
- return this.options;
100
- };
101
-
102
- /**
103
- * 插件初始化之后
104
- */
105
- Plugin.prototype._initOptions = function () {
106
- var options = this.getConfigOptions();
107
- this.options = this.mergeOptions(options);
108
- this.backupOptions();
109
- };
110
-
111
- /**
112
- * 转换数字类型值
113
- * @param {*} value 原始值
114
- * @returns {number} 转换后的值
115
- * @private
116
- */
117
- Plugin.prototype._convertNumber = function (value) {
118
- if (value === 'null') return 0;
119
- return Number(value || '0');
120
- };
121
-
122
- /**
123
- * 转换布尔类型值
124
- * @param {*} value 原始值
125
- * @returns {boolean} 转换后的值
126
- * @private
127
- */
128
- Plugin.prototype._convertBoolean = function (value) {
129
- if (!value) return false;
130
- if (typeof value === 'boolean') return value;
131
- if (typeof value === 'string') {
132
- return value === '1' || value === 'true';
133
- }
134
- return false;
135
- };
136
-
137
- /**
138
- * 转换对象类型值
139
- * @param {*} value 原始值
140
- * @returns {object} 转换后的值
141
- * @private
142
- */
143
- Plugin.prototype._convertObject = function (value) {
144
- if (value === 'null') return {};
145
- return value.toJSON ? value.toJSON() : {};
146
- };
147
-
148
- /**
149
- * 转换数组类型值
150
- * @param {*} value 原始值
151
- * @returns {Array} 转换后的值
152
- * @private
153
- */
154
- Plugin.prototype._convertArray = function (value) {
155
- if (value === 'null') return [];
156
- return value.toJSON ? value.toJSON() : [];
157
- };
158
-
159
- /**
160
- * 转换字符串类型值
161
- * @param {*} value 原始值
162
- * @returns {string} 转换后的值
163
- * @private
164
- */
165
- Plugin.prototype._convertString = function (value) {
166
- if (value === 'null') return null;
167
- return value || '';
168
- };
169
-
170
- /**
171
- * 转换单个配置项的值
172
- * @param {object} option 配置项
173
- * @returns {*} 转换后的值
174
- * @private
175
- */
176
- Plugin.prototype._convertOptionValue = function (option) {
177
- var val = option.value;
178
- if (val === 'null') return null;
179
-
180
- var type = option.type;
181
- switch (type) {
182
- case 'number':
183
- return this._convertNumber(val);
184
- case 'boolean':
185
- return this._convertBoolean(val);
186
- case 'object':
187
- return this._convertObject(val);
188
- case 'array':
189
- return this._convertArray(val);
190
- case 'string':
191
- return this._convertString(val);
192
- default:
193
- return val;
194
- }
195
- };
196
-
197
- /**
198
- * 获取配置参数
199
- * @returns {object} 返回配置参数
200
- */
201
- Plugin.prototype.getConfigOptions = function () {
202
- var op = this.config.options || [];
203
- var dict = {};
204
- for (var i = 0; i < op.length; i++) {
205
- var o = op[i];
206
- dict[o.name] = this._convertOptionValue(o);
207
- }
208
- return dict;
209
- };
210
-
211
- /**
212
- * 设计配置
213
- * @param {object} body 配置参数
214
- */
215
- Plugin.prototype.designOptions = function (body) {
216
- var cg = this.config;
217
- if (Array.isArray(body)) {
218
- cg.options = body;
219
- } else {
220
- var options = cg.options || [];
221
- var option = options.getObj({
222
- name: body.name
223
- });
224
- if (option) {
225
- Object.assign(option, body);
226
- } else {
227
- options.push(body);
228
- }
229
- cg.options = options;
230
- }
231
- };
232
-
233
- /**
234
- * 保存配置
235
- * @param {object} options 配置参数
236
- */
237
- Plugin.prototype.saveOptions = function (options) {
238
- this.options = options;
239
- this.backupOptions();
240
- };
241
-
242
- /**
243
- * 保存配置
244
- */
245
- Plugin.prototype.backupOptions = function () {
246
- var file = this._getCacheOptionsFile();
247
- file = file.fullname();
248
- file.addDir();
249
- file.saveJson(this.options);
250
- };
251
-
252
- /**
253
- * 合并配置
254
- * @param {object} options 配置参数
255
- * @returns {object} 返回配置参数
256
- */
257
- Plugin.prototype.mergeOptions = function (options) {
258
- var file = this._getCacheOptionsFile();
259
- var options_cache = file.loadJson();
260
- if (options_cache) {
261
- $.push(options, options_cache);
262
- }
263
- return options;
264
- };
265
-
266
- /**
267
- * 获取缓存配置文件
268
- * @returns {string} 缓存配置文件
269
- */
270
- Plugin.prototype._getCacheOptionsFile = function () {
271
- let plugin_name = this.config.name;
272
- let app_name = this.getApp().config.name;
273
- var file = `/cache/${app_name}/${plugin_name}/config.json`.fullname();
274
- return file;
275
- };
276
-
277
-
278
- /**
279
- * 获取模型
280
- * @param {string} type 模型类型
281
- * @returns {object} 返回获取到的模型
282
- */
283
- Drive.prototype.getModel = function (type) {
284
- let model = { ...this.config };
285
- let dir = this.getDir();
286
- let l = $.slash;
287
- let app_name = dir.between('app' + l, l);
288
- let plugin_name = dir.between('plugin' + l, l);
289
- let name = dir.basename();
290
- model.app = app_name;
291
- model.plugin = plugin_name;
292
- model.name = model.name || name;
293
- model.path = '/' + app_name + '/' + name;
294
- return model;
295
- };
296
-
297
-
298
- /**
299
- * 安装插件
300
- * @private
301
- */
302
- Plugin.prototype._install = async function () {
303
- return this;
304
- };
305
-
306
- /**
307
- * 安装插件
308
- */
309
- Plugin.prototype.install = async function () {
310
- return this._install();
311
- };
312
-
313
- /**
314
- * 卸载插件
315
- * @private
316
- */
317
- Plugin.prototype._uninstall = async function () {
318
- return this;
319
- };
320
-
321
- /**
322
- * 卸载插件
323
- */
324
- Plugin.prototype.uninstall = async function () {
325
- return this._uninstall();
326
- };
327
-
328
- exports.Plugin = Plugin;
1
+ const { Drive } = require('mm_machine');
2
+
3
+ /**
4
+ * 插件基类
5
+ * 负责管理插件的生命周期、资源加载和依赖管理
6
+ */
7
+ class Plugin extends Drive {
8
+ static config = {
9
+ // 插件名称
10
+ name: '',
11
+ // 插件标题
12
+ title: '插件',
13
+ // 插件描述
14
+ description: '介绍插件的作用',
15
+ // 插件版本
16
+ version: '1.0.0',
17
+ // 用于什么应用
18
+ app: 'tool',
19
+ // 作者
20
+ author: 'qww',
21
+ // 主文件
22
+ main: './index.js',
23
+ // git仓库地址
24
+ git: '',
25
+ // 依赖的npm模块
26
+ dependencies: [],
27
+ };
28
+ /**
29
+ * 构造函数
30
+ * @param {object} config 配置参数
31
+ * @param {object} parent 父对象
32
+ */
33
+ constructor(config, parent) {
34
+ super({ ...Plugin.config, ...(config || {}) }, parent);
35
+ this.options = {};
36
+ }
37
+ }
38
+
39
+ /**
40
+ * 获取模板目录
41
+ * @returns {string} 模板目录
42
+ */
43
+ Plugin.prototype.getTplDir = function () {
44
+ return __dirname;
45
+ };
46
+
47
+ /**
48
+ * 初始化核心
49
+ * @param {object} app 应用实例
50
+ * @param {object} eventer 事件管理器
51
+ * @param {object} logger 日志管理器
52
+ * @private
53
+ */
54
+ Plugin.prototype._initCore = async function (app, eventer, logger) {
55
+ // 初始化依赖项
56
+ if (logger) {
57
+ this.setLogger(logger);
58
+ }
59
+ if (eventer) {
60
+ this.getEventer = function () {
61
+ return eventer;
62
+ };
63
+ }
64
+ if (app) {
65
+ this.getApp = function () {
66
+ return app;
67
+ };
68
+ this._db = app.db;
69
+ this._cache = app.cache;
70
+ this._filer = app.filer;
71
+ }
72
+ // // 初始化管理
73
+ // await this._initManager();
74
+ // // 加载资源
75
+ // await this._loadSources();
76
+ // // 初始化资源
77
+ // await this._initSources();
78
+ // 初始化配置
79
+ this._initOptions();
80
+ };
81
+
82
+ /**
83
+ * 获取应用实例
84
+ * @returns {object} 应用实例
85
+ */
86
+ Plugin.prototype.getApp = function () {
87
+ // 初始化资源
88
+ return this.getParent();
89
+ };
90
+
91
+ /**
92
+ * 获取插件配置
93
+ * @returns {object} 插件配置
94
+ */
95
+ Plugin.prototype.getOptions = function () {
96
+ return this.options;
97
+ };
98
+
99
+ /**
100
+ * 初始化插件选项
101
+ * 从config.options中提取默认值,mm_machine的save/load机制负责持久化
102
+ */
103
+ Plugin.prototype._initOptions = function () {
104
+ this.options = this.getConfigOptions();
105
+ };
106
+
107
+ /**
108
+ * 转换数字类型值
109
+ * @param {*} value 原始值
110
+ * @returns {number} 转换后的值
111
+ * @private
112
+ */
113
+ Plugin.prototype._convertNumber = function (value) {
114
+ if (value === 'null') return 0;
115
+ return Number(value || '0');
116
+ };
117
+
118
+ /**
119
+ * 转换布尔类型值
120
+ * @param {*} value 原始值
121
+ * @returns {boolean} 转换后的值
122
+ * @private
123
+ */
124
+ Plugin.prototype._convertBoolean = function (value) {
125
+ if (!value) return false;
126
+ if (typeof value === 'boolean') return value;
127
+ if (typeof value === 'string') {
128
+ return value === '1' || value === 'true';
129
+ }
130
+ return false;
131
+ };
132
+
133
+ /**
134
+ * 转换对象类型值
135
+ * @param {*} value 原始值
136
+ * @returns {object} 转换后的值
137
+ * @private
138
+ */
139
+ Plugin.prototype._convertObject = function (value) {
140
+ if (value === 'null') return {};
141
+ return value.toJSON ? value.toJSON() : {};
142
+ };
143
+
144
+ /**
145
+ * 转换数组类型值
146
+ * @param {*} value 原始值
147
+ * @returns {Array} 转换后的值
148
+ * @private
149
+ */
150
+ Plugin.prototype._convertArray = function (value) {
151
+ if (value === 'null') return [];
152
+ return value.toJSON ? value.toJSON() : [];
153
+ };
154
+
155
+ /**
156
+ * 转换字符串类型值
157
+ * @param {*} value 原始值
158
+ * @returns {string} 转换后的值
159
+ * @private
160
+ */
161
+ Plugin.prototype._convertString = function (value) {
162
+ if (value === 'null') return null;
163
+ return value || '';
164
+ };
165
+
166
+ /**
167
+ * 转换单个配置项的值
168
+ * @param {object} option 配置项
169
+ * @returns {*} 转换后的值
170
+ * @private
171
+ */
172
+ Plugin.prototype._convertOptionValue = function (option) {
173
+ var val = option.value;
174
+ if (val === 'null') return null;
175
+
176
+ var type = option.type;
177
+ switch (type) {
178
+ case 'number':
179
+ return this._convertNumber(val);
180
+ case 'boolean':
181
+ return this._convertBoolean(val);
182
+ case 'object':
183
+ return this._convertObject(val);
184
+ case 'array':
185
+ return this._convertArray(val);
186
+ case 'string':
187
+ return this._convertString(val);
188
+ default:
189
+ return val;
190
+ }
191
+ };
192
+
193
+ /**
194
+ * 获取配置参数
195
+ * @returns {object} 返回配置参数
196
+ */
197
+ Plugin.prototype.getConfigOptions = function () {
198
+ var op = this.config.options || [];
199
+ var dict = {};
200
+ for (var i = 0; i < op.length; i++) {
201
+ var o = op[i];
202
+ dict[o.name] = this._convertOptionValue(o);
203
+ }
204
+ return dict;
205
+ };
206
+
207
+ /**
208
+ * 设计配置
209
+ * @param {object} body 配置参数
210
+ */
211
+ Plugin.prototype.designOptions = function (body) {
212
+ var cg = this.config;
213
+ if (Array.isArray(body)) {
214
+ cg.options = body;
215
+ } else {
216
+ var options = cg.options || [];
217
+ var option = options.getObj({
218
+ name: body.name,
219
+ });
220
+ if (option) {
221
+ Object.assign(option, body);
222
+ } else {
223
+ options.push(body);
224
+ }
225
+ cg.options = options;
226
+ }
227
+ };
228
+
229
+ /**
230
+ * 保存配置
231
+ * 更新options字典和config.options数组中的值,并通过mm_machine的save()持久化
232
+ * @param {object} options 配置参数
233
+ */
234
+ Plugin.prototype.saveOptions = function (options) {
235
+ this.options = options;
236
+ var config_options = this.config.options;
237
+ if (config_options) {
238
+ for (var i = 0; i < config_options.length; i++) {
239
+ var o = config_options[i];
240
+ if (o.name in options) {
241
+ o.value = options[o.name];
242
+ }
243
+ }
244
+ }
245
+ this.save();
246
+ };
247
+
248
+ /**
249
+ * 获取模型
250
+ * @param {string} type 模型类型
251
+ * @returns {object} 返回获取到的模型
252
+ */
253
+ Drive.prototype.getModel = function (type) {
254
+ let model = { ...this.config };
255
+ let dir = this.getDir();
256
+ let l = $.slash;
257
+ let app_name = dir.between('app' + l, l);
258
+ let plugin_name = dir.between('plugin' + l, l);
259
+ let name = dir.basename();
260
+ model.app = app_name;
261
+ model.plugin = plugin_name;
262
+ model.name = model.name || name;
263
+ model.path = '/' + app_name + '/' + name;
264
+ return model;
265
+ };
266
+
267
+ /**
268
+ * 安装插件
269
+ * @private
270
+ */
271
+ Plugin.prototype._install = async function () {
272
+ return this;
273
+ };
274
+
275
+ /**
276
+ * 安装插件
277
+ */
278
+ Plugin.prototype.install = async function () {
279
+ return this._install();
280
+ };
281
+
282
+ /**
283
+ * 卸载插件
284
+ * @private
285
+ */
286
+ Plugin.prototype._uninstall = async function () {
287
+ return this;
288
+ };
289
+
290
+ /**
291
+ * 卸载插件
292
+ */
293
+ Plugin.prototype.uninstall = async function () {
294
+ return this._uninstall();
295
+ };
296
+
297
+ exports.Plugin = Plugin;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mm_os",
3
3
  "description": "MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。",
4
- "version": "4.2.8",
4
+ "version": "4.3.0",
5
5
  "main": "index.js",
6
6
  "keywords": [
7
7
  "AI",
@@ -79,6 +79,7 @@
79
79
  "core/",
80
80
  "ulits/",
81
81
  "tcp.js",
82
- "software.js"
82
+ "software.js",
83
+ "ai.js"
83
84
  ]
84
85
  }