sharktide commited on
Commit
b682f80
·
verified ·
1 Parent(s): f97a46d

Create chatSessionSerializer.js

Browse files
Files changed (1) hide show
  1. server/chatSessionSerializer.js +139 -0
server/chatSessionSerializer.js ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const ROOT_JSON_KEY = '__historyRootJson';
2
+ const VERSION_META_FIELDS = ['toolCalls', 'responseEdits', 'responseSegments', 'error'];
3
+
4
+ function validateAndRepairTree(rootMessage) {
5
+ const repair = (msg) => {
6
+ if (!msg) return;
7
+ if (msg.content === undefined || msg.content === null) {
8
+ msg.content = '';
9
+ }
10
+ if (msg.versions && Array.isArray(msg.versions)) {
11
+ for (const version of msg.versions) {
12
+ if (version.content === undefined || version.content === null) {
13
+ version.content = '';
14
+ }
15
+ if (version.tail && Array.isArray(version.tail)) {
16
+ for (const tailMsg of version.tail) {
17
+ repair(tailMsg);
18
+ }
19
+ }
20
+ }
21
+ }
22
+ };
23
+ repair(rootMessage);
24
+ return rootMessage;
25
+ }
26
+
27
+ function cloneAndRepairTree(rootMessage) {
28
+ return validateAndRepairTree(JSON.parse(JSON.stringify(rootMessage)));
29
+ }
30
+
31
+ function getActiveVersion(message) {
32
+ if (!message) return null;
33
+ const versions = Array.isArray(message.versions) ? message.versions : [];
34
+ if (!versions.length) {
35
+ message.versions = [{ content: message.content ?? '', tail: [], timestamp: Date.now() }];
36
+ message.currentVersionIdx = 0;
37
+ return message.versions[0];
38
+ }
39
+ const currentVersionIdx = Number.isInteger(message.currentVersionIdx)
40
+ ? Math.max(0, Math.min(message.currentVersionIdx, versions.length - 1))
41
+ : 0;
42
+ message.currentVersionIdx = currentVersionIdx;
43
+ if (!Array.isArray(message.versions[currentVersionIdx].tail)) {
44
+ message.versions[currentVersionIdx].tail = [];
45
+ }
46
+ if (message.versions[currentVersionIdx].content === undefined || message.versions[currentVersionIdx].content === null) {
47
+ message.versions[currentVersionIdx].content = message.content ?? '';
48
+ }
49
+ return message.versions[currentVersionIdx];
50
+ }
51
+
52
+ function cloneVersionMetaValue(value) {
53
+ if (value === undefined) return undefined;
54
+ return JSON.parse(JSON.stringify(value));
55
+ }
56
+
57
+ function syncMessageFromActiveVersion(message) {
58
+ if (!message) return message;
59
+ const currentVersion = getActiveVersion(message);
60
+ if (!currentVersion) return message;
61
+ message.content = currentVersion.content ?? message.content ?? '';
62
+ VERSION_META_FIELDS.forEach((key) => {
63
+ if (key in currentVersion) {
64
+ message[key] = cloneVersionMetaValue(currentVersion[key]);
65
+ } else {
66
+ delete message[key];
67
+ }
68
+ });
69
+ return message;
70
+ }
71
+
72
+ function cloneJson(value) {
73
+ return JSON.parse(JSON.stringify(value));
74
+ }
75
+
76
+ export function extractFlatHistory(rootMessage) {
77
+ if (!rootMessage) return [];
78
+
79
+ const toFlatEntry = (message) => {
80
+ const cloned = cloneJson(message);
81
+ if (cloned.content === undefined || cloned.content === null) {
82
+ cloned.content = '';
83
+ }
84
+ syncMessageFromActiveVersion(cloned);
85
+ if (Array.isArray(cloned.versions)) {
86
+ cloned.versions = cloned.versions.map((version) => ({
87
+ ...version,
88
+ tail: [],
89
+ }));
90
+ }
91
+ return cloned;
92
+ };
93
+
94
+ const history = [toFlatEntry(rootMessage)];
95
+ const currentVerIdx = rootMessage.currentVersionIdx ?? 0;
96
+
97
+ if (!Array.isArray(rootMessage.versions) || currentVerIdx >= rootMessage.versions.length) {
98
+ return history;
99
+ }
100
+
101
+ const currentTail = rootMessage.versions[currentVerIdx]?.tail;
102
+ if (currentTail && Array.isArray(currentTail)) {
103
+ const walkTail = (tail) => {
104
+ for (let i = 0; i < tail.length; i++) {
105
+ const msg = tail[i];
106
+ if (msg?.content === undefined || msg?.content === null) {
107
+ msg.content = '';
108
+ }
109
+ syncMessageFromActiveVersion(msg);
110
+ history.push(toFlatEntry(msg));
111
+ const ver = msg.versions?.[msg.currentVersionIdx ?? 0];
112
+ if (ver?.tail && Array.isArray(ver.tail)) {
113
+ walkTail(ver.tail);
114
+ }
115
+ if (msg.role === 'user' && Array.isArray(msg.versions) && msg.versions.length > 1) {
116
+ break;
117
+ }
118
+ }
119
+ };
120
+ walkTail(currentTail);
121
+ }
122
+
123
+ return history;
124
+ }
125
+
126
+ export function serializeSessionForClient(session) {
127
+ const rootMessage = Array.isArray(session?.history) && session.history[0]
128
+ ? cloneAndRepairTree(session.history[0])
129
+ : null;
130
+ return {
131
+ id: session?.id,
132
+ name: session?.name,
133
+ created: session?.created,
134
+ history: rootMessage ? extractFlatHistory(rootMessage) : [],
135
+ model: session?.model || null,
136
+ updatedAt: session?.updatedAt || null,
137
+ [ROOT_JSON_KEY]: rootMessage ? JSON.stringify(rootMessage) : null,
138
+ };
139
+ }