R.C.M. commited on
Commit
03d60b4
·
1 Parent(s): caeb530

Revert "Add new session handling"

Browse files

This reverts commit caeb5301c1d9f9f999894dfab9625bce6adc06b9.

server/chatSessionSerializer.js DELETED
@@ -1,139 +0,0 @@
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
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
server/index.js CHANGED
@@ -10,13 +10,11 @@ import rateLimit from 'express-rate-limit';
10
  import fs from 'fs';
11
  import { registerFeedbackRoutes } from './handleFeedback.js';
12
  import { abortActiveStream, handleWsMessage } from './wsHandler.js';
13
- import { serializeSessionForClient } from './chatSessionSerializer.js';
14
  import { sessionStore, initStoreConfig } from './sessionStore.js';
15
  import { SUPABASE_URL, SUPABASE_ANON_KEY } from './config.js';
16
  import { safeSend } from './helpers.js';
17
  import { verifySupabaseToken } from './auth.js';
18
  import { mediaStore } from './mediaStore.js';
19
- import { pendingTurnstileTokens } from './turnstileState.js';
20
 
21
  export { SUPABASE_URL, SUPABASE_ANON_KEY };
22
  export { LIGHTNING_BASE, PUBLIC_URL } from './config.js';
@@ -413,12 +411,12 @@ app.get('/api/db/chats', async (req, res) => {
413
  })),
414
  });
415
  }
