@gendive/chatllm 0.9.0 → 0.10.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.
@@ -65,6 +65,16 @@ interface MarkdownRendererProps {
65
65
  className?: string;
66
66
  /** 선택지 클릭 핸들러 */
67
67
  onChoiceClick?: (choice: ChoiceOption) => void;
68
+ /**
69
+ * @description Thinking 블록 표시 여부
70
+ * @Todo vibecode - AI 추론 과정 표시 (기본: true)
71
+ */
72
+ showThinking?: boolean;
73
+ /**
74
+ * @description Thinking 블록 기본 펼침 상태
75
+ * @Todo vibecode - true면 펼쳐진 상태로 표시 (기본: false)
76
+ */
77
+ thinkingDefaultOpen?: boolean;
68
78
  }
69
79
  declare const MarkdownRenderer: React$1.FC<MarkdownRendererProps>;
70
80
 
@@ -314,6 +324,16 @@ interface ChatUIProps {
314
324
  role: 'USER' | 'ASSISTANT';
315
325
  message: string;
316
326
  }[]) => Promise<void>;
327
+ /**
328
+ * @description Thinking 블록 표시 여부
329
+ * @Todo vibecode - AI 추론 과정 표시 (기본: true)
330
+ */
331
+ showThinking?: boolean;
332
+ /**
333
+ * @description Thinking 블록 기본 펼침 상태
334
+ * @Todo vibecode - true면 펼쳐진 상태로 표시 (기본: false)
335
+ */
336
+ thinkingDefaultOpen?: boolean;
317
337
  }
