File size: 2,041 Bytes
6c62075
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21ad36a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import type { ChatMessage, ChatSession, ModelId } from './contracts';

const MODEL_IDS: readonly ModelId[] = ['bonsai-1.7b', 'bonsai-4b', 'bonsai-8b', 'bonsai-27b'];

export function conversationTitle(messages: ChatMessage[]): string {
  const firstPrompt = messages.find((message) => message.role === 'user' && message.content.trim())?.content.trim();
  return firstPrompt ? firstPrompt.replace(/\s+/g, ' ').slice(0, 80) : 'New chat';
}

export function conversationPreview(messages: ChatMessage[]): string {
  const latest = [...messages].reverse().find((message) => message.content.trim())?.content.trim();
  return latest ? latest.replace(/\s+/g, ' ').slice(0, 140) : 'No messages yet';
}

export function normalizeConversationModelId(value: string): ModelId {
  return MODEL_IDS.includes(value as ModelId) ? value as ModelId : 'bonsai-27b';
}

export function upsertConversation(sessions: ChatSession[], next: ChatSession): ChatSession[] {
  return [next, ...sessions.filter((session) => session.id !== next.id)]
    .sort((left, right) => right.updatedAt - left.updatedAt);
}

export interface MessageRegenerationPlan {
  baseMessages: ChatMessage[];
  userMessage: ChatMessage;
  discardedMessageIds: string[];
}

export function planMessageRegeneration(
  messages: ChatMessage[],
  messageId: string,
): MessageRegenerationPlan | null {
  const targetIndex = messages.findIndex((message) => message.id === messageId);
  if (targetIndex < 0) return null;
  const target = messages[targetIndex];
  if (!target || target.role === 'system') return null;

  let userIndex = target.role === 'user' ? targetIndex : -1;
  for (let index = targetIndex - 1; userIndex < 0 && index >= 0; index -= 1) {
    if (messages[index]?.role === 'user') userIndex = index;
  }
  const userMessage = messages[userIndex];
  if (!userMessage || !userMessage.content.trim()) return null;

  return {
    baseMessages: messages.slice(0, userIndex),
    userMessage,
    discardedMessageIds: messages.slice(userIndex + 1).map((message) => message.id),
  };
}