@gendive/chatllm 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -59,6 +59,7 @@ var useChatUI = (options) => {
59
59
  ...DEFAULT_PERSONALIZATION,
60
60
  ...initialPersonalization
61
61
  });
62
+ const [activeAlternatives, setActiveAlternatives] = useState({});
62
63
  const abortControllerRef = useRef(null);
63
64
  const currentSession = sessions.find((s) => s.id === currentSessionId) || null;
64
65
  const messages = currentSession?.messages || [];
@@ -658,6 +659,15 @@ ${currentSession.contextSummary}` },
658
659
  onSendMessage,
659
660
  onError
660
661
  ]);
662
+ const setActiveAlternative = useCallback((assistantMessageId, index) => {
663
+ setActiveAlternatives((prev) => ({
664
+ ...prev,
665
+ [assistantMessageId]: index
666
+ }));
667
+ }, []);
668
+ const getActiveAlternative = useCallback((assistantMessageId) => {
669
+ return activeAlternatives[assistantMessageId] ?? 0;
670
+ }, [activeAlternatives]);
661
671
  return {
662
672
  // State
663
673
  sessions,
@@ -674,6 +684,7 @@ ${currentSession.contextSummary}` },
674
684
  copiedMessageId,
675
685
  editingMessageId,
676
686
  personalization,
687
+ activeAlternatives,
677
688
  // Actions
678
689
  setInput,
679
690
  sendMessage,
