rol-websocket-channel 1.4.2 → 1.4.8

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 (43) hide show
  1. package/{MQTT-API /346/226/260/345/242/236/346/226/207/344/273/266/345/212/237/350/203/275.md" → MQTT-API 5-6.md } +89 -1
  2. package/dist/index.js +617 -617
  3. package/dist/message-handler.js +515 -503
  4. package/dist/src/admin/cli.js +43 -43
  5. package/dist/src/admin/jsonrpc.js +60 -60
  6. package/dist/src/admin/lib/fs.js +30 -30
  7. package/dist/src/admin/lib/paths.js +80 -80
  8. package/dist/src/admin/methods/admin.js +60 -60
  9. package/dist/src/admin/methods/agents-extended.js +251 -251
  10. package/dist/src/admin/methods/artifacts.js +736 -642
  11. package/dist/src/admin/methods/artifacts.test.js +210 -191
  12. package/dist/src/admin/methods/cron.js +250 -250
  13. package/dist/src/admin/methods/index.js +104 -102
  14. package/dist/src/admin/methods/mem9.js +309 -270
  15. package/dist/src/admin/methods/mem9.test.js +34 -0
  16. package/dist/src/admin/methods/memory.js +363 -363
  17. package/dist/src/admin/methods/models-extended.js +190 -190
  18. package/dist/src/admin/methods/models.js +195 -195
  19. package/dist/src/admin/methods/pairing.js +268 -268
  20. package/dist/src/admin/methods/sessions-extended.js +215 -215
  21. package/dist/src/admin/methods/sessions.js +75 -75
  22. package/dist/src/admin/methods/skills-extended.js +157 -157
  23. package/dist/src/admin/methods/skills-toggle.js +183 -183
  24. package/dist/src/admin/methods/skills.js +528 -528
  25. package/dist/src/admin/methods/system.js +271 -180
  26. package/dist/src/admin/methods/usage.js +1170 -1170
  27. package/dist/src/admin/types.js +1 -1
  28. package/dist/src/mqtt/connection-manager.js +209 -209
  29. package/dist/src/mqtt/index.js +5 -5
  30. package/dist/src/mqtt/mqtt-client.js +110 -110
  31. package/dist/src/mqtt/mqtt.test.js +418 -418
  32. package/dist/src/mqtt/types.js +2 -2
  33. package/dist/src/shared/context.js +24 -24
  34. package/dist/src/shared/wrapper.js +23 -23
  35. package/message-handler.ts +15 -1
  36. package/openclaw.plugin.json +73 -0
  37. package/package.json +1 -1
  38. package/src/admin/methods/artifacts.test.ts +35 -0
  39. package/src/admin/methods/artifacts.ts +140 -2
  40. package/src/admin/methods/index.ts +3 -1
  41. package/src/admin/methods/mem9.test.ts +39 -0
  42. package/src/admin/methods/mem9.ts +48 -1
  43. package/src/admin/methods/system.ts +129 -1
@@ -1,190 +1,190 @@
1
- import path from 'node:path';
2
- import { readJsonFile, writeJsonFile } from '../lib/fs.js';
3
- import { JsonRpcException, JSON_RPC_ERRORS } from '../jsonrpc.js';
4
- // 允许修改的 provider 配置字段白名单
5
- const ALLOWED_PROVIDER_FIELDS = {
6
- 'apiKey': true,
7
- 'api': true,
8
- 'baseUrl': true,
9
- 'models': true,
10
- 'name': true,
11
- 'label': true,
12
- 'model': true,
13
- 'temperature': true,
14
- 'maxTokens': true,
15
- 'topP': true,
16
- 'frequencyPenalty': true,
17
- 'presencePenalty': true,
18
- };
19
- /**
20
- * 更新模型配置
21
- * 支持修改 primary model 和 provider 配置
22
- */
23
- export const updateModels = async (params, context) => {
24
- const objectParams = isObject(params) ? params : {};
25
- const primaryModel = pickString(objectParams.primaryModel);
26
- const modelProvider = pickString(objectParams.modelProvider);
27
- const provider = pickString(objectParams.provider);
28
- const providerConfig = isObject(objectParams.providerConfig) ? objectParams.providerConfig : null;
29
- const configPath = path.join(context.openclawRoot, 'openclaw.json');
30
- const config = await readJsonFile(configPath);
31
- let updated = false;
32
- const changes = [];
33
- // 更新 primary model
34
- if (primaryModel) {
35
- if (!config.agents)
36
- config.agents = {};
37
- if (!config.agents.defaults)
38
- config.agents.defaults = {};
39
- if (!config.agents.defaults.model)
40
- config.agents.defaults.model = {};
41
- config.agents.defaults.model.primary = primaryModel;
42
- const inferredProvider = inferProviderFromPrimaryModel(primaryModel);
43
- if (modelProvider && modelProvider !== inferredProvider) {
44
- throwModelError('MODEL_PROVIDER_MISMATCH', 'modelProvider does not match primaryModel');
45
- }
46
- updated = true;
47
- changes.push(`Updated primary model to: ${primaryModel}`);
48
- }
49
- if (modelProvider && !primaryModel) {
50
- throwModelError('MODEL_PROVIDER_DERIVED', 'modelProvider cannot be updated directly; set primaryModel in provider/model format');
51
- }
52
- // 更新 provider 配置
53
- if (provider && providerConfig) {
54
- if (!config.models)
55
- config.models = {};
56
- if (!config.models.providers)
57
- config.models.providers = {};
58
- // 验证字段白名单
59
- for (const field of Object.keys(providerConfig)) {
60
- if (!ALLOWED_PROVIDER_FIELDS[field]) {
61
- throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, `Field not allowed for provider config: ${field}. Allowed fields: ${Object.keys(ALLOWED_PROVIDER_FIELDS).join(', ')}`);
62
- }
63
- }
64
- // 合并配置
65
- if (!config.models.providers[provider]) {
66
- config.models.providers[provider] = {};
67
- }
68
- config.models.providers[provider] = {
69
- ...config.models.providers[provider],
70
- ...providerConfig
71
- };
72
- updated = true;
73
- changes.push(`Updated provider config for: ${provider}`);
74
- }
75
- if (!updated) {
76
- throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, 'No valid update parameters provided. Use primaryModel, modelProvider, or provider+providerConfig.');
77
- }
78
- // 写回配置文件
79
- await writeJsonFile(configPath, config);
80
- return {
81
- success: true,
82
- configFile: configPath,
83
- changes,
84
- updatedConfig: {
85
- primaryModel: config.agents?.defaults?.model?.primary ?? null,
86
- modelProvider: config.agents?.defaults?.model?.primary
87
- ? inferProviderFromPrimaryModel(config.agents.defaults.model.primary)
88
- : null,
89
- defaultModel: config.agents?.defaults?.model ?? {},
90
- providers: redactSecrets(config.models?.providers ?? {})
91
- }
92
- };
93
- };
94
- export const setModel = async (params, context) => {
95
- const objectParams = isObject(params) ? params : {};
96
- const primary = pickString(objectParams.primary);
97
- const provider = pickString(objectParams.provider);
98
- if (!primary) {
99
- throwModelError('MODEL_PRIMARY_REQUIRED', 'primary is required');
100
- }
101
- const inferredProvider = inferProviderFromPrimaryModel(primary);
102
- if (!inferredProvider) {
103
- throwModelError('MODEL_PRIMARY_INVALID', 'primary must be in provider/model format');
104
- }
105
- if (provider && provider !== inferredProvider) {
106
- throwModelError('MODEL_PROVIDER_MISMATCH', 'provider does not match primary');
107
- }
108
- const configPath = path.join(context.openclawRoot, 'openclaw.json');
109
- const config = await readJsonFile(configPath);
110
- if (!isAllowedModel(config, primary)) {
111
- throwModelError('MODEL_NOT_ALLOWED', 'model is not in allowed model options');
112
- }
113
- if (!config.agents)
114
- config.agents = {};
115
- if (!config.agents.defaults)
116
- config.agents.defaults = {};
117
- if (!config.agents.defaults.model)
118
- config.agents.defaults.model = {};
119
- config.agents.defaults.model.primary = primary;
120
- await writeJsonFile(configPath, config);
121
- return {
122
- ok: true,
123
- model: {
124
- primary,
125
- provider: inferredProvider
126
- },
127
- defaults: {
128
- model: config.agents.defaults.model
129
- }
130
- };
131
- };
132
- function inferProviderFromPrimaryModel(primaryModel) {
133
- const slashIndex = primaryModel.indexOf('/');
134
- if (slashIndex <= 0) {
135
- return null;
136
- }
137
- return primaryModel.slice(0, slashIndex);
138
- }
139
- function isAllowedModel(config, primary) {
140
- const catalog = config.agents?.defaults?.models;
141
- if (catalog && typeof catalog === 'object' && !Array.isArray(catalog)) {
142
- return Object.prototype.hasOwnProperty.call(catalog, primary);
143
- }
144
- const currentPrimary = pickString(config.agents?.defaults?.model?.primary);
145
- if (currentPrimary === primary) {
146
- return true;
147
- }
148
- const agents = Array.isArray(config.agents?.list) ? config.agents.list : [];
149
- return agents.some((agent) => pickString(agent?.model?.primary) === primary);
150
- }
151
- function throwModelError(errorCode, message) {
152
- throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, message, { code: errorCode });
153
- }
154
- function pickString(value) {
155
- if (typeof value !== 'string') {
156
- return null;
157
- }
158
- const trimmed = value.trim();
159
- return trimmed.length > 0 ? trimmed : null;
160
- }
161
- function isObject(value) {
162
- return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
163
- }
164
- function redactSecrets(value) {
165
- if (Array.isArray(value)) {
166
- return value.map(redactSecrets);
167
- }
168
- if (!value || typeof value !== 'object') {
169
- return value;
170
- }
171
- const result = {};
172
- for (const [key, nestedValue] of Object.entries(value)) {
173
- if (isSecretKey(key) && typeof nestedValue === 'string') {
174
- result[key] = redactString(nestedValue);
175
- continue;
176
- }
177
- result[key] = redactSecrets(nestedValue);
178
- }
179
- return result;
180
- }
181
- function isSecretKey(key) {
182
- const normalized = key.toLowerCase();
183
- return normalized.includes('apikey') || normalized.includes('token') || normalized.includes('secret');
184
- }
185
- function redactString(value) {
186
- if (value.length <= 8) {
187
- return '********';
188
- }
189
- return `${value.slice(0, 4)}***${value.slice(-4)}`;
190
- }
1
+ import path from 'node:path';
2
+ import { readJsonFile, writeJsonFile } from '../lib/fs.js';
3
+ import { JsonRpcException, JSON_RPC_ERRORS } from '../jsonrpc.js';
4
+ // 允许修改的 provider 配置字段白名单
5
+ const ALLOWED_PROVIDER_FIELDS = {
6
+ 'apiKey': true,
7
+ 'api': true,
8
+ 'baseUrl': true,
9
+ 'models': true,
10
+ 'name': true,
11
+ 'label': true,
12
+ 'model': true,
13
+ 'temperature': true,
14
+ 'maxTokens': true,
15
+ 'topP': true,
16
+ 'frequencyPenalty': true,
17
+ 'presencePenalty': true,
18
+ };
19
+ /**
20
+ * 更新模型配置
21
+ * 支持修改 primary model 和 provider 配置
22
+ */
23
+ export const updateModels = async (params, context) => {
24
+ const objectParams = isObject(params) ? params : {};
25
+ const primaryModel = pickString(objectParams.primaryModel);
26
+ const modelProvider = pickString(objectParams.modelProvider);
27
+ const provider = pickString(objectParams.provider);
28
+ const providerConfig = isObject(objectParams.providerConfig) ? objectParams.providerConfig : null;
29
+ const configPath = path.join(context.openclawRoot, 'openclaw.json');
30
+ const config = await readJsonFile(configPath);
31
+ let updated = false;
32
+ const changes = [];
33
+ // 更新 primary model
34
+ if (primaryModel) {
35
+ if (!config.agents)
36
+ config.agents = {};
37
+ if (!config.agents.defaults)
38
+ config.agents.defaults = {};
39
+ if (!config.agents.defaults.model)
40
+ config.agents.defaults.model = {};
41
+ config.agents.defaults.model.primary = primaryModel;
42
+ const inferredProvider = inferProviderFromPrimaryModel(primaryModel);
43
+ if (modelProvider && modelProvider !== inferredProvider) {
44
+ throwModelError('MODEL_PROVIDER_MISMATCH', 'modelProvider does not match primaryModel');
45
+ }
46
+ updated = true;
47
+ changes.push(`Updated primary model to: ${primaryModel}`);
48
+ }
49
+ if (modelProvider && !primaryModel) {
50
+ throwModelError('MODEL_PROVIDER_DERIVED', 'modelProvider cannot be updated directly; set primaryModel in provider/model format');
51
+ }
52
+ // 更新 provider 配置
53
+ if (provider && providerConfig) {
54
+ if (!config.models)
55
+ config.models = {};
56
+ if (!config.models.providers)
57
+ config.models.providers = {};
58
+ // 验证字段白名单
59
+ for (const field of Object.keys(providerConfig)) {
60
+ if (!ALLOWED_PROVIDER_FIELDS[field]) {
61
+ throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, `Field not allowed for provider config: ${field}. Allowed fields: ${Object.keys(ALLOWED_PROVIDER_FIELDS).join(', ')}`);
62
+ }
63
+ }
64
+ // 合并配置
65
+ if (!config.models.providers[provider]) {
66
+ config.models.providers[provider] = {};
67
+ }
68
+ config.models.providers[provider] = {
69
+ ...config.models.providers[provider],
70
+ ...providerConfig
71
+ };
72
+ updated = true;
73
+ changes.push(`Updated provider config for: ${provider}`);
74
+ }
75
+ if (!updated) {
76
+ throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, 'No valid update parameters provided. Use primaryModel, modelProvider, or provider+providerConfig.');
77
+ }
78
+ // 写回配置文件
79
+ await writeJsonFile(configPath, config);
80
+ return {
81
+ success: true,
82
+ configFile: configPath,
83
+ changes,
84
+ updatedConfig: {
85
+ primaryModel: config.agents?.defaults?.model?.primary ?? null,
86
+ modelProvider: config.agents?.defaults?.model?.primary
87
+ ? inferProviderFromPrimaryModel(config.agents.defaults.model.primary)
88
+ : null,
89
+ defaultModel: config.agents?.defaults?.model ?? {},
90
+ providers: redactSecrets(config.models?.providers ?? {})
91
+ }
92
+ };
93
+ };
94
+ export const setModel = async (params, context) => {
95
+ const objectParams = isObject(params) ? params : {};
96
+ const primary = pickString(objectParams.primary);
97
+ const provider = pickString(objectParams.provider);
98
+ if (!primary) {
99
+ throwModelError('MODEL_PRIMARY_REQUIRED', 'primary is required');
100
+ }
101
+ const inferredProvider = inferProviderFromPrimaryModel(primary);
102
+ if (!inferredProvider) {
103
+ throwModelError('MODEL_PRIMARY_INVALID', 'primary must be in provider/model format');
104
+ }
105
+ if (provider && provider !== inferredProvider) {
106
+ throwModelError('MODEL_PROVIDER_MISMATCH', 'provider does not match primary');
107
+ }
108
+ const configPath = path.join(context.openclawRoot, 'openclaw.json');
109
+ const config = await readJsonFile(configPath);
110
+ if (!isAllowedModel(config, primary)) {
111
+ throwModelError('MODEL_NOT_ALLOWED', 'model is not in allowed model options');
112
+ }
113
+ if (!config.agents)
114
+ config.agents = {};
115
+ if (!config.agents.defaults)
116
+ config.agents.defaults = {};
117
+ if (!config.agents.defaults.model)
118
+ config.agents.defaults.model = {};
119
+ config.agents.defaults.model.primary = primary;
120
+ await writeJsonFile(configPath, config);
121
+ return {
122
+ ok: true,
123
+ model: {
124
+ primary,
125
+ provider: inferredProvider
126
+ },
127
+ defaults: {
128
+ model: config.agents.defaults.model
129
+ }
130
+ };
131
+ };
132
+ function inferProviderFromPrimaryModel(primaryModel) {
133
+ const slashIndex = primaryModel.indexOf('/');
134
+ if (slashIndex <= 0) {
135
+ return null;
136
+ }
137
+ return primaryModel.slice(0, slashIndex);
138
+ }
139
+ function isAllowedModel(config, primary) {
140
+ const catalog = config.agents?.defaults?.models;
141
+ if (catalog && typeof catalog === 'object' && !Array.isArray(catalog)) {
142
+ return Object.prototype.hasOwnProperty.call(catalog, primary);
143
+ }
144
+ const currentPrimary = pickString(config.agents?.defaults?.model?.primary);
145
+ if (currentPrimary === primary) {
146
+ return true;
147
+ }
148
+ const agents = Array.isArray(config.agents?.list) ? config.agents.list : [];
149
+ return agents.some((agent) => pickString(agent?.model?.primary) === primary);
150
+ }
151
+ function throwModelError(errorCode, message) {
152
+ throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, message, { code: errorCode });
153
+ }
154
+ function pickString(value) {
155
+ if (typeof value !== 'string') {
156
+ return null;
157
+ }
158
+ const trimmed = value.trim();
159
+ return trimmed.length > 0 ? trimmed : null;
160
+ }
161
+ function isObject(value) {
162
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
163
+ }
164
+ function redactSecrets(value) {
165
+ if (Array.isArray(value)) {
166
+ return value.map(redactSecrets);
167
+ }
168
+ if (!value || typeof value !== 'object') {
169
+ return value;
170
+ }
171
+ const result = {};
172
+ for (const [key, nestedValue] of Object.entries(value)) {
173
+ if (isSecretKey(key) && typeof nestedValue === 'string') {
174
+ result[key] = redactString(nestedValue);
175
+ continue;
176
+ }
177
+ result[key] = redactSecrets(nestedValue);
178
+ }
179
+ return result;
180
+ }
181
+ function isSecretKey(key) {
182
+ const normalized = key.toLowerCase();
183
+ return normalized.includes('apikey') || normalized.includes('token') || normalized.includes('secret');
184
+ }
185
+ function redactString(value) {
186
+ if (value.length <= 8) {
187
+ return '********';
188
+ }
189
+ return `${value.slice(0, 4)}***${value.slice(-4)}`;
190
+ }