416
- const items = [];
417
- for (const listedSession of listed) {
418
- const full = await sessionStore.getUserSessionResolved(resolved.user.id, listedSession.id);
419
- if (full) items.push(serializeSessionForClient(full));
420
- }
421
- res.json({ items });
422
  } catch (err) {
423
  console.error('db chats list error', err);
424
  res.status(500).json({ error: 'db:chats_list_failed' });
@@ -438,7 +436,7 @@ app.post('/api/db/chats', async (req, res) => {
438
  if (Object.keys(patch).length) {
439
  created = await sessionStore.updateUserSession(resolved.user.id, resolved.accessToken, created.id, patch);
440
  }
441
- res.status(201).json({ item: serializeSessionForClient(created) });
442
  } catch (err) {
443
  console.error('db chat create error', err);
444
  res.status(500).json({ error: 'db:chat_create_failed' });
@@ -451,7 +449,7 @@ app.get('/api/db/chats/:sessionId', async (req, res) => {
451
  try {
452
  const session = await sessionStore.getUserSessionResolved(resolved.user.id, req.params.sessionId);
453
  if (!session) return res.status(404).json({ error: 'db:chat_not_found' });
454
- res.json({ item: serializeSessionForClient(session) });
455
  } catch (err) {
456
  console.error('db chat get error', err);
457
  res.status(500).json({ error: 'db:chat_get_failed' });
@@ -475,7 +473,7 @@ app.patch('/api/db/chats/:sessionId', async (req, res) => {
475
  patch
476
  );
477
  if (!updated) return res.status(404).json({ error: 'db:chat_not_found' });
478
- res.json({ item: serializeSessionForClient(updated) });
479
  } catch (err) {
480
  console.error('db chat patch error', err);
481
  res.status(500).json({ error: 'db:chat_update_failed' });
@@ -728,7 +726,7 @@ app.get('/api/db/export', async (req, res) => {
728
  const chats = [];
729
  for (const listedSession of listed) {
730
  const full = await sessionStore.getUserSessionResolved(resolved.user.id, listedSession.id);
731
- if (full) chats.push(serializeSessionForClient(full));
732
  }
733
 
734
  const mediaResult = await mediaStore.listAll(resolved.owner, { view: 'all' });
@@ -990,6 +988,8 @@ app.get('/api/media/:id/content', async (req, res) => {
990
  }
991
  });
992
 
 
 
993
  app.post('/api/turnstile', async (req, res) => {
994
  try {
995
  const token = req.body?.token;
 
10
  import fs from 'fs';
11
  import { registerFeedbackRoutes } from './handleFeedback.js';
12
  import { abortActiveStream, handleWsMessage } from './wsHandler.js';
 
13
  import { sessionStore, initStoreConfig } from './sessionStore.js';
14
  import { SUPABASE_URL, SUPABASE_ANON_KEY } from './config.js';
15
  import { safeSend } from './helpers.js';
16
  import { verifySupabaseToken } from './auth.js';
17
  import { mediaStore } from './mediaStore.js';
 
18
 
19
  export { SUPABASE_URL, SUPABASE_ANON_KEY };
20
  export { LIGHTNING_BASE, PUBLIC_URL } from './config.js';
 
411
  })),
412
  });
413
  }
414
+ const items = [];
415
+ for (const listedSession of listed) {
416
+ const full = await sessionStore.getUserSessionResolved(resolved.user.id, listedSession.id);
417
+ if (full) items.push(full);
418
+ }
419
+ res.json({ items });
420
  } catch (err) {
421
  console.error('db chats list error', err);
422
  res.status(500).json({ error: 'db:chats_list_failed' });
 
436
  if (Object.keys(patch).length) {
437
  created = await sessionStore.updateUserSession(resolved.user.id, resolved.accessToken, created.id, patch);
438
  }
439
+ res.status(201).json({ item: created });
440
  } catch (err) {
441
  console.error('db chat create error', err);
442
  res.status(500).json({ error: 'db:chat_create_failed' });
 
449
  try {
450
  const session = await sessionStore.getUserSessionResolved(resolved.user.id, req.params.sessionId);
451
  if (!session) return res.status(404).json({ error: 'db:chat_not_found' });
452
+ res.json({ item: session });
453
  } catch (err) {
454
  console.error('db chat get error', err);
455
  res.status(500).json({ error: 'db:chat_get_failed' });
 
473
  patch
474
  );
475
  if (!updated) return res.status(404).json({ error: 'db:chat_not_found' });
476
+ res.json({ item: updated });
477
  } catch (err) {
478
  console.error('db chat patch error', err);
479
  res.status(500).json({ error: 'db:chat_update_failed' });
 
726
  const chats = [];
727
  for (const listedSession of listed) {
728
  const full = await sessionStore.getUserSessionResolved(resolved.user.id, listedSession.id);
729
+ if (full) chats.push(full);
730
  }
731
 
732
  const mediaResult = await mediaStore.listAll(resolved.owner, { view: 'all' });
 
988
  }
989
  });
990
 
991
+ const pendingTurnstileTokens = new Map(); // token -> expiry
992
+
993
  app.post('/api/turnstile', async (req, res) => {
994
  try {
995
  const token = req.body?.token;
server/sessionStore.js CHANGED
@@ -53,9 +53,6 @@ function ensureSessionShape(raw, fallbackId = null) {
53
  created,
54
  history: Array.isArray(raw?.history) ? raw.history : [],
55
  model: raw?.model || null,
56
- updatedAt: typeof raw?.updatedAt === 'string' && raw.updatedAt.trim()
57
- ? raw.updatedAt
58
- : nowIso(),
59
  };
60
  }
61
 
@@ -180,7 +177,6 @@ function sessionForList(meta, loaded) {
180
  created: Number.isFinite(source.created) ? source.created : Date.now(),
181
  history: loaded?.history || [],
182
  model: source.model || null,
183
- updatedAt: source.updatedAt || null,
184
  };
185
  }
186
 
 
53
  created,
54
  history: Array.isArray(raw?.history) ? raw.history : [],
55
  model: raw?.model || null,
 
 
 
56
  };
57
  }
58
 
 
177
  created: Number.isFinite(source.created) ? source.created : Date.now(),
178
  history: loaded?.history || [],
179
  model: source.model || null,
 
180
  };
181
  }
182
 
server/turnstileState.js DELETED
@@ -1 +0,0 @@
1
- export const pendingTurnstileTokens = new Map();
 
 
server/wsHandler.js CHANGED
@@ -17,7 +17,7 @@ import { systemPromptStore } from './systemPromptStore.js';
17
  import { getWebSearchUsage } from './webSearchUsageStore.js';
18
  import crypto from 'crypto';
19
  import path from 'path';
