incognitolm commited on
Commit
12272d1
·
verified ·
1 Parent(s): 14e2e36

Update server/wsHandler.js

Browse files
Files changed (1) hide show
  1. server/wsHandler.js +21 -2
server/wsHandler.js CHANGED
@@ -26,6 +26,8 @@ function bcast(wsClients, userId, data, excludeWs) {
26
  }
27
 
28
  const handlers = {
 
 
29
  'auth:login': async (ws, msg, client, wsClients) => {
30
  const { accessToken, tempId: clientTempId } = msg;
31
  if (!accessToken) return safeSend(ws, { type: 'auth:error', message: 'Missing token' });
@@ -153,7 +155,14 @@ const handlers = {
153
  activeStreams.delete(ws);
154
  const finalText = text || fullText;
155
  const userEntry = buildEntry('user', content);
156
- const asstEntry = buildEntry('assistant', finalText, toolCalls || []);
 
 
 
 
 
 
 
157
  // Assets (images/video/audio) are sent to the client via chat:asset events and
158
  // must NOT be pushed into LLM history — invalid roles cause blank responses.
159
  const newHistory = [...(session.history || []), userEntry, asstEntry];
@@ -238,9 +247,19 @@ const handlers = {
238
  function ser(s) { return { id: s.id, name: s.name, created: s.created, history: s.history || [], model: s.model }; }
239
 
240
  function buildEntry(role, content, toolCalls = []) {
 
 
 
 
 
 
 
 
 
 
241
  return { role, content, timestamp: Date.now(),
242
  versions: [{ content, tail: [], timestamp: Date.now() }], currentVersionIdx: 0,
243
- ...(toolCalls.length ? { toolCalls } : {}) };
244
  }
245
 
246
  async function autoName(prompt, accessToken) {
 
26
  }
27
 
28
  const handlers = {
29
+ 'ping': (ws) => { safeSend(ws, { type: 'pong' }); },
30
+
31
  'auth:login': async (ws, msg, client, wsClients) => {
32
  const { accessToken, tempId: clientTempId } = msg;
33
  if (!accessToken) return safeSend(ws, { type: 'auth:error', message: 'Missing token' });
 
155
  activeStreams.delete(ws);
156
  const finalText = text || fullText;
157
  const userEntry = buildEntry('user', content);
158
+ // Merge: toolCalls from streamChat (OpenAI format) merged with
159
+ // resolved state/result info from toolCallsCollected (flat format)
160
+ const resolvedMap = new Map(toolCallsCollected.map(c => [c.id, c]));
161
+ const mergedCalls = (toolCalls || []).map(c => {
162
+ const resolved = resolvedMap.get(c.id) || {};
163
+ return { ...c, state: resolved.state || 'resolved', result: resolved.result };
164
+ });
165
+ const asstEntry = buildEntry('assistant', finalText, mergedCalls);
166
  // Assets (images/video/audio) are sent to the client via chat:asset events and
167
  // must NOT be pushed into LLM history — invalid roles cause blank responses.
168
  const newHistory = [...(session.history || []), userEntry, asstEntry];
 
247
  function ser(s) { return { id: s.id, name: s.name, created: s.created, history: s.history || [], model: s.model }; }
248
 
249
  function buildEntry(role, content, toolCalls = []) {
250
+ // Normalize tool calls so the UI can always read call.name directly,
251
+ // regardless of whether they arrived in OpenAI format {function:{name,arguments}}
252
+ // or already-flat format {name, args}.
253
+ const normalizedCalls = toolCalls.map(c => ({
254
+ id: c.id,
255
+ name: c.name || c.function?.name,
256
+ args: c.args ?? (c.function?.arguments ? (() => { try { return JSON.parse(c.function.arguments); } catch { return c.function.arguments; } })() : {}),
257
+ state: c.state || 'resolved',
258
+ result: c.result,
259
+ }));
260
  return { role, content, timestamp: Date.now(),
261
  versions: [{ content, tail: [], timestamp: Date.now() }], currentVersionIdx: 0,
262
+ ...(normalizedCalls.length ? { toolCalls: normalizedCalls } : {}) };
263
  }
264
 
265
  async function autoName(prompt, accessToken) {