@rei-standard/amsg-server 2.1.1 → 2.3.1
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/README.md +32 -0
- package/dist/index.cjs +188 -21
- package/dist/index.d.cts +297 -24
- package/dist/index.d.ts +297 -24
- package/dist/index.mjs +185 -18
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -47,6 +47,71 @@ function isValidUUIDv4(uuid) {
|
|
|
47
47
|
const uuidV4Regex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
48
48
|
return uuidV4Regex.test(uuid);
|
|
49
49
|
}
|
|
50
|
+
var VALID_LLM_MESSAGE_ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant", "tool"]);
|
|
51
|
+
var AVATAR_URL_MAX_LENGTH = 2048;
|
|
52
|
+
function validateAvatarUrl(value) {
|
|
53
|
+
if (value === void 0 || value === null) return null;
|
|
54
|
+
if (typeof value !== "string") {
|
|
55
|
+
return "avatarUrl \u5FC5\u987B\u662F\u5B57\u7B26\u4E32";
|
|
56
|
+
}
|
|
57
|
+
if (/^data:/i.test(value)) {
|
|
58
|
+
return "\u5934\u50CF\u4E0D\u652F\u6301\u4F20\u5165 data: URI\uFF0C\u8BF7\u6539\u4E3A\u516C\u7F51\u53EF\u8BBF\u95EE\u7684 https:// \u56FE\u7247 URL";
|
|
59
|
+
}
|
|
60
|
+
if (value.length > AVATAR_URL_MAX_LENGTH) {
|
|
61
|
+
return `\u5934\u50CF URL \u957F\u5EA6 ${value.length} \u5B57\u7B26\u8D85\u8FC7 ${AVATAR_URL_MAX_LENGTH} \u4E0A\u9650\uFF0C\u8BF7\u6539\u4E3A\u66F4\u77ED\u7684\u56FE\u7247 URL`;
|
|
62
|
+
}
|
|
63
|
+
if (!isValidUrl(value)) {
|
|
64
|
+
return "avatarUrl \u4E0D\u662F\u5408\u6CD5 URL";
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
var SPLIT_PATTERN_MAX_LENGTH = 200;
|
|
69
|
+
var SPLIT_PATTERN_MAX_ITEMS = 10;
|
|
70
|
+
function validateSplitPattern(value) {
|
|
71
|
+
if (value === void 0 || value === null) return null;
|
|
72
|
+
const isArray = Array.isArray(value);
|
|
73
|
+
const items = isArray ? value : [value];
|
|
74
|
+
if (isArray && items.length === 0) return null;
|
|
75
|
+
if (items.length > SPLIT_PATTERN_MAX_ITEMS) {
|
|
76
|
+
return `splitPattern \u6570\u7EC4\u6700\u591A ${SPLIT_PATTERN_MAX_ITEMS} \u9879`;
|
|
77
|
+
}
|
|
78
|
+
for (let i = 0; i < items.length; i++) {
|
|
79
|
+
const s = items[i];
|
|
80
|
+
const label = isArray ? `splitPattern[${i}]` : "splitPattern";
|
|
81
|
+
if (typeof s !== "string") return `${label} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`;
|
|
82
|
+
if (s.length > SPLIT_PATTERN_MAX_LENGTH) {
|
|
83
|
+
return `${label} \u4E0D\u80FD\u8D85\u8FC7 ${SPLIT_PATTERN_MAX_LENGTH} \u5B57\u7B26`;
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
new RegExp(s);
|
|
87
|
+
} catch (_) {
|
|
88
|
+
return `${label} \u4E0D\u662F\u6709\u6548\u6B63\u5219\u8868\u8FBE\u5F0F`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
function validateLlmMessagesArray(messages) {
|
|
94
|
+
if (!Array.isArray(messages) || messages.length === 0) {
|
|
95
|
+
return "messages must be a non-empty array";
|
|
96
|
+
}
|
|
97
|
+
for (let i = 0; i < messages.length; i++) {
|
|
98
|
+
const m = messages[i];
|
|
99
|
+
if (!m || typeof m !== "object" || Array.isArray(m)) {
|
|
100
|
+
return `messages[${i}] must be an object`;
|
|
101
|
+
}
|
|
102
|
+
if (!VALID_LLM_MESSAGE_ROLES.has(m.role)) {
|
|
103
|
+
return `messages[${i}].role must be one of system / user / assistant / tool`;
|
|
104
|
+
}
|
|
105
|
+
if (typeof m.content === "string") {
|
|
106
|
+
if (!m.content) return `messages[${i}].content must be a non-empty string`;
|
|
107
|
+
} else if (Array.isArray(m.content)) {
|
|
108
|
+
if (m.content.length === 0) return `messages[${i}].content array must be non-empty`;
|
|
109
|
+
} else {
|
|
110
|
+
return `messages[${i}].content must be a non-empty string or a non-empty array`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
50
115
|
function validateScheduleMessagePayload(payload) {
|
|
51
116
|
if (!payload.contactName || typeof payload.contactName !== "string") {
|
|
52
117
|
return { valid: false, errorCode: "INVALID_PARAMETERS", errorMessage: "\u7F3A\u5C11\u5FC5\u9700\u53C2\u6570\u6216\u53C2\u6570\u683C\u5F0F\u9519\u8BEF", details: { missingFields: ["contactName"] } };
|
|
@@ -74,9 +139,35 @@ function validateScheduleMessagePayload(payload) {
|
|
|
74
139
|
return { valid: false, errorCode: "INVALID_PARAMETERS", errorMessage: "\u7F3A\u5C11\u5FC5\u9700\u53C2\u6570\u6216\u53C2\u6570\u683C\u5F0F\u9519\u8BEF", details: { missingFields: ["userMessage (required for fixed type)"] } };
|
|
75
140
|
}
|
|
76
141
|
}
|
|
142
|
+
const promptCheck = (() => {
|
|
143
|
+
const hasCompletePrompt = payload.completePrompt !== void 0 && payload.completePrompt !== null && payload.completePrompt !== "";
|
|
144
|
+
const hasMessages = payload.messages !== void 0 && payload.messages !== null;
|
|
145
|
+
if (hasCompletePrompt && hasMessages) {
|
|
146
|
+
return {
|
|
147
|
+
error: { code: "INVALID_PARAMETERS", message: "exactly one of `completePrompt` or `messages` must be provided\uFF08\u4E24\u8005\u4E0D\u80FD\u540C\u65F6\u51FA\u73B0\uFF09", details: { invalidFields: ["completePrompt", "messages"] } },
|
|
148
|
+
hasCompletePrompt: true,
|
|
149
|
+
hasMessages: true
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
if (hasMessages) {
|
|
153
|
+
const err = validateLlmMessagesArray(payload.messages);
|
|
154
|
+
if (err) {
|
|
155
|
+
return {
|
|
156
|
+
error: { code: "INVALID_PARAMETERS", message: err, details: { invalidFields: ["messages"] } },
|
|
157
|
+
hasCompletePrompt: false,
|
|
158
|
+
hasMessages: true
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return { error: null, hasCompletePrompt, hasMessages };
|
|
163
|
+
})();
|
|
164
|
+
if (promptCheck.error) {
|
|
165
|
+
return { valid: false, errorCode: promptCheck.error.code, errorMessage: promptCheck.error.message, details: promptCheck.error.details };
|
|
166
|
+
}
|
|
167
|
+
const hasPrompt = promptCheck.hasCompletePrompt || promptCheck.hasMessages;
|
|
77
168
|
if (payload.messageType === "prompted" || payload.messageType === "auto") {
|
|
78
169
|
const missingAiFields = [];
|
|
79
|
-
if (!
|
|
170
|
+
if (!hasPrompt) missingAiFields.push("completePrompt or messages");
|
|
80
171
|
if (!payload.apiUrl) missingAiFields.push("apiUrl");
|
|
81
172
|
if (!payload.apiKey) missingAiFields.push("apiKey");
|
|
82
173
|
if (!payload.primaryModel) missingAiFields.push("primaryModel");
|
|
@@ -88,14 +179,18 @@ function validateScheduleMessagePayload(payload) {
|
|
|
88
179
|
if (payload.recurrenceType && payload.recurrenceType !== "none") {
|
|
89
180
|
return { valid: false, errorCode: "INVALID_PARAMETERS", errorMessage: "instant \u7C7B\u578B\u7684 recurrenceType \u5FC5\u987B\u4E3A none", details: { invalidFields: ['recurrenceType (must be "none" for instant type)'] } };
|
|
90
181
|
}
|
|
91
|
-
const hasAiConfig =
|
|
182
|
+
const hasAiConfig = hasPrompt && payload.apiUrl && payload.apiKey && payload.primaryModel;
|
|
92
183
|
const hasUserMessage = payload.userMessage;
|
|
93
184
|
if (!hasAiConfig && !hasUserMessage) {
|
|
94
|
-
return { valid: false, errorCode: "INVALID_PARAMETERS", errorMessage: "instant \u7C7B\u578B\u5FC5\u987B\u63D0\u4F9B userMessage \u6216\u5B8C\u6574\u7684 AI \u914D\u7F6E", details: { missingFields: ["userMessage or (completePrompt + apiUrl + apiKey + primaryModel)"] } };
|
|
185
|
+
return { valid: false, errorCode: "INVALID_PARAMETERS", errorMessage: "instant \u7C7B\u578B\u5FC5\u987B\u63D0\u4F9B userMessage \u6216\u5B8C\u6574\u7684 AI \u914D\u7F6E", details: { missingFields: ["userMessage or ((completePrompt | messages) + apiUrl + apiKey + primaryModel)"] } };
|
|
95
186
|
}
|
|
96
187
|
}
|
|
97
|
-
if (payload.
|
|
98
|
-
return { valid: false, errorCode: "INVALID_PARAMETERS", errorMessage: "\u7F3A\u5C11\u5FC5\u9700\u53C2\u6570\u6216\u53C2\u6570\u683C\u5F0F\u9519\u8BEF", details: { invalidFields: ["
|
|
188
|
+
if (payload.temperature !== void 0 && payload.temperature !== null && (typeof payload.temperature !== "number" || !Number.isFinite(payload.temperature))) {
|
|
189
|
+
return { valid: false, errorCode: "INVALID_PARAMETERS", errorMessage: "\u7F3A\u5C11\u5FC5\u9700\u53C2\u6570\u6216\u53C2\u6570\u683C\u5F0F\u9519\u8BEF", details: { invalidFields: ["temperature (must be a finite number)"] } };
|
|
190
|
+
}
|
|
191
|
+
const avatarErr = validateAvatarUrl(payload.avatarUrl);
|
|
192
|
+
if (avatarErr) {
|
|
193
|
+
return { valid: false, errorCode: "INVALID_PARAMETERS", errorMessage: avatarErr, details: { invalidFields: ["avatarUrl"] } };
|
|
99
194
|
}
|
|
100
195
|
if (payload.uuid && !isValidUUID(payload.uuid)) {
|
|
101
196
|
return { valid: false, errorCode: "INVALID_PARAMETERS", errorMessage: "\u7F3A\u5C11\u5FC5\u9700\u53C2\u6570\u6216\u53C2\u6570\u683C\u5F0F\u9519\u8BEF", details: { invalidFields: ["uuid (invalid UUID format)"] } };
|
|
@@ -103,6 +198,10 @@ function validateScheduleMessagePayload(payload) {
|
|
|
103
198
|
if (payload.messageSubtype !== void 0 && payload.messageSubtype !== null && typeof payload.messageSubtype !== "string") {
|
|
104
199
|
return { valid: false, errorCode: "INVALID_PARAMETERS", errorMessage: "\u7F3A\u5C11\u5FC5\u9700\u53C2\u6570\u6216\u53C2\u6570\u683C\u5F0F\u9519\u8BEF", details: { invalidFields: ["messageSubtype"] } };
|
|
105
200
|
}
|
|
201
|
+
const splitErr = validateSplitPattern(payload.splitPattern);
|
|
202
|
+
if (splitErr) {
|
|
203
|
+
return { valid: false, errorCode: "INVALID_PARAMETERS", errorMessage: splitErr, details: { invalidFields: ["splitPattern"] } };
|
|
204
|
+
}
|
|
106
205
|
return { valid: true };
|
|
107
206
|
}
|
|
108
207
|
|
|
@@ -383,6 +482,26 @@ function isUniqueViolation(error) {
|
|
|
383
482
|
|
|
384
483
|
// src/server/lib/message-processor.js
|
|
385
484
|
import { randomUUID } from "crypto";
|
|
485
|
+
var DEFAULT_SPLIT_REGEX = /([。!?!?]+)/;
|
|
486
|
+
function splitOnceByRegex(chunk, regex) {
|
|
487
|
+
const out = chunk.split(regex).reduce((acc, part, i, arr) => {
|
|
488
|
+
if (i % 2 === 0 && part.trim()) {
|
|
489
|
+
const punctuation = arr[i + 1] || "";
|
|
490
|
+
acc.push(part.trim() + punctuation);
|
|
491
|
+
}
|
|
492
|
+
return acc;
|
|
493
|
+
}, []).filter((s) => s.length > 0);
|
|
494
|
+
return out.length > 0 ? out : [chunk];
|
|
495
|
+
}
|
|
496
|
+
function splitMessageIntoSentences(messageContent, splitPattern = null) {
|
|
497
|
+
const sources = splitPattern == null ? null : Array.isArray(splitPattern) ? splitPattern : [splitPattern];
|
|
498
|
+
const regexes = sources && sources.length > 0 ? sources.map((s) => new RegExp(s)) : [DEFAULT_SPLIT_REGEX];
|
|
499
|
+
let chunks = [messageContent];
|
|
500
|
+
for (const regex of regexes) {
|
|
501
|
+
chunks = chunks.flatMap((c) => splitOnceByRegex(c, regex));
|
|
502
|
+
}
|
|
503
|
+
return chunks.length > 0 ? chunks : [messageContent];
|
|
504
|
+
}
|
|
386
505
|
async function processSingleMessage(task, ctx, providedMasterKey) {
|
|
387
506
|
try {
|
|
388
507
|
const masterKey = providedMasterKey || ctx.masterKey;
|
|
@@ -395,7 +514,8 @@ async function processSingleMessage(task, ctx, providedMasterKey) {
|
|
|
395
514
|
if (decryptedPayload.messageType === "fixed") {
|
|
396
515
|
messageContent = decryptedPayload.userMessage;
|
|
397
516
|
} else if (decryptedPayload.messageType === "instant") {
|
|
398
|
-
|
|
517
|
+
const hasPrompt = !!decryptedPayload.completePrompt || Array.isArray(decryptedPayload.messages) && decryptedPayload.messages.length > 0;
|
|
518
|
+
if (hasPrompt && decryptedPayload.apiUrl && decryptedPayload.apiKey && decryptedPayload.primaryModel) {
|
|
399
519
|
messageContent = await _callAI(decryptedPayload);
|
|
400
520
|
} else if (decryptedPayload.userMessage) {
|
|
401
521
|
messageContent = decryptedPayload.userMessage;
|
|
@@ -407,14 +527,7 @@ async function processSingleMessage(task, ctx, providedMasterKey) {
|
|
|
407
527
|
} else {
|
|
408
528
|
throw new Error("Invalid message configuration: no content source available");
|
|
409
529
|
}
|
|
410
|
-
const
|
|
411
|
-
if (i % 2 === 0 && part.trim()) {
|
|
412
|
-
const punctuation = arr[i + 1] || "";
|
|
413
|
-
acc.push(part.trim() + punctuation);
|
|
414
|
-
}
|
|
415
|
-
return acc;
|
|
416
|
-
}, []).filter((s) => s.length > 0);
|
|
417
|
-
const messages = sentences.length > 0 ? sentences : [messageContent];
|
|
530
|
+
const messages = splitMessageIntoSentences(messageContent, decryptedPayload.splitPattern ?? null);
|
|
418
531
|
if (!ctx.vapid.email || !ctx.vapid.publicKey || !ctx.vapid.privateKey) {
|
|
419
532
|
throw new Error("VAPID configuration missing - push notifications cannot be sent");
|
|
420
533
|
}
|
|
@@ -537,11 +650,16 @@ async function _callAI(payload) {
|
|
|
537
650
|
return content.trim();
|
|
538
651
|
}
|
|
539
652
|
function buildAiRequestBody(payload) {
|
|
653
|
+
const llmMessages = Array.isArray(payload.messages) && payload.messages.length > 0 ? payload.messages : [{ role: "user", content: payload.completePrompt }];
|
|
540
654
|
const requestBody = {
|
|
541
655
|
model: payload.primaryModel,
|
|
542
|
-
messages:
|
|
543
|
-
temperature: 0.8
|
|
656
|
+
messages: llmMessages
|
|
544
657
|
};
|
|
658
|
+
if (payload.temperature !== void 0 && payload.temperature !== null) {
|
|
659
|
+
requestBody.temperature = payload.temperature;
|
|
660
|
+
} else if (!Array.isArray(payload.messages)) {
|
|
661
|
+
requestBody.temperature = 0.8;
|
|
662
|
+
}
|
|
545
663
|
if (payload.maxTokens === void 0 || payload.maxTokens === null) {
|
|
546
664
|
return requestBody;
|
|
547
665
|
}
|
|
@@ -641,8 +759,17 @@ function createScheduleMessageHandler(ctx) {
|
|
|
641
759
|
apiUrl: payload.apiUrl || null,
|
|
642
760
|
apiKey: payload.apiKey || null,
|
|
643
761
|
primaryModel: payload.primaryModel || null,
|
|
762
|
+
// Prompt is one-of: legacy completePrompt (string) OR messages (OpenAI-
|
|
763
|
+
// style array). Validation has already enforced exactly-one-of, so
|
|
764
|
+
// exactly one of these will be non-null when an AI config is provided.
|
|
644
765
|
completePrompt: payload.completePrompt || null,
|
|
766
|
+
messages: Array.isArray(payload.messages) ? payload.messages : null,
|
|
645
767
|
maxTokens: payload.maxTokens ?? null,
|
|
768
|
+
temperature: payload.temperature ?? null,
|
|
769
|
+
// 0.6.0+: optional caller-provided regex (string or string[]) used by
|
|
770
|
+
// the message processor to chunk LLM output into individual pushes.
|
|
771
|
+
// null → processor falls back to the default /([。!?!?]+)/ regex.
|
|
772
|
+
splitPattern: payload.splitPattern ?? null,
|
|
646
773
|
pushSubscription: payload.pushSubscription,
|
|
647
774
|
metadata: payload.metadata || {}
|
|
648
775
|
};
|
|
@@ -954,6 +1081,30 @@ function createUpdateMessageHandler(ctx) {
|
|
|
954
1081
|
if (Object.prototype.hasOwnProperty.call(updates, "maxTokens") && updates.maxTokens !== null && (!Number.isInteger(updates.maxTokens) || updates.maxTokens <= 0)) {
|
|
955
1082
|
return { status: 400, body: { success: false, error: { code: "INVALID_UPDATE_DATA", message: "\u66F4\u65B0\u6570\u636E\u683C\u5F0F\u9519\u8BEF", details: { invalidFields: ["maxTokens"] } } } };
|
|
956
1083
|
}
|
|
1084
|
+
if (updates.completePrompt && updates.messages !== void 0 && updates.messages !== null) {
|
|
1085
|
+
return { status: 400, body: { success: false, error: { code: "INVALID_UPDATE_DATA", message: "completePrompt \u4E0E messages \u4E0D\u80FD\u540C\u65F6\u66F4\u65B0\uFF08\u4E8C\u9009\u4E00\uFF09", details: { invalidFields: ["completePrompt", "messages"] } } } };
|
|
1086
|
+
}
|
|
1087
|
+
if (updates.messages !== void 0 && updates.messages !== null) {
|
|
1088
|
+
const msgErr = validateLlmMessagesArray(updates.messages);
|
|
1089
|
+
if (msgErr) {
|
|
1090
|
+
return { status: 400, body: { success: false, error: { code: "INVALID_UPDATE_DATA", message: msgErr, details: { invalidFields: ["messages"] } } } };
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
if (Object.prototype.hasOwnProperty.call(updates, "temperature") && updates.temperature !== null && (typeof updates.temperature !== "number" || !Number.isFinite(updates.temperature))) {
|
|
1094
|
+
return { status: 400, body: { success: false, error: { code: "INVALID_UPDATE_DATA", message: "\u66F4\u65B0\u6570\u636E\u683C\u5F0F\u9519\u8BEF", details: { invalidFields: ["temperature"] } } } };
|
|
1095
|
+
}
|
|
1096
|
+
if (Object.prototype.hasOwnProperty.call(updates, "splitPattern")) {
|
|
1097
|
+
const splitErr = validateSplitPattern(updates.splitPattern);
|
|
1098
|
+
if (splitErr) {
|
|
1099
|
+
return { status: 400, body: { success: false, error: { code: "INVALID_UPDATE_DATA", message: splitErr, details: { invalidFields: ["splitPattern"] } } } };
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
if (Object.prototype.hasOwnProperty.call(updates, "avatarUrl")) {
|
|
1103
|
+
const avatarErr = validateAvatarUrl(updates.avatarUrl);
|
|
1104
|
+
if (avatarErr) {
|
|
1105
|
+
return { status: 400, body: { success: false, error: { code: "INVALID_UPDATE_DATA", message: avatarErr, details: { invalidFields: ["avatarUrl"] } } } };
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
957
1108
|
const existingTask = await db.getTaskByUuid(taskUuid, userId);
|
|
958
1109
|
if (!existingTask) {
|
|
959
1110
|
const taskStatus = await db.getTaskStatus(taskUuid, userId);
|
|
@@ -963,14 +1114,27 @@ function createUpdateMessageHandler(ctx) {
|
|
|
963
1114
|
return { status: 409, body: { success: false, error: { code: "TASK_ALREADY_COMPLETED", message: "\u4EFB\u52A1\u5DF2\u5B8C\u6210\u6216\u5DF2\u5931\u8D25\uFF0C\u65E0\u6CD5\u66F4\u65B0" } } };
|
|
964
1115
|
}
|
|
965
1116
|
const existingData = JSON.parse(decryptFromStorage(existingTask.encrypted_payload, userKey));
|
|
1117
|
+
const promptUpdates = {};
|
|
1118
|
+
if (updates.completePrompt) {
|
|
1119
|
+
promptUpdates.completePrompt = updates.completePrompt;
|
|
1120
|
+
promptUpdates.messages = null;
|
|
1121
|
+
} else if (updates.messages !== void 0 && updates.messages !== null) {
|
|
1122
|
+
promptUpdates.messages = updates.messages;
|
|
1123
|
+
promptUpdates.completePrompt = null;
|
|
1124
|
+
}
|
|
966
1125
|
const updatedData = {
|
|
967
1126
|
...existingData,
|
|
968
|
-
...
|
|
1127
|
+
...promptUpdates,
|
|
969
1128
|
...updates.userMessage && { userMessage: updates.userMessage },
|
|
970
1129
|
...updates.recurrenceType && { recurrenceType: updates.recurrenceType },
|
|
971
1130
|
...updates.avatarUrl && { avatarUrl: updates.avatarUrl },
|
|
972
1131
|
...updates.metadata && { metadata: updates.metadata },
|
|
973
|
-
...Object.prototype.hasOwnProperty.call(updates, "maxTokens") && { maxTokens: updates.maxTokens ?? null }
|
|
1132
|
+
...Object.prototype.hasOwnProperty.call(updates, "maxTokens") && { maxTokens: updates.maxTokens ?? null },
|
|
1133
|
+
...Object.prototype.hasOwnProperty.call(updates, "temperature") && { temperature: updates.temperature ?? null },
|
|
1134
|
+
// splitPattern: hasOwnProperty so that explicit `null` (= revert to
|
|
1135
|
+
// default) doesn't get swallowed by truthy-spread the way the optional
|
|
1136
|
+
// string fields above are.
|
|
1137
|
+
...Object.prototype.hasOwnProperty.call(updates, "splitPattern") && { splitPattern: updates.splitPattern ?? null }
|
|
974
1138
|
};
|
|
975
1139
|
const encryptedPayload = encryptForStorage(JSON.stringify(updatedData), userKey);
|
|
976
1140
|
const extraFields = updates.nextSendAt ? { next_send_at: updates.nextSendAt } : void 0;
|
|
@@ -1491,6 +1655,9 @@ export {
|
|
|
1491
1655
|
isValidUUID,
|
|
1492
1656
|
isValidUUIDv4,
|
|
1493
1657
|
isValidUrl,
|
|
1658
|
+
validateAvatarUrl,
|
|
1659
|
+
validateLlmMessagesArray,
|
|
1494
1660
|
validateScheduleMessagePayload,
|
|
1661
|
+
validateSplitPattern,
|
|
1495
1662
|
verifyTenantToken
|
|
1496
1663
|
};
|