@@ -693,6 +704,8 @@ ${currentSession.contextSummary}` },
693
704
  saveEdit,
694
705
  regenerate,
695
706
  askOtherModel,
707
+ setActiveAlternative,
708
+ getActiveAlternative,
696
709
  updatePersonalization,
697
710
  models
698
711
  };
@@ -2158,16 +2171,20 @@ var MessageBubble = ({
2158
2171
  models,
2159
2172
  alternatives,
2160
2173
  activeAlternativeIndex = 0,
2161
- onAlternativeChange
2174
+ onAlternativeChange,
2175
+ nextAssistantMessage
2162
2176
  }) => {
2163
2177
  const [showActions, setShowActions] = useState5(false);
2164
2178
  const [showModelMenu, setShowModelMenu] = useState5(false);
2165
2179
  const isUser = message.role === "user";
2166
2180
  const isAssistant = message.role === "assistant";
2167
- const otherModels = models?.filter((m) => m.id !== message.model) || [];
2168
- const displayContent = alternatives && alternatives.length > 0 && activeAlternativeIndex > 0 ? alternatives[activeAlternativeIndex - 1]?.content || message.content : message.content;
2169
- const displayModel = alternatives && alternatives.length > 0 && activeAlternativeIndex > 0 ? alternatives[activeAlternativeIndex - 1]?.model : message.model;
2170
- const displaySources = alternatives && alternatives.length > 0 && activeAlternativeIndex > 0 ? alternatives[activeAlternativeIndex - 1]?.sources : message.sources;
2181
+ const relevantAlternatives = isUser ? alternatives : message.alternatives;
2182
+ const relevantActiveIndex = activeAlternativeIndex;
2183
+ const currentAssistantModel = isUser ? nextAssistantMessage?.model : message.model;
2184
+ const otherModels = models?.filter((m) => m.id !== currentAssistantModel) || [];
2185
+ const displayContent = isAssistant && relevantAlternatives && relevantAlternatives.length > 0 && relevantActiveIndex > 0 ? relevantAlternatives[relevantActiveIndex - 1]?.content || message.content : message.content;
2186
+ const displayModel = isAssistant && relevantAlternatives && relevantAlternatives.length > 0 && relevantActiveIndex > 0 ? relevantAlternatives[relevantActiveIndex - 1]?.model : message.model;
2187
+ const displaySources = isAssistant && relevantAlternatives && relevantAlternatives.length > 0 && relevantActiveIndex > 0 ? relevantAlternatives[relevantActiveIndex - 1]?.sources : message.sources;
2171
2188
  const handleMouseUp = () => {
2172
2189
  if (!onQuote) return;
2173
2190
  const selection = window.getSelection();
@@ -2329,7 +2346,7 @@ var MessageBubble = ({
2329
2346
  ]
2330
2347
  }
2331
2348
  ),
2332
- alternatives && alternatives.length > 0 && /* @__PURE__ */ jsxs6(
2349
+ isUser && relevantAlternatives && relevantAlternatives.length > 0 && /* @__PURE__ */ jsxs6(
2333
2350
  "div",
2334
2351
  {
2335
2352
  style: {
@@ -2344,30 +2361,30 @@ var MessageBubble = ({
2344
2361
  /* @__PURE__ */ jsx7(
2345
2362
  "button",
2346
2363
  {
2347
- onClick: () => onAlternativeChange?.(Math.max(0, activeAlternativeIndex - 1)),
2348
- disabled: activeAlternativeIndex === 0,
2364
+ onClick: () => onAlternativeChange?.(Math.max(0, relevantActiveIndex - 1)),
2365
+ disabled: relevantActiveIndex === 0,
2349
2366
  style: {
2350
2367
  ...navButtonStyle,
2351
- opacity: activeAlternativeIndex === 0 ? 0.5 : 1,
2352
- cursor: activeAlternativeIndex === 0 ? "not-allowed" : "pointer"
2368
+ opacity: relevantActiveIndex === 0 ? 0.5 : 1,
2369
+ cursor: relevantActiveIndex === 0 ? "not-allowed" : "pointer"
2353
2370
  },
2354
2371
  children: /* @__PURE__ */ jsx7(IconSvg, { name: "arrow-left-line", size: 14 })
2355
2372
  }
2356
2373
  ),
2357
2374
  /* @__PURE__ */ jsxs6("span", { style: { fontSize: "12px", color: "var(--chatllm-text-muted, #9ca3af)" }, children: [
2358
- activeAlternativeIndex + 1,
2375
+ relevantActiveIndex + 1,
2359
2376
  " / ",
2360
- alternatives.length + 1
2377
+ relevantAlternatives.length + 1
2361
2378
  ] }),
2362
2379
  /* @__PURE__ */ jsx7(
2363
2380
  "button",
2364
2381
  {
2365
- onClick: () => onAlternativeChange?.(Math.min(alternatives.length, activeAlternativeIndex + 1)),
2366
- disabled: activeAlternativeIndex === alternatives.length,
2382
+ onClick: () => onAlternativeChange?.(Math.min(relevantAlternatives.length, relevantActiveIndex + 1)),
2383
+ disabled: relevantActiveIndex === relevantAlternatives.length,
2367
2384
  style: {
2368
2385
  ...navButtonStyle,
2369
- opacity: activeAlternativeIndex === alternatives.length ? 0.5 : 1,
2370
- cursor: activeAlternativeIndex === alternatives.length ? "not-allowed" : "pointer"
2386
+ opacity: relevantActiveIndex === relevantAlternatives.length ? 0.5 : 1,
2387
+ cursor: relevantActiveIndex === relevantAlternatives.length ? "not-allowed" : "pointer"
2371
2388
  },
2372
2389
  children: /* @__PURE__ */ jsx7(IconSvg, { name: "arrow-right-line", size: 14 })
2373
2390
  }
@@ -2394,7 +2411,7 @@ var MessageBubble = ({
2394
2411
  ) }),
2395
2412
  isUser && /* @__PURE__ */ jsx7("button", { onClick: onEdit, style: actionButtonStyle, title: "\uC218\uC815", children: /* @__PURE__ */ jsx7(IconSvg, { name: "edit-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) }),
2396
2413
  isAssistant && onRegenerate && /* @__PURE__ */ jsx7("button", { onClick: onRegenerate, style: actionButtonStyle, title: "\uB2E4\uC2DC \uC0DD\uC131", children: /* @__PURE__ */ jsx7(IconSvg, { name: "refresh-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) }),
2397
- isAssistant && onAskOtherModel && otherModels.length > 0 && /* @__PURE__ */ jsxs6("div", { style: { position: "relative" }, children: [
2414
+ isUser && onAskOtherModel && otherModels.length > 0 && /* @__PURE__ */ jsxs6("div", { style: { position: "relative" }, children: [
2398
2415
  /* @__PURE__ */ jsxs6(
2399
2416
  "button",
2400
2417
  {
@@ -2544,6 +2561,8 @@ var MessageList = ({
2544
2561
  onRegenerate,
2545
2562
  onQuote,
2546
2563
  onAskOtherModel,
2564
+ onSetActiveAlternative,
2565
+ activeAlternatives = {},
2547
2566
  models,
2548
2567
  copiedId,
2549
2568
  editingId
@@ -2598,23 +2617,31 @@ var MessageList = ({
2598
2617
  },
2599
2618
  onMouseUp: handleMouseUp,
2600
2619
  children: [
2601
- messages.map((message, index) => /* @__PURE__ */ jsx8(
2602
- MessageBubble,
2603
- {
2604
- message,
2605
- isLoading: isLoading && index === messages.length - 1 && message.role === "assistant",
2606
- isCopied: copiedId === message.id,
2607
- isEditing: editingId === message.id,
2608
- onCopy: () => onCopy(message.content, message.id),
2609
- onEdit: () => onEdit(message),
2610
- onRegenerate: message.role === "assistant" ? () => onRegenerate(message.id) : void 0,
2611
- onQuote,
2612
- onAskOtherModel: message.role === "assistant" && onAskOtherModel ? (targetModel) => onAskOtherModel(message.id, targetModel) : void 0,
2613
- models,
2614
- alternatives: message.alternatives
2615
- },
2616
- message.id
2617
- )),
2620
+ messages.map((message, index) => {
2621
+ const nextAssistant = message.role === "user" && index + 1 < messages.length ? messages[index + 1] : null;
2622
+ const assistantForAlts = nextAssistant?.role === "assistant" ? nextAssistant : null;
2623
+ const activeAltIndex = assistantForAlts ? activeAlternatives[assistantForAlts.id] ?? 0 : 0;
2624
+ return /* @__PURE__ */ jsx8(
2625
+ MessageBubble,
2626
+ {
2627
+ message,
2628
+ isLoading: isLoading && index === messages.length - 1 && message.role === "assistant",
2629
+ isCopied: copiedId === message.id,
2630
+ isEditing: editingId === message.id,
2631
+ onCopy: () => onCopy(message.content, message.id),
2632
+ onEdit: () => onEdit(message),
2633
+ onRegenerate: message.role === "assistant" ? () => onRegenerate(message.id) : void 0,
2634
+ onQuote,
2635
+ nextAssistantMessage: assistantForAlts,
2636
+ activeAlternativeIndex: message.role === "user" ? activeAltIndex : activeAlternatives[message.id] ?? 0,
2637
+ onAskOtherModel: message.role === "user" && assistantForAlts && onAskOtherModel ? (targetModel) => onAskOtherModel(message.id, assistantForAlts.id, targetModel) : void 0,
2638
+ onAlternativeChange: message.role === "user" && assistantForAlts && onSetActiveAlternative ? (idx) => onSetActiveAlternative(assistantForAlts.id, idx) : message.role === "assistant" && onSetActiveAlternative ? (idx) => onSetActiveAlternative(message.id, idx) : void 0,
2639
+ models,
2640
+ alternatives: message.role === "assistant" ? message.alternatives : assistantForAlts?.alternatives
2641
+ },
2642
+ message.id
2643
+ );
2644
+ }),
2618
2645
  selectionPosition && /* @__PURE__ */ jsxs7(
2619
2646
  "div",
2620
2647
  {