318
338
  interface SendMessageParams {
319
339
  messages: {
@@ -376,6 +396,16 @@ interface MessageListProps {
376
396
  editingId: string | null;
377
397
  /** 선택지 클릭 핸들러 */
378
398
  onChoiceClick?: (choice: ChoiceOption) => void;
399
+ /**
400
+ * @description Thinking 블록 표시 여부
401
+ * @Todo vibecode - AI 추론 과정 표시 (기본: true)
402
+ */
403
+ showThinking?: boolean;
404
+ /**
405
+ * @description Thinking 블록 기본 펼침 상태
406
+ * @Todo vibecode - true면 펼쳐진 상태로 표시 (기본: false)
407
+ */
408
+ thinkingDefaultOpen?: boolean;
379
409
  }
380
410
  interface MessageBubbleProps {
381
411
  message: ChatMessage;
@@ -393,6 +423,16 @@ interface MessageBubbleProps {
393
423
  models?: ModelConfig[];
394
424
  alternatives?: AlternativeResponse[];
395
425
  onChoiceClick?: (choice: ChoiceOption) => void;
426
+ /**
427
+ * @description Thinking 블록 표시 여부
428
+ * @Todo vibecode - AI 추론 과정 표시 (기본: true)
429
+ */
430
+ showThinking?: boolean;
431
+ /**
432
+ * @description Thinking 블록 기본 펼침 상태
433
+ * @Todo vibecode - true면 펼쳐진 상태로 표시 (기본: false)
434
+ */
435
+ thinkingDefaultOpen?: boolean;
396
436
  }
397
437
  interface InputProps {
398
438
  value: string;
@@ -65,6 +65,16 @@ interface MarkdownRendererProps {
65
65
  className?: string;
66
66
  /** 선택지 클릭 핸들러 */
67
67
  onChoiceClick?: (choice: ChoiceOption) => void;
68
+ /**
69
+ * @description Thinking 블록 표시 여부
70
+ * @Todo vibecode - AI 추론 과정 표시 (기본: true)
71
+ */
72
+ showThinking?: boolean;
73
+ /**
74
+ * @description Thinking 블록 기본 펼침 상태
75
+ * @Todo vibecode - true면 펼쳐진 상태로 표시 (기본: false)
76
+ */
77
+ thinkingDefaultOpen?: boolean;
68
78
  }
69
79
  declare const MarkdownRenderer: React$1.FC<MarkdownRendererProps>;
70
80
 
@@ -314,6 +324,16 @@ interface ChatUIProps {
314
324
  role: 'USER' | 'ASSISTANT';
315
325
  message: string;
316
326
  }[]) => Promise<void>;
327
+ /**
328
+ * @description Thinking 블록 표시 여부
329
+ * @Todo vibecode - AI 추론 과정 표시 (기본: true)
330
+ */
331
+ showThinking?: boolean;
332
+ /**
333
+ * @description Thinking 블록 기본 펼침 상태
334
+ * @Todo vibecode - true면 펼쳐진 상태로 표시 (기본: false)
335
+ */
336
+ thinkingDefaultOpen?: boolean;
317
337
  }
318
338
  interface SendMessageParams {
319
339
  messages: {
@@ -376,6 +396,16 @@ interface MessageListProps {
376
396
  editingId: string | null;
377
397
  /** 선택지 클릭 핸들러 */
378
398
  onChoiceClick?: (choice: ChoiceOption) => void;
399
+ /**
400
+ * @description Thinking 블록 표시 여부
401
+ * @Todo vibecode - AI 추론 과정 표시 (기본: true)
402
+ */
403
+ showThinking?: boolean;
404
+ /**
405
+ * @description Thinking 블록 기본 펼침 상태
406
+ * @Todo vibecode - true면 펼쳐진 상태로 표시 (기본: false)
407
+ */
408
+ thinkingDefaultOpen?: boolean;
379
409
  }
380
410
  interface MessageBubbleProps {
381
411
  message: ChatMessage;
@@ -393,6 +423,16 @@ interface MessageBubbleProps {
393
423
  models?: ModelConfig[];
394
424
  alternatives?: AlternativeResponse[];
395
425
  onChoiceClick?: (choice: ChoiceOption) => void;
426
+ /**
427
+ * @description Thinking 블록 표시 여부
428
+ * @Todo vibecode - AI 추론 과정 표시 (기본: true)
429
+ */
430
+ showThinking?: boolean;
431
+ /**
432
+ * @description Thinking 블록 기본 펼침 상태
433
+ * @Todo vibecode - true면 펼쳐진 상태로 표시 (기본: false)
434
+ */
435
+ thinkingDefaultOpen?: boolean;
396
436
  }
397
437
  interface InputProps {
398
438
  value: string;
@@ -2697,6 +2697,9 @@ var SOURCE_LINKS_REGEX = /(\*{0,2}출처:?\*{0,2}\s*)?((?:(?<!!)\[`?[^\]]+`?\]\(
2697
2697
  var INLINE_CHOICE_PATTERN = /\[(\d+)\]\s*([^\[\n]+?)(?=\s*\[\d+\]|$)/g;
2698
2698
  var INLINE_CHOICE_LINE_PATTERN = /^(.+?)?\s*(\[\d+\][^\[]+(?:\[\d+\][^\[]+)+)$/;
2699
2699
  var CODE_BLOCK_REGEX = /```(\w*)\n?([\s\S]*?)```/g;
2700
+ var THINKING_TAG_REGEX = /<thinking>([\s\S]*?)<\/thinking>/gi;
2701
+ var THINKING_CODEBLOCK_REGEX = /```thinking\n?([\s\S]*?)```/gi;
2702
+ var THINKING_TEXT_REGEX = /^Thinking:\s*\n([\s\S]*?)(?=\n\n|$)/gim;
2700
2703
  var INLINE_CODE_REGEX = /`([^`]+)`/g;
2701
2704
  var BOLD_REGEX = /\*\*([^*]+)\*\*/g;
2702
2705
  var ITALIC_REGEX = /(?<!\*)\*([^*]+)\*(?!\*)/g;
@@ -2874,6 +2877,80 @@ var MarkdownTable = ({ data }) => {
2874
2877
  }
2875
2878
  );
2876
2879
  };
2880
+ var ThinkingBlock = ({ content, defaultOpen = false }) => {
2881
+ const [isOpen, setIsOpen] = import_react8.default.useState(defaultOpen);
2882
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2883
+ "details",
2884
+ {
2885
+ open: isOpen,
2886
+ className: "chatllm-thinking",
2887
+ style: {
2888
+ margin: "12px 0",
2889
+ borderRadius: "8px",
2890
+ border: "1px solid var(--chatllm-border, #e5e7eb)",
2891
+ background: "var(--chatllm-bg-secondary, #f9fafb)",
2892
+ overflow: "hidden"
2893
+ },
2894
+ children: [
2895
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2896
+ "summary",
2897
+ {
2898
+ onClick: (e) => {
2899
+ e.preventDefault();
2900
+ setIsOpen(!isOpen);
2901
+ },
2902
+ style: {
2903
+ padding: "10px 14px",
2904
+ cursor: "pointer",
2905
+ fontSize: "13px",
2906
+ color: "var(--chatllm-text-secondary, #6b7280)",
2907
+ userSelect: "none",
2908
+ listStyle: "none",
2909
+ display: "flex",
2910
+ alignItems: "center",
2911
+ gap: "6px"
2912
+ },
2913
+ children: [
2914
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { fontSize: "14px" }, children: "\u{1F4AD}" }),
2915
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
2916
+ "Thinking",
2917
+ isOpen ? "" : "..."
2918
+ ] }),
2919
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2920
+ "span",
2921
+ {
2922
+ style: {
2923
+ marginLeft: "auto",
2924
+ fontSize: "10px",
2925
+ transition: "transform 0.2s",
2926
+ transform: isOpen ? "rotate(180deg)" : "rotate(0deg)"
2927
+ },
2928
+ children: "\u25BC"
2929
+ }
2930
+ )
2931
+ ]
2932
+ }
2933
+ ),
2934
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2935
+ "div",
2936
+ {
2937
+ className: "chatllm-thinking-content",
2938
+ style: {
2939
+ padding: "12px 14px",
2940
+ borderTop: "1px solid var(--chatllm-border, #e5e7eb)",
2941
+ fontSize: "13px",
2942
+ color: "var(--chatllm-text-secondary, #6b7280)",
2943
+ whiteSpace: "pre-wrap",
2944
+ lineHeight: "1.6",
2945
+ background: "var(--chatllm-bg, #ffffff)"
2946
+ },
2947
+ children: content.trim()
2948
+ }
2949
+ )
2950
+ ]
2951
+ }
2952
+ );
2953
+ };
2877
2954
  var CodeBlock = ({ language, code }) => {
2878
2955
  const [copied, setCopied] = import_react8.default.useState(false);
2879
2956
  const handleCopy = async () => {
@@ -3298,10 +3375,35 @@ var SourceLinksSection = ({ links, label }) => {
3298
3375
  }
3299
3376
  );
3300
3377
  };
3301
- var MarkdownRenderer = ({ content, className, onChoiceClick }) => {
3378
+ var MarkdownRenderer = ({
3379
+ content,
3380
+ className,
3381
+ onChoiceClick,
3382
+ showThinking = true,
3383
+ thinkingDefaultOpen = false
3384
+ }) => {
3302
3385
  const rendered = (0, import_react8.useMemo)(() => {
3303
3386
  const elements = [];
3304
3387
  let processedContent = content;
3388
+ const thinkingBlocks = [];
3389
+ if (showThinking) {
3390
+ processedContent = processedContent.replace(THINKING_TAG_REGEX, (_, thinkContent) => {
3391
+ thinkingBlocks.push(thinkContent);
3392
+ return `\xA7THINKING\xA7${thinkingBlocks.length - 1}\xA7/THINKING\xA7`;
3393
+ });
3394
+ processedContent = processedContent.replace(THINKING_CODEBLOCK_REGEX, (_, thinkContent) => {
3395
+ thinkingBlocks.push(thinkContent);
3396
+ return `\xA7THINKING\xA7${thinkingBlocks.length - 1}\xA7/THINKING\xA7`;
3397
+ });
3398
+ processedContent = processedContent.replace(THINKING_TEXT_REGEX, (_, thinkContent) => {
3399
+ thinkingBlocks.push(thinkContent);
3400
+ return `\xA7THINKING\xA7${thinkingBlocks.length - 1}\xA7/THINKING\xA7`;
3401
+ });
3402
+ } else {
3403
+ processedContent = processedContent.replace(THINKING_TAG_REGEX, "");
3404
+ processedContent = processedContent.replace(THINKING_CODEBLOCK_REGEX, "");
3405
+ processedContent = processedContent.replace(THINKING_TEXT_REGEX, "");
3406
+ }
3305
3407
  const codeBlocks = [];
3306
3408
  processedContent = processedContent.replace(CODE_BLOCK_REGEX, (_, lang, code) => {
3307
3409
  codeBlocks.push({ language: lang || "", code });
@@ -3409,6 +3511,23 @@ var MarkdownRenderer = ({ content, className, onChoiceClick }) => {
3409
3511
  }
3410
3512
  };
3411
3513
  lines.forEach((line, lineIndex) => {
3514
+ const thinkingMatch = line.match(/§THINKING§(\d+)§\/THINKING§/);
3515
+ if (thinkingMatch) {
3516
+ flushList();
3517
+ flushBlockquote();
3518
+ const index = parseInt(thinkingMatch[1]);
3519
+ elements.push(
3520
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3521
+ ThinkingBlock,
3522
+ {
3523
+ content: thinkingBlocks[index],
3524
+ defaultOpen: thinkingDefaultOpen
3525
+ },
3526
+ `thinking-${lineIndex}`
3527
+ )
3528
+ );
3529
+ return;
3530
+ }
3412
3531
  const codeBlockMatch = line.match(/§CODEBLOCK§(\d+)§\/CODEBLOCK§/);
3413
3532
  if (codeBlockMatch) {
3414
3533
  flushList();
@@ -3597,7 +3716,9 @@ var MessageBubble = ({
3597
3716
  activeAlternativeIndex = 0,
3598
3717
  onAlternativeChange,
3599
3718
  nextAssistantMessage,
3600
- onChoiceClick
3719
+ onChoiceClick,
3720
+ showThinking = true,
3721
+ thinkingDefaultOpen = false
3601
3722
  }) => {
3602
3723
  const [showActions, setShowActions] = (0, import_react9.useState)(false);
3603
3724
  const [showModelMenu, setShowModelMenu] = (0, import_react9.useState)(false);
@@ -3701,7 +3822,15 @@ var MessageBubble = ({
3701
3822
  children: [
3702
3823
  isAssistant ? (
3703
3824
  // AI 메시지는 마크다운 렌더링
3704
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: displayContent, onChoiceClick })
3825
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3826
+ MarkdownRenderer,
3827
+ {
3828
+ content: displayContent,
3829
+ onChoiceClick,
3830
+ showThinking,
3831
+ thinkingDefaultOpen
3832
+ }
3833
+ )
3705
3834
  ) : (
3706
3835
  // 사용자 메시지는 일반 텍스트
3707
3836
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -3991,7 +4120,9 @@ var MessageList = ({
3991
4120
  models,
3992
4121
  copiedId,
3993
4122
  editingId,
3994
- onChoiceClick
4123
+ onChoiceClick,
4124
+ showThinking = true,
4125
+ thinkingDefaultOpen = false
3995
4126
  }) => {
3996
4127
  const messagesEndRef = (0, import_react10.useRef)(null);
3997
4128
  const containerRef = (0, import_react10.useRef)(null);
@@ -4064,7 +4195,9 @@ var MessageList = ({
4064
4195
  onAlternativeChange: message.role === "user" && assistantForAlts && onSetActiveAlternative ? (idx) => onSetActiveAlternative(assistantForAlts.id, idx) : message.role === "assistant" && onSetActiveAlternative ? (idx) => onSetActiveAlternative(message.id, idx) : void 0,
4065
4196
  models,
4066
4197
  alternatives: message.role === "assistant" ? message.alternatives : assistantForAlts?.alternatives,
4067
- onChoiceClick: message.role === "assistant" ? onChoiceClick : void 0
4198
+ onChoiceClick: message.role === "assistant" ? onChoiceClick : void 0,
4199
+ showThinking,
4200
+ thinkingDefaultOpen
4068
4201
  },
4069
4202
  message.id
4070
4203
  );
@@ -5360,7 +5493,10 @@ var ChatUI = ({
5360
5493
  onLoadSession,
5361
5494
  onDeleteSession,
5362
5495
  onUpdateSessionTitle,
5363
- onSaveMessages
5496
+ onSaveMessages,
5497
+ // Thinking Block Props
5498
+ showThinking = true,
5499
+ thinkingDefaultOpen = false
5364
5500
  }) => {
5365
5501
  import_react13.default.useEffect(() => {
5366
5502
  injectStyles();
@@ -5556,7 +5692,9 @@ var ChatUI = ({
5556
5692
  models: hookModels,
5557
5693
  copiedId: copiedMessageId,
5558
5694
  editingId: editingMessageId,
5559
- onChoiceClick: handleChoiceClick
5695
+ onChoiceClick: handleChoiceClick,
5696
+ showThinking,
5697
+ thinkingDefaultOpen
5560
5698
  }
5561
5699
  ),
5562
5700
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(