20
- import { pendingTurnstileTokens } from './turnstileState.js';
21
 
22
  /**
23
  * Message Structure: Tree-based with versioned tails
@@ -48,7 +48,6 @@ import { pendingTurnstileTokens } from './turnstileState.js';
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,13 +454,7 @@ const handlers = {
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,15 +525,7 @@ const handlers = {
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,14 +560,7 @@ const handlers = {
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,13 +709,7 @@ const handlers = {
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,22 +853,7 @@ const handlers = {
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,10 +1093,6 @@ function cloneVersionMetaValue(value) {
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,23 +1143,16 @@ function appendConversationTurn(rootMessage, userEntry, assistantEntry, mediaEnt
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,11 +1171,7 @@ function extractFlatHistory(rootMessage) {
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);
 
17
  import { getWebSearchUsage } from './webSearchUsageStore.js';
18
  import crypto from 'crypto';
19
  import path from 'path';
20
+ import { pendingTurnstileTokens } from './index.js';
21
 
22
  /**
23
  * Message Structure: Tree-based with versioned tails
 
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
  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, { type: aborted ? 'chat:aborted' : 'chat:done', sessionId, name: newName, history: extractFlatHistory(newRootMessage) });
 
 
 
 
 
 
458
  },
459
  onError(err) {
460
  activeStreams.delete(ws);
 
525
  return safeSend(ws, { type: 'error', message: 'Failed to apply edit - message lost' });
526
  }
527
 
528
+ safeSend(ws, { type: 'chat:messageEdited', sessionId, messageId: targetMsg.id, messageIndex, message: updatedTargetMsg, history: updatedFlatHistory });
 
 
 
 
 
 
 
 
529
  },
530
 
531
  'chat:selectVersion': async (ws, msg, client) => {
 
560
  }
561
 
562
  // Send back with messageId for clarity
563
+ safeSend(ws, { type: 'chat:versionSelected', sessionId, messageId: targetMsg.id, messageIndex, history: extractFlatHistory(newRoot) });
 
 
 
 
 
 
 
564
  },
565
 
566
  'chat:assistantAction': async (ws, msg, client) => {
 
709
  sessionStore.updateTempSession(client.tempId, sessionId, { history: newHistory, name: newName });
710
  }
711
 
712
+ safeSend(ws, { type: 'chat:done', sessionId, name: newName, history: extractFlatHistory(newRoot) });
 
 
 
 
 
 
713
  },
714
  onError(err) {
715
  activeStreams.delete(ws);
 
853
  },
854
  };
855
 
856
+ function ser(s) { return { id: s.id, name: s.name, created: s.created, history: s.history || [], model: s.model }; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
857
 
858
  function getClientOwner(client) {
859
  return client.userId
 
1093
  return JSON.parse(JSON.stringify(value));
1094
  }
1095
 
 
 
 
 
1096
  function syncMessageFromActiveVersion(message) {
1097
  if (!message) return message;
1098
  const currentVersion = getActiveVersion(message);
 
1143
 
1144
  function extractFlatHistory(rootMessage) {
1145
  if (!rootMessage) return [];
1146
+
1147
+ // Helper to ensure message has valid content
1148
+ const ensureValidContent = (msg) => {
1149
+ if (msg.content === undefined || msg.content === null) {
1150
+ msg.content = '';
 
 
 
 
 
 
 
1151
  }
1152
+ return syncMessageFromActiveVersion(msg);
1153
  };
1154
+
1155
+ const history = [ensureValidContent(rootMessage)];
1156
  const currentVerIdx = rootMessage.currentVersionIdx ?? 0;
1157
 
1158
  if (!Array.isArray(rootMessage.versions)) {
 
1171
  const walkTail = (tail) => {
1172
  for (let i = 0; i < tail.length; i++) {
1173
  const msg = tail[i];
1174
+ history.push(ensureValidContent(msg));
 
 
 
 
1175
  const ver = msg.versions?.[msg.currentVersionIdx ?? 0];
1176
  if (ver?.tail && Array.isArray(ver.tail)) {
1177
  walkTail(ver.tail);