Update server/wsHandler.js
Browse files- server/wsHandler.js +72 -14
server/wsHandler.js
CHANGED
|
@@ -48,6 +48,7 @@ import { pendingTurnstileTokens } from './index.js';
|
|
| 48 |
|
| 49 |
const activeStreams = new Map();
|
| 50 |
const VERSION_META_FIELDS = ['toolCalls', 'responseEdits', 'responseSegments', 'error'];
|
|
|
|
| 51 |
const CONTINUE_ASSISTANT_PROMPT =
|
| 52 |
'Continue your previous response exactly where it left off. Do not restart, summarize, or repeat the opening. Preserve the same formatting and only add the missing continuation.';
|
| 53 |
const FREE_WEB_SEARCH_LIMIT = 15;
|
|
@@ -454,7 +455,13 @@ const handlers = {
|
|
| 454 |
await sessionStore.updateUserSession(client.userId, client.accessToken, sessionId, { history: newHistory, name: newName });
|
| 455 |
else sessionStore.updateTempSession(client.tempId, sessionId, { history: newHistory, name: newName });
|
| 456 |
|
| 457 |
-
safeSend(ws, {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 458 |
},
|
| 459 |
onError(err) {
|
| 460 |
activeStreams.delete(ws);
|
|
@@ -525,7 +532,15 @@ const handlers = {
|
|
| 525 |
return safeSend(ws, { type: 'error', message: 'Failed to apply edit - message lost' });
|
| 526 |
}
|
| 527 |
|
| 528 |
-
safeSend(ws, {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 529 |
},
|
| 530 |
|
| 531 |
'chat:selectVersion': async (ws, msg, client) => {
|
|
@@ -560,7 +575,14 @@ const handlers = {
|
|
| 560 |
}
|
| 561 |
|
| 562 |
// Send back with messageId for clarity
|
| 563 |
-
safeSend(ws, {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 564 |
},
|
| 565 |
|
| 566 |
'chat:assistantAction': async (ws, msg, client) => {
|
|
@@ -709,7 +731,13 @@ const handlers = {
|
|
| 709 |
sessionStore.updateTempSession(client.tempId, sessionId, { history: newHistory, name: newName });
|
| 710 |
}
|
| 711 |
|
| 712 |
-
safeSend(ws, {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 713 |
},
|
| 714 |
onError(err) {
|
| 715 |
activeStreams.delete(ws);
|
|
@@ -853,7 +881,22 @@ const handlers = {
|
|
| 853 |
},
|
| 854 |
};
|
| 855 |
|
| 856 |
-
function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 857 |
|
| 858 |
function getClientOwner(client) {
|
| 859 |
return client.userId
|
|
@@ -1093,6 +1136,10 @@ function cloneVersionMetaValue(value) {
|
|
| 1093 |
return JSON.parse(JSON.stringify(value));
|
| 1094 |
}
|
| 1095 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1096 |
function syncMessageFromActiveVersion(message) {
|
| 1097 |
if (!message) return message;
|
| 1098 |
const currentVersion = getActiveVersion(message);
|
|
@@ -1143,16 +1190,23 @@ function appendConversationTurn(rootMessage, userEntry, assistantEntry, mediaEnt
|
|
| 1143 |
|
| 1144 |
function extractFlatHistory(rootMessage) {
|
| 1145 |
if (!rootMessage) return [];
|
| 1146 |
-
|
| 1147 |
-
|
| 1148 |
-
|
| 1149 |
-
if (
|
| 1150 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1151 |
}
|
| 1152 |
-
return
|
| 1153 |
};
|
| 1154 |
-
|
| 1155 |
-
const history = [
|
| 1156 |
const currentVerIdx = rootMessage.currentVersionIdx ?? 0;
|
| 1157 |
|
| 1158 |
if (!Array.isArray(rootMessage.versions)) {
|
|
@@ -1171,7 +1225,11 @@ function extractFlatHistory(rootMessage) {
|
|
| 1171 |
const walkTail = (tail) => {
|
| 1172 |
for (let i = 0; i < tail.length; i++) {
|
| 1173 |
const msg = tail[i];
|
| 1174 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1175 |
const ver = msg.versions?.[msg.currentVersionIdx ?? 0];
|
| 1176 |
if (ver?.tail && Array.isArray(ver.tail)) {
|
| 1177 |
walkTail(ver.tail);
|
|
|
|
| 48 |
|
| 49 |
const activeStreams = new Map();
|
| 50 |
const VERSION_META_FIELDS = ['toolCalls', 'responseEdits', 'responseSegments', 'error'];
|
| 51 |
+
const ROOT_JSON_KEY = '__historyRootJson';
|
| 52 |
const CONTINUE_ASSISTANT_PROMPT =
|
| 53 |
'Continue your previous response exactly where it left off. Do not restart, summarize, or repeat the opening. Preserve the same formatting and only add the missing continuation.';
|
| 54 |
const FREE_WEB_SEARCH_LIMIT = 15;
|
|
|
|
| 455 |
await sessionStore.updateUserSession(client.userId, client.accessToken, sessionId, { history: newHistory, name: newName });
|
| 456 |
else sessionStore.updateTempSession(client.tempId, sessionId, { history: newHistory, name: newName });
|
| 457 |
|
| 458 |
+
safeSend(ws, {
|
| 459 |
+
type: aborted ? 'chat:aborted' : 'chat:done',
|
| 460 |
+
sessionId,
|
| 461 |
+
name: newName,
|
| 462 |
+
history: extractFlatHistory(newRootMessage),
|
| 463 |
+
[ROOT_JSON_KEY]: JSON.stringify(newRootMessage),
|
| 464 |
+
});
|
| 465 |
},
|
| 466 |
onError(err) {
|
| 467 |
activeStreams.delete(ws);
|
|
|
|
| 532 |
return safeSend(ws, { type: 'error', message: 'Failed to apply edit - message lost' });
|
| 533 |
}
|
| 534 |
|
| 535 |
+
safeSend(ws, {
|
| 536 |
+
type: 'chat:messageEdited',
|
| 537 |
+
sessionId,
|
| 538 |
+
messageId: targetMsg.id,
|
| 539 |
+
messageIndex,
|
| 540 |
+
message: updatedTargetMsg,
|
| 541 |
+
history: updatedFlatHistory,
|
| 542 |
+
[ROOT_JSON_KEY]: JSON.stringify(newRoot),
|
| 543 |
+
});
|
| 544 |
},
|
| 545 |
|
| 546 |
'chat:selectVersion': async (ws, msg, client) => {
|
|
|
|
| 575 |
}
|
| 576 |
|
| 577 |
// Send back with messageId for clarity
|
| 578 |
+
safeSend(ws, {
|
| 579 |
+
type: 'chat:versionSelected',
|
| 580 |
+
sessionId,
|
| 581 |
+
messageId: targetMsg.id,
|
| 582 |
+
messageIndex,
|
| 583 |
+
history: extractFlatHistory(newRoot),
|
| 584 |
+
[ROOT_JSON_KEY]: JSON.stringify(newRoot),
|
| 585 |
+
});
|
| 586 |
},
|
| 587 |
|
| 588 |
'chat:assistantAction': async (ws, msg, client) => {
|
|
|
|
| 731 |
sessionStore.updateTempSession(client.tempId, sessionId, { history: newHistory, name: newName });
|
| 732 |
}
|
| 733 |
|
| 734 |
+
safeSend(ws, {
|
| 735 |
+
type: 'chat:done',
|
| 736 |
+
sessionId,
|
| 737 |
+
name: newName,
|
| 738 |
+
history: extractFlatHistory(newRoot),
|
| 739 |
+
[ROOT_JSON_KEY]: JSON.stringify(newRoot),
|
| 740 |
+
});
|
| 741 |
},
|
| 742 |
onError(err) {
|
| 743 |
activeStreams.delete(ws);
|
|
|
|
| 881 |
},
|
| 882 |
};
|
| 883 |
|
| 884 |
+
export function serializeSessionForClient(session) {
|
| 885 |
+
const rootMessage = Array.isArray(session?.history) && session.history[0]
|
| 886 |
+
? cloneAndRepairTree(session.history[0])
|
| 887 |
+
: null;
|
| 888 |
+
return {
|
| 889 |
+
id: session?.id,
|
| 890 |
+
name: session?.name,
|
| 891 |
+
created: session?.created,
|
| 892 |
+
history: rootMessage ? extractFlatHistory(rootMessage) : [],
|
| 893 |
+
model: session?.model || null,
|
| 894 |
+
updatedAt: session?.updatedAt || null,
|
| 895 |
+
[ROOT_JSON_KEY]: rootMessage ? JSON.stringify(rootMessage) : null,
|
| 896 |
+
};
|
| 897 |
+
}
|
| 898 |
+
|
| 899 |
+
function ser(s) { return serializeSessionForClient(s); }
|
| 900 |
|
| 901 |
function getClientOwner(client) {
|
| 902 |
return client.userId
|
|
|
|
| 1136 |
return JSON.parse(JSON.stringify(value));
|
| 1137 |
}
|
| 1138 |
|
| 1139 |
+
function cloneJson(value) {
|
| 1140 |
+
return JSON.parse(JSON.stringify(value));
|
| 1141 |
+
}
|
| 1142 |
+
|
| 1143 |
function syncMessageFromActiveVersion(message) {
|
| 1144 |
if (!message) return message;
|
| 1145 |
const currentVersion = getActiveVersion(message);
|
|
|
|
| 1190 |
|
| 1191 |
function extractFlatHistory(rootMessage) {
|
| 1192 |
if (!rootMessage) return [];
|
| 1193 |
+
|
| 1194 |
+
const toFlatEntry = (message) => {
|
| 1195 |
+
const cloned = cloneJson(message);
|
| 1196 |
+
if (cloned.content === undefined || cloned.content === null) {
|
| 1197 |
+
cloned.content = '';
|
| 1198 |
+
}
|
| 1199 |
+
syncMessageFromActiveVersion(cloned);
|
| 1200 |
+
if (Array.isArray(cloned.versions)) {
|
| 1201 |
+
cloned.versions = cloned.versions.map((version) => ({
|
| 1202 |
+
...version,
|
| 1203 |
+
tail: [],
|
| 1204 |
+
}));
|
| 1205 |
}
|
| 1206 |
+
return cloned;
|
| 1207 |
};
|
| 1208 |
+
|
| 1209 |
+
const history = [toFlatEntry(rootMessage)];
|
| 1210 |
const currentVerIdx = rootMessage.currentVersionIdx ?? 0;
|
| 1211 |
|
| 1212 |
if (!Array.isArray(rootMessage.versions)) {
|
|
|
|
| 1225 |
const walkTail = (tail) => {
|
| 1226 |
for (let i = 0; i < tail.length; i++) {
|
| 1227 |
const msg = tail[i];
|
| 1228 |
+
if (msg?.content === undefined || msg?.content === null) {
|
| 1229 |
+
msg.content = '';
|
| 1230 |
+
}
|
| 1231 |
+
syncMessageFromActiveVersion(msg);
|
| 1232 |
+
history.push(toFlatEntry(msg));
|
| 1233 |
const ver = msg.versions?.[msg.currentVersionIdx ?? 0];
|
| 1234 |
if (ver?.tail && Array.isArray(ver.tail)) {
|
| 1235 |
walkTail(ver.tail);
|