File size: 3,514 Bytes
d0878a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/**

 * Apply chat-stream advisor events. Display order is first-start order:

 * new cards append; they are never sorted by rank or finish time.

 */

function trailingAdvisorStart(messages) {
  let i = messages.length;
  while (i > 0 && messages[i - 1].type === 'advisor') i -= 1;
  return i;
}

function findTrailingAdvisorIndex(messages, personaId) {
  const start = trailingAdvisorStart(messages);
  for (let i = start; i < messages.length; i += 1) {
    if (messages[i].persona_id === personaId) return i;
  }
  return -1;
}

export function applyAdvisorStreamEvent(messages, payload, { generateId, now } = {}) {
  const type = payload?.type;
  const d = payload?.data || {};
  const idFactory = generateId || (() => `msg-${Date.now()}`);
  const timestamp = now ? now() : new Date();

  if (type === 'advisor_start') {
    if (findTrailingAdvisorIndex(messages, d.persona_id) !== -1) {
      return messages;
    }
    const msg = {
      id: idFactory(),
      type: 'advisor',
      persona_id: d.persona_id,
      content: '',
      timestamp,
      advisorName: d.persona_name || d.persona_id,
      used_documents: false,
      document_chunks_used: 0,
      streaming: true,
    };
    return [...messages, msg];
  }

  if (type === 'advisor_delta') {
    const idx = findTrailingAdvisorIndex(messages, d.persona_id);
    const delta = d.delta || '';
    if (idx === -1) {
      const created = applyAdvisorStreamEvent(
        messages,
        { type: 'advisor_start', data: d },
        { generateId: idFactory, now: () => timestamp },
      );
      return applyAdvisorStreamEvent(
        created,
        payload,
        { generateId: idFactory, now: () => timestamp },
      );
    }
    const next = messages.slice();
    const prev = next[idx];
    next[idx] = {
      ...prev,
      content: `${prev.content || ''}${delta}`,
      streaming: true,
    };
    return next;
  }

  if (type === 'advisor_done') {
    const idx = findTrailingAdvisorIndex(messages, d.persona_id);
    const doneFields = {
      content: d.content ?? '',
      advisorName: d.persona_name || d.persona_id,
      used_documents: d.used_documents || false,
      document_chunks_used: d.document_chunks_used || 0,
      streaming: false,
    };
    if (idx === -1) {
      return [
        ...messages,
        {
          id: idFactory(),
          type: 'advisor',
          persona_id: d.persona_id,
          timestamp,
          ...doneFields,
        },
      ];
    }
    const next = messages.slice();
    next[idx] = { ...next[idx], ...doneFields };
    return next;
  }

  if (type === 'advisor') {
    const idx = findTrailingAdvisorIndex(messages, d.persona_id);
    const msg = {
      id: idx === -1 ? idFactory() : messages[idx].id,
      type: 'advisor',
      persona_id: d.persona_id,
      content: d.content,
      timestamp: idx === -1 ? timestamp : messages[idx].timestamp,
      advisorName: d.persona_name || d.persona_id,
      used_documents: d.used_documents || false,
      document_chunks_used: d.document_chunks_used || 0,
      streaming: false,
    };
    if (idx === -1) return [...messages, msg];
    const next = messages.slice();
    next[idx] = { ...messages[idx], ...msg };
    return next;
  }

  return messages;
}

export function advisorDisplayOrder(messages) {
  return messages
    .filter((m) => m.type === 'advisor')
    .map((m) => m.persona_id);
}