@gendive/chatllm 0.17.20 → 0.17.21

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react/ChatUI.tsx","../../src/react/hooks/useChatUI.ts","../../src/types.ts","../../src/react/hooks/useGlobalMemory.ts","../../src/react/adapters/LocalStorageAdapter.ts","../../src/react/adapters/PostgreSQLAdapter.ts","../../src/react/hooks/useInfoExtraction.ts","../../src/react/hooks/useSkills.ts","../../src/react/utils/skillParser.ts","../../src/react/utils/deepResearchAdapter.ts","../../src/react/hooks/useProject.ts","../../src/react/utils/projectMigration.ts","../../src/react/utils/pollParser.ts","../../src/react/utils/toolAdapter.ts","../../src/react/utils/sessionCache.ts","../../src/react/components/ChatSidebar.tsx","../../src/react/components/Icon.tsx","../../src/react/components/ProjectSelector.tsx","../../src/react/components/ChatHeader.tsx","../../src/react/components/ChatInput.tsx","../../src/react/components/MessageList.tsx","../../src/react/components/MessageBubble.tsx","../../src/react/components/MarkdownRenderer.tsx","../../src/react/components/LinkChip.tsx","../../src/react/components/DeepResearchProgressUI.tsx","../../src/react/components/PollCard.tsx","../../src/react/components/SkillProgressUI.tsx","../../src/react/components/ImageContentCard.tsx","../../src/react/components/FileContentCard.tsx","../../src/react/components/ToolStatusCard.tsx","../../src/react/components/ContentPartRenderer.tsx","../../src/react/components/EmptyState.tsx","../../src/react/components/SettingsModal.tsx","../../src/react/components/ProjectSettingsModal.tsx","../../src/react/components/DisclaimerModal.tsx","../../src/react/hooks/useDeepResearch.ts","../../src/react/components/MemoryPanel.tsx"],"sourcesContent":["/**\n * @description ChatUI 메인 컴포넌트\n * 풀 기능 채팅 UI\n */\n\nimport React from 'react';\nimport { useChatUI, UseChatUIOptions } from './hooks/useChatUI';\nimport { ChatSidebar } from './components/ChatSidebar';\nimport { ChatHeader } from './components/ChatHeader';\nimport { ChatInput } from './components/ChatInput';\nimport { MessageList } from './components/MessageList';\nimport { EmptyState } from './components/EmptyState';\nimport { SettingsModal } from './components/SettingsModal';\nimport { ProjectSettingsModal } from './components/ProjectSettingsModal';\nimport { DisclaimerModal } from './components/DisclaimerModal';\nimport type { ChatUIProps, ActionItem, PromptTemplate, ModelConfig, UseChatUIReturn } from './types';\nimport type { MemoryItem } from './components/MemoryPanel';\n\n// ============================================================================\n// Default Actions\n// ============================================================================\n\nconst DEFAULT_ACTIONS: ActionItem[] = [];\n\n// ============================================================================\n// Default Templates\n// ============================================================================\n\nconst DEFAULT_TEMPLATES: PromptTemplate[] = [];\n\n// ============================================================================\n// Default Models\n// ============================================================================\n\n/**\n * @description 기본 모델 목록\n * @Todo vibecode\n */\nconst DEFAULT_MODELS: ModelConfig[] = [\n { id: 'gpt-4o', name: 'GPT-4o', provider: 'openai' },\n { id: 'gpt-4o-mini', name: 'GPT-4o Mini', provider: 'openai' },\n { id: 'claude-3-5-sonnet', name: 'Claude 3.5 Sonnet', provider: 'anthropic' },\n];\n\n// ============================================================================\n// CSS Styles (injected)\n// ============================================================================\n\n/**\n * @description Modern Canvas 디자인 시스템 스타일 주입\n * @Todo vibecode - 새로운 디자인 시스템 적용 (v0.11.0)\n */\nconst injectStyles = () => {\n if (typeof document === 'undefined') return;\n\n const styleId = 'chatllm-styles';\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = `\n @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');\n\n @keyframes chatllm-typing {\n 0%, 80%, 100% {\n transform: scale(0);\n opacity: 0.5;\n }\n 40% {\n transform: scale(1);\n opacity: 1;\n }\n }\n\n @keyframes chatllm-bounce {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-4px); }\n }\n\n @keyframes chatllm-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n\n @keyframes chatllm-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n\n .chatllm-root {\n --chatllm-primary: #4A90E2;\n --chatllm-primary-hover: #357ABD;\n --chatllm-primary-light: rgba(74, 144, 226, 0.1);\n --chatllm-bg: #F5F5F5;\n --chatllm-bg-secondary: #F5F5F5;\n --chatllm-bg-tertiary: #EDEDED;\n --chatllm-bg-hover: rgba(255, 255, 255, 0.4);\n --chatllm-bg-active: rgba(255, 255, 255, 0.6);\n --chatllm-bg-disabled: #E5E7EB;\n --chatllm-sidebar-bg: #F5F5F5;\n --chatllm-content-bg: #FFFFFF;\n --chatllm-input-bg: #FFFFFF;\n --chatllm-user-bubble: #EDEDED;\n --chatllm-text: #1e293b;\n --chatllm-text-secondary: #475569;\n --chatllm-text-muted: #94a3b8;\n --chatllm-border: #e2e8f0;\n --chatllm-border-light: rgba(226, 232, 240, 0.5);\n --chatllm-error: #ef4444;\n --chatllm-success: #22c55e;\n --chatllm-radius: 1rem;\n --chatllm-radius-lg: 1.5rem;\n --chatllm-shadow-sheet: 0 4px 20px -2px rgba(0, 0, 0, 0.05), 0 2px 6px -2px rgba(0, 0, 0, 0.03);\n --chatllm-shadow-input: 0 10px 40px -10px rgba(0, 0, 0, 0.1);\n }\n\n .chatllm-root.chatllm-dark {\n --chatllm-primary: #60a5fa;\n --chatllm-primary-hover: #3b82f6;\n --chatllm-primary-light: rgba(96, 165, 250, 0.15);\n --chatllm-bg: #0f172a;\n --chatllm-bg-secondary: #1e293b;\n --chatllm-bg-tertiary: #334155;\n --chatllm-bg-hover: rgba(51, 65, 85, 0.5);\n --chatllm-bg-active: rgba(51, 65, 85, 0.8);\n --chatllm-sidebar-bg: #0f172a;\n --chatllm-content-bg: #1e293b;\n --chatllm-input-bg: #1e293b;\n --chatllm-user-bubble: #334155;\n --chatllm-text: #f1f5f9;\n --chatllm-text-secondary: #cbd5e1;\n --chatllm-text-muted: #64748b;\n --chatllm-border: #334155;\n --chatllm-border-light: rgba(51, 65, 85, 0.5);\n }\n\n .chatllm-root {\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n .chatllm-root * {\n box-sizing: border-box;\n }\n\n .chatllm-root textarea::placeholder {\n color: var(--chatllm-text-muted);\n }\n\n .chatllm-root button:focus-visible {\n outline: 2px solid var(--chatllm-primary);\n outline-offset: 2px;\n }\n\n .chatllm-scrollbar::-webkit-scrollbar {\n width: 5px;\n }\n\n .chatllm-scrollbar::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .chatllm-scrollbar::-webkit-scrollbar-thumb {\n background: #E0E0E0;\n border-radius: 10px;\n }\n\n .chatllm-sheet {\n background: var(--chatllm-content-bg);\n border-radius: var(--chatllm-radius-lg);\n box-shadow: var(--chatllm-shadow-sheet);\n border: 1px solid var(--chatllm-border);\n }\n\n .chatllm-input-container {\n background: var(--chatllm-input-bg);\n border-radius: var(--chatllm-radius-lg);\n box-shadow: var(--chatllm-shadow-input);\n border: 1px solid var(--chatllm-border);\n transition: all 0.3s ease;\n }\n\n .chatllm-input-container:focus-within {\n border-color: rgba(74, 144, 226, 0.3);\n box-shadow: var(--chatllm-shadow-input), 0 0 0 4px rgba(74, 144, 226, 0.05);\n }\n\n .chatllm-dot-bounce {\n animation: chatllm-bounce 0.6s infinite ease-in-out;\n }\n\n .chatllm-dot-bounce:nth-child(2) {\n animation-delay: 0.1s;\n }\n\n .chatllm-dot-bounce:nth-child(3) {\n animation-delay: 0.2s;\n }\n\n .chatllm-skeleton-pulse {\n animation: chatllm-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n }\n\n .chatllm-sidebar-transition {\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .chatllm-table {\n width: 100%;\n border-collapse: collapse;\n margin: 12px 0;\n }\n\n .chatllm-table th,\n .chatllm-table td {\n border: 1px solid var(--chatllm-border);\n padding: 10px 12px;\n }\n\n .chatllm-table th {\n background-color: var(--chatllm-bg-tertiary);\n font-weight: 600;\n }\n\n .chatllm-table tr:hover {\n background-color: var(--chatllm-bg-hover);\n }\n\n .chatllm-image {\n max-width: 100%;\n border-radius: var(--chatllm-radius);\n margin: 8px 0;\n display: block;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n\n .chatllm-image:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n\n .chatllm-btn-primary {\n background: var(--chatllm-primary);\n color: white;\n border: none;\n border-radius: var(--chatllm-radius);\n font-weight: 600;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px rgba(74, 144, 226, 0.25);\n }\n\n .chatllm-btn-primary:hover {\n background: var(--chatllm-primary-hover);\n }\n\n .chatllm-btn-primary:active {\n transform: scale(0.98);\n }\n\n .chatllm-btn-secondary {\n background: var(--chatllm-content-bg);\n color: var(--chatllm-text-secondary);\n border: 1px solid var(--chatllm-border);\n border-radius: 9999px;\n font-weight: 500;\n transition: all 0.2s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n }\n\n .chatllm-btn-secondary:hover {\n background: var(--chatllm-bg-hover);\n border-color: rgba(74, 144, 226, 0.3);\n }\n `;\n\n document.head.appendChild(style);\n};\n\n// ============================================================================\n// ChatUIView - 순수 렌더링 컴포넌트\n// ============================================================================\n\n/**\n * @description 상태를 외부에서 주입받아 렌더링하는 순수 뷰 컴포넌트\n * @Todo vibecode - chatState prop 지원을 위해 렌더링 로직 분리\n */\ninterface ChatUIViewProps {\n state: UseChatUIReturn;\n models: ModelConfig[];\n actions: ActionItem[];\n templates: PromptTemplate[];\n showSidebar: boolean;\n sidebarWidth?: number | string;\n /** @Todo vibecode - 사이드바 커스텀 슬롯 */\n sidebarRenderAfterHeader?: () => React.ReactNode;\n sidebarRenderFooter?: () => React.ReactNode;\n showSettings: boolean;\n showMemoryTab: boolean;\n showModelSelector: boolean;\n showThinking: boolean;\n thinkingDefaultOpen: boolean;\n theme?: ChatUIProps['theme'];\n className: string;\n apiKey?: string;\n onApiKeyChange?: (key: string) => void;\n deepResearchEnabled: boolean;\n}\n\nconst ChatUIView: React.FC<ChatUIViewProps> = ({\n state,\n models,\n actions,\n templates,\n showSidebar,\n sidebarWidth,\n sidebarRenderAfterHeader,\n sidebarRenderFooter,\n showSettings,\n showMemoryTab,\n showModelSelector,\n showThinking,\n thinkingDefaultOpen,\n theme,\n className,\n apiKey,\n onApiKeyChange,\n deepResearchEnabled,\n}) => {\n const {\n sessions,\n currentSession,\n currentSessionId,\n messages,\n input,\n isLoading,\n selectedModel,\n sidebarOpen,\n settingsOpen,\n quotedText,\n selectedAction,\n copiedMessageId,\n editingMessageId,\n personalization: currentPersonalization,\n setInput,\n sendMessage,\n stopGeneration,\n newSession,\n selectSession,\n deleteSession,\n renameSession,\n setModel,\n toggleSidebar,\n openSettings,\n closeSettings,\n setQuotedText,\n setSelectedAction,\n copyMessage,\n startEdit,\n regenerate,\n askOtherModel,\n setActiveAlternative,\n activeAlternatives,\n loadingAlternativeFor,\n updatePersonalization,\n savePersonalization,\n models: hookModels,\n isDeepResearchMode,\n toggleDeepResearchMode,\n handlePollSubmit,\n globalMemory,\n compressionState,\n manualSkills,\n activeSkillExecution,\n executeManualSkill,\n attachments,\n addAttachments,\n removeAttachment,\n // Project\n projects,\n currentProjectId,\n currentProject,\n createProject,\n selectProject,\n updateProject,\n deleteProject,\n addProjectFile,\n deleteProjectFile,\n projectSettingsOpen,\n openProjectSettings,\n closeProjectSettings,\n projectMemory,\n isSessionsLoading,\n } = state;\n\n /** @Todo vibecode - AI 면책조항 모달 상태 */\n const [disclaimerOpen, setDisclaimerOpen] = React.useState(false);\n\n const greeting = currentPersonalization.userProfile.nickname\n ? `안녕하세요, ${currentPersonalization.userProfile.nickname}님`\n : '안녕하세요';\n\n const handleTemplateClick = (template: PromptTemplate) => {\n setInput(template.prompt);\n };\n\n const handleActionSelect = (action: ActionItem) => {\n setSelectedAction(action);\n };\n\n const handleSubmit = () => {\n sendMessage();\n };\n\n const handleChoiceClick = (choice: { number: number; text: string; fullText: string }) => {\n setInput(choice.text);\n };\n\n /**\n * @description globalMemory entries → MemoryItem[] 변환\n * @Todo vibecode - 설정 모달 메모리 탭용\n */\n const memoryItems: MemoryItem[] = React.useMemo(() => {\n if (!globalMemory?.state.entries) return [];\n const items: MemoryItem[] = [];\n for (const [key, entry] of globalMemory.state.entries) {\n items.push({\n id: key,\n key,\n value: typeof entry.value === 'object' ? JSON.stringify(entry.value, null, 2) : String(entry.value),\n category: entry.category as MemoryItem['category'],\n timestamp: entry.updatedAt || entry.createdAt || Date.now(),\n });\n }\n return items;\n }, [globalMemory?.state.entries]);\n\n /**\n * @description projectMemory entries → MemoryItem[] 변환\n * @Todo vibecode - 설정 모달 프로젝트 메모리 탭용\n */\n const projectMemoryItems: MemoryItem[] = React.useMemo(() => {\n if (!projectMemory?.state.entries) return [];\n const items: MemoryItem[] = [];\n for (const [key, entry] of projectMemory.state.entries) {\n items.push({\n id: key,\n key,\n value: typeof entry.value === 'object' ? JSON.stringify(entry.value, null, 2) : String(entry.value),\n category: entry.category as MemoryItem['category'],\n timestamp: entry.updatedAt || entry.createdAt || Date.now(),\n });\n }\n return items;\n }, [projectMemory?.state.entries]);\n\n const themeClass = theme?.mode === 'dark' ? 'chatllm-dark' : '';\n\n return (\n <div\n className={`chatllm-root ${themeClass} ${className}`}\n style={{\n display: 'flex',\n height: '100%',\n width: '100%',\n backgroundColor: 'var(--chatllm-bg, #F5F5F5)',\n overflow: 'hidden',\n position: 'relative',\n }}\n >\n {/* Sidebar */}\n {showSidebar && (\n <ChatSidebar\n sessions={sessions}\n currentSessionId={currentSessionId}\n onSelectSession={selectSession}\n onNewSession={newSession}\n onDeleteSession={deleteSession}\n onRenameSession={renameSession}\n isOpen={sidebarOpen}\n onToggle={toggleSidebar}\n width={sidebarWidth}\n theme={theme?.mode}\n projects={projects.length > 0 ? projects : undefined}\n currentProjectId={currentProjectId}\n onSelectProject={projects.length > 0 ? selectProject : undefined}\n onNewProject={projects.length > 0 ? () => {\n if (typeof window === 'undefined') return;\n const title = window.prompt('프로젝트 이름을 입력하세요');\n if (title?.trim()) {\n createProject({ title: title.trim() });\n }\n } : undefined}\n onProjectSettings={projects.length > 0 ? (id: string) => {\n selectProject(id);\n openProjectSettings();\n } : undefined}\n renderAfterHeader={sidebarRenderAfterHeader}\n renderFooter={sidebarRenderFooter}\n isLoading={isSessionsLoading}\n />\n )}\n\n {/* Main Content */}\n <main\n style={{\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n position: 'relative',\n overflow: 'hidden',\n minWidth: 0,\n }}\n >\n {/* Header */}\n <ChatHeader\n title={currentSession?.title || '새 대화'}\n model={selectedModel}\n models={models}\n onModelChange={setModel}\n onSettingsOpen={openSettings}\n onSidebarToggle={toggleSidebar}\n sidebarOpen={sidebarOpen}\n showModelSelector={showModelSelector}\n showSettings={showSettings}\n />\n\n {/* Messages or Empty State */}\n {messages.length === 0 ? (\n <EmptyState\n greeting={greeting}\n templates={templates}\n onTemplateClick={handleTemplateClick}\n actions={actions}\n onActionSelect={handleActionSelect}\n />\n ) : (\n <MessageList\n messages={messages}\n isLoading={isLoading}\n onCopy={copyMessage}\n onEdit={startEdit}\n onRegenerate={regenerate}\n onQuote={setQuotedText}\n onAskOtherModel={(userMessageId, assistantMessageId, targetModel) =>\n askOtherModel(assistantMessageId, targetModel)\n }\n onSetActiveAlternative={setActiveAlternative}\n activeAlternatives={activeAlternatives}\n models={hookModels}\n copiedId={copiedMessageId}\n editingId={editingMessageId}\n onChoiceClick={handleChoiceClick}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n loadingAlternativeFor={loadingAlternativeFor}\n onPollSubmit={handlePollSubmit}\n />\n )}\n\n {/* Input */}\n <ChatInput\n value={input}\n onChange={setInput}\n onSubmit={handleSubmit}\n onStop={stopGeneration}\n isLoading={isLoading}\n placeholder=\"메시지를 입력하세요...\"\n quotedText={quotedText}\n onClearQuote={() => setQuotedText(null)}\n selectedAction={selectedAction}\n onClearAction={() => setSelectedAction(null)}\n onActionSelect={setSelectedAction}\n actions={actions}\n onDeepResearch={toggleDeepResearchMode}\n isDeepResearchMode={isDeepResearchMode}\n deepResearchEnabled={deepResearchEnabled}\n manualSkills={manualSkills}\n onSkillSelect={executeManualSkill}\n activeSkillExecution={activeSkillExecution}\n attachments={attachments}\n onFileAttach={addAttachments}\n onRemoveAttachment={removeAttachment}\n onDisclaimerClick={() => setDisclaimerOpen(true)}\n />\n\n </main>\n\n {/* Settings Modal */}\n {showSettings && (\n <SettingsModal\n isOpen={settingsOpen}\n onClose={closeSettings}\n personalization={currentPersonalization}\n onPersonalizationChange={updatePersonalization}\n apiKey={apiKey}\n onApiKeyChange={onApiKeyChange}\n onClearAllData={() => {\n sessions.forEach((s) => deleteSession(s.id));\n }}\n apiKeyLabel=\"API Key\"\n apiKeyDescription=\"Cloud 모델 사용에 필요합니다\"\n memoryItems={memoryItems}\n contextSummary={compressionState?.contextSummary}\n onDeleteMemory={globalMemory ? (key) => globalMemory.remove(key) : undefined}\n onClearMemory={globalMemory ? () => globalMemory.clear() : undefined}\n onSave={savePersonalization}\n showMemoryTab={showMemoryTab}\n enableProjects={projects.length > 0}\n projectMemoryItems={projectMemoryItems}\n onDeleteProjectMemory={projectMemory ? (key) => projectMemory.remove(key) : undefined}\n onClearProjectMemory={projectMemory ? () => projectMemory.clear() : undefined}\n currentProjectTitle={currentProject?.title}\n />\n )}\n\n {/* Project Settings Modal */}\n <ProjectSettingsModal\n isOpen={projectSettingsOpen}\n project={currentProject}\n onClose={closeProjectSettings}\n onUpdateProject={updateProject}\n onAddFile={addProjectFile}\n onDeleteFile={deleteProjectFile}\n onDeleteProject={deleteProject}\n />\n\n {/* AI Disclaimer Modal */}\n <DisclaimerModal isOpen={disclaimerOpen} onClose={() => setDisclaimerOpen(false)} />\n </div>\n );\n};\n\n// ============================================================================\n// ChatUIWithHook - 내부 Hook 호출 래퍼\n// ============================================================================\n\n/**\n * @description chatState 미제공 시 내부에서 useChatUI를 호출하는 래퍼\n * @Todo vibecode - React hooks 조건부 호출 불가 → 컴포넌트 경계에서 분기\n */\nconst ChatUIWithHook: React.FC<ChatUIProps> = ({\n models = DEFAULT_MODELS,\n actions = DEFAULT_ACTIONS,\n templates = DEFAULT_TEMPLATES,\n personalization,\n onPersonalizationChange,\n onPersonalizationSave,\n apiKey,\n onApiKeyChange,\n apiEndpoint = '/api/chat',\n theme,\n showSidebar = true,\n sidebarWidth,\n sidebarRenderAfterHeader,\n sidebarRenderFooter,\n showSettings = true,\n showMemoryTab = true,\n showModelSelector = true,\n systemPrompt,\n contextCompressionThreshold = 20,\n keepRecentMessages = 6,\n storageKey = 'chatllm_sessions',\n initialSessionId,\n className = '',\n onSendMessage,\n onSessionChange,\n onError,\n onTitleChange,\n generateTitle,\n useExternalStorage = false,\n onLoadSessions,\n onCreateSession,\n onLoadSession,\n onDeleteSession,\n onUpdateSessionTitle,\n onSaveMessages,\n showThinking = true,\n thinkingDefaultOpen = false,\n deepResearch,\n skills,\n tools,\n onToolCall,\n continueAfterToolResult,\n onSkillComplete,\n onLoadModels,\n // Project options\n enableProjects,\n onLoadProjects,\n onCreateProject,\n onLoadProject,\n onUpdateProject,\n onDeleteProject,\n onAddProjectFile,\n onDeleteProjectFile,\n}) => {\n const hookOptions: UseChatUIOptions = {\n models,\n actions,\n initialPersonalization: personalization,\n onPersonalizationChange,\n onPersonalizationSave,\n initialSessionId,\n apiKey,\n apiEndpoint,\n initialModel: models[0]?.id,\n storageKey,\n contextCompressionThreshold,\n keepRecentMessages,\n onSendMessage,\n onSessionChange,\n onError,\n onTitleChange,\n generateTitle,\n useExternalStorage,\n onLoadSessions,\n onCreateSession,\n onLoadSession,\n onDeleteSession,\n onUpdateSessionTitle,\n onSaveMessages,\n deepResearch,\n skills,\n tools,\n onToolCall,\n continueAfterToolResult,\n onSkillComplete,\n onLoadModels,\n enableProjects,\n onLoadProjects,\n onCreateProject,\n onLoadProject,\n onUpdateProject,\n onDeleteProject,\n onAddProjectFile,\n onDeleteProjectFile,\n };\n\n const state = useChatUI(hookOptions);\n\n return (\n <ChatUIView\n state={state}\n models={models}\n actions={actions}\n templates={templates}\n showSidebar={showSidebar}\n sidebarWidth={sidebarWidth}\n sidebarRenderAfterHeader={sidebarRenderAfterHeader}\n sidebarRenderFooter={sidebarRenderFooter}\n showSettings={showSettings}\n showMemoryTab={showMemoryTab}\n showModelSelector={showModelSelector}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n theme={theme}\n className={className}\n apiKey={apiKey}\n onApiKeyChange={onApiKeyChange}\n deepResearchEnabled={!!deepResearch?.onWebSearch}\n />\n );\n};\n\n// ============================================================================\n// ChatUI - 메인 진입점\n// ============================================================================\n\n/**\n * @description ChatUI 메인 컴포넌트\n * @Todo vibecode - chatState 제공 시 외부 상태 사용, 미제공 시 내부 useChatUI 호출\n */\nexport const ChatUI: React.FC<ChatUIProps> = (props) => {\n injectStyles();\n\n if (props.chatState) {\n const {\n models = DEFAULT_MODELS,\n actions = DEFAULT_ACTIONS,\n templates = DEFAULT_TEMPLATES,\n showSidebar = true,\n sidebarWidth,\n sidebarRenderAfterHeader,\n sidebarRenderFooter,\n showSettings = true,\n showMemoryTab: chatStateShowMemoryTab = true,\n showModelSelector = true,\n showThinking = true,\n thinkingDefaultOpen = false,\n theme,\n className = '',\n apiKey,\n onApiKeyChange,\n deepResearch,\n } = props;\n\n return (\n <ChatUIView\n state={props.chatState}\n models={models}\n actions={actions}\n templates={templates}\n showSidebar={showSidebar}\n sidebarWidth={sidebarWidth}\n sidebarRenderAfterHeader={sidebarRenderAfterHeader}\n sidebarRenderFooter={sidebarRenderFooter}\n showSettings={showSettings}\n showMemoryTab={chatStateShowMemoryTab}\n showModelSelector={showModelSelector}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n theme={theme}\n className={className}\n apiKey={apiKey}\n onApiKeyChange={onApiKeyChange}\n deepResearchEnabled={!!deepResearch?.onWebSearch}\n />\n );\n }\n\n return <ChatUIWithHook {...props} />;\n};\n\nexport default ChatUI;\n","/**\n * @description Headless Chat UI Hook\n * 상태 관리와 로직만 제공, UI는 자유롭게 구현 가능\n */\n\nimport { useState, useRef, useCallback, useEffect, useMemo } from 'react';\nimport type {\n ChatSession,\n ChatMessage,\n ChatProject,\n ProjectFile,\n ActionItem,\n ModelConfig,\n PersonalizationConfig,\n UseChatUIReturn,\n SendMessageParams,\n SendMessageResponse,\n ProviderType,\n GlobalMemoryConfig,\n DeepResearchProgress,\n DeepResearchCallbacks,\n PollResponse,\n PollBlock,\n SkillConfig,\n SkillExecution,\n SkillExecutionResult,\n ManualSkillItem,\n ChatToolDefinition,\n ToolCallResult,\n MessageContentPart,\n ChatAttachment,\n} from '../types';\nimport { DEFAULT_PERSONALIZATION } from '../../types';\nimport { useGlobalMemory } from './useGlobalMemory';\nimport { useInfoExtraction } from './useInfoExtraction';\nimport { useSkills } from './useSkills';\nimport { useProject } from './useProject';\nimport { parsePollFromContent, formatPollResponse } from '../utils/pollParser';\nimport { convertToolsToSkills } from '../utils/toolAdapter';\nimport { parseSkillCallFromContent } from '../utils/skillParser';\n\n/**\n * @description SSE 스트리밍 Response에서 텍스트 추출\n * @Todo vibecode - 내부 LLM 호출(압축/추출) 응답 파싱 공통 유틸\n */\nconst parseSSEResponse = async (response: Response): Promise<string> => {\n const reader = response.body?.getReader();\n if (!reader) return '';\n\n const decoder = new TextDecoder();\n let buffer = '';\n let result = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n try {\n const parsed = JSON.parse(data);\n const chunk = parsed.content ?? parsed.text ?? '';\n if (chunk) result += chunk;\n } catch {\n // Ignore parse errors\n }\n }\n }\n }\n\n return result;\n};\nimport { writeSessionCache, readSessionCache, removeSessionCache } from '../utils/sessionCache';\nimport { migrateSessionsToProjects, DEFAULT_PROJECT_ID } from '../utils/projectMigration';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_STORAGE_KEY = 'chatllm_sessions';\nconst DEFAULT_PERSONALIZATION_KEY = 'chatllm_personalization';\nconst DEFAULT_COMPRESSION_THRESHOLD = 20;\nconst DEFAULT_KEEP_RECENT = 6;\nconst DEFAULT_RECOMPRESSION_THRESHOLD = 10;\nconst DEFAULT_TOKEN_LIMIT = 8000;\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\nconst generateId = (prefix: string): string =>\n `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n/**\n * @description File 객체를 base64 문자열로 변환\n * @Todo vibecode - autoConvertBase64 옵션 지원용 유틸리티\n */\nconst fileToBase64 = (file: File): Promise<string> =>\n new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve((reader.result as string).split(',')[1] || '');\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n\n/**\n * @description ChatAttachment 배열을 base64 변환된 객체 배열로 변환\n * @Todo vibecode - autoConvertBase64 옵션 지원\n */\nconst convertAttachmentsToBase64 = async (\n attachments: ChatAttachment[]\n): Promise<Array<{ name: string; mimeType: string; base64: string; size: number }>> =>\n Promise.all(\n attachments.map(async (att) => ({\n name: att.name,\n mimeType: att.mimeType,\n base64: await fileToBase64(att.file),\n size: att.size,\n }))\n );\n\nconst generateTitle = (messages: ChatMessage[]): string => {\n const firstUserMessage = messages.find((m) => m.role === 'user');\n if (!firstUserMessage) return '새 대화';\n const content = firstUserMessage.content;\n return content.length > 30 ? content.substring(0, 30) + '...' : content;\n};\n\n// ============================================================================\n// Hook Options\n// ============================================================================\n\nexport interface UseChatUIOptions {\n /** 사용 가능한 모델 목록 */\n models: ModelConfig[];\n /** 사용 가능한 Actions */\n actions?: ActionItem[];\n /** 초기 개인화 설정 */\n initialPersonalization?: Partial<PersonalizationConfig>;\n /** @Todo vibecode - 개인화 설정 변경 콜백 (실시간 UI 반영용) */\n onPersonalizationChange?: (config: PersonalizationConfig) => void;\n /** @Todo vibecode - 개인화 설정 저장 콜백 (저장 버튼 클릭 시 백엔드 저장용) */\n onPersonalizationSave?: (config: PersonalizationConfig) => void;\n /** @Todo vibecode - 초기 선택 세션 ID (미제공 시 sessions[0] 자동 선택) */\n initialSessionId?: string;\n /** API 키 */\n apiKey?: string;\n /** API 엔드포인트 */\n apiEndpoint?: string;\n /** 초기 모델 */\n initialModel?: string;\n /** 스토리지 키 */\n storageKey?: string;\n /** 컨텍스트 압축 임계값 */\n contextCompressionThreshold?: number;\n /** 압축 후 유지할 메시지 수 */\n keepRecentMessages?: number;\n /** 커스텀 메시지 전송 핸들러 */\n onSendMessage?: (params: SendMessageParams) => Promise<SendMessageResponse>;\n /** 세션 변경 핸들러 */\n onSessionChange?: (session: ChatSession | null) => void;\n /** 에러 핸들러 */\n onError?: (error: Error) => void;\n /** @Todo vibecode - 세션 제목 변경 핸들러 */\n onTitleChange?: (sessionId: string, newTitle: string) => void;\n /**\n * @description 첫 메시지 전송 시 LLM으로 제목 생성 콜백\n * @Todo vibecode - 자동 제목 생성 기능\n */\n generateTitle?: (firstMessage: string) => Promise<string> | string;\n\n // Memory Options\n /** 글로벌 메모리 사용 여부 (기본: true) */\n useGlobalMemoryEnabled?: boolean;\n /** 글로벌 메모리 설정 */\n globalMemoryConfig?: GlobalMemoryConfig;\n /** 자동 정보 추출 활성화 (기본: true) */\n enableAutoExtraction?: boolean;\n\n // External Storage Options\n /**\n * @description 외부 스토리지 사용 여부\n * @Todo vibecode - true 시 localStorage 대신 콜백 사용\n */\n useExternalStorage?: boolean;\n /**\n * @description 세션 목록 로드 콜백\n * @Todo vibecode - 컴포넌트 마운트 시 호출\n */\n onLoadSessions?: () => Promise<{ id: string; title: string }[]>;\n /**\n * @description 세션 생성 콜백\n * @Todo vibecode - 새 채팅 생성 시 호출\n */\n onCreateSession?: () => Promise<{ id: string; title: string }>;\n /**\n * @description 세션 상세 로드 콜백 (메시지 포함)\n * @Todo vibecode - 세션 선택 시 호출 (lazy loading)\n * API 응답 형식: { role: 'USER'|'ASSISTANT', message: string }\n */\n onLoadSession?: (sessionId: string) => Promise<{\n id: string;\n title: string;\n messages: Array<{\n id?: string;\n role: 'USER' | 'ASSISTANT' | 'user' | 'assistant';\n message?: string;\n content?: string;\n /** @Todo vibecode - 멀티 콘텐츠 파트 (이미지/파일 등 복원용) */\n contentParts?: MessageContentPart[];\n created_at?: string;\n }>;\n memory_data?: object;\n }>;\n /**\n * @description 세션 삭제 콜백\n * @Todo vibecode - 세션 삭제 시 호출\n */\n onDeleteSession?: (sessionId: string) => Promise<void>;\n /**\n * @description 세션 제목 수정 콜백\n * @Todo vibecode - 세션 제목 변경 시 호출\n */\n onUpdateSessionTitle?: (sessionId: string, title: string) => Promise<void>;\n /**\n * @description 메시지 저장 콜백\n * @Todo vibecode - 메시지 전송 완료 후 호출, contentParts로 이미지/파일 등 저장\n */\n onSaveMessages?: (\n sessionId: string,\n messages: { role: 'user' | 'assistant'; message: string; contentParts?: MessageContentPart[] }[]\n ) => Promise<void>;\n\n // Deep Research Options\n /**\n * @description 심층연구 콜백 (onWebSearch 필수)\n * @Todo vibecode - Perplexity 스타일 심층연구 기능\n */\n deepResearch?: DeepResearchCallbacks;\n\n // Poll Options\n /**\n * @description AI 주도 선택지 기능 활성화 (기본: true)\n * @Todo vibecode - AI가 자동으로 선택지를 제공하도록 시스템 프롬프트에 가이드 추가\n */\n enablePoll?: boolean;\n\n // Skills Options\n /**\n * @description 커스텀 스킬 등록\n * @Todo vibecode - AI가 자동/수동으로 활용하는 스킬 시스템\n */\n skills?: Record<string, SkillConfig>;\n\n // Tool Options\n /**\n * @description 도구 정의 목록 (호스트가 제공)\n * @Todo vibecode - AI가 자동으로 호출할 수 있는 도구 등록\n */\n tools?: ChatToolDefinition[];\n /**\n * @description 도구 실행 콜백 (호스트가 구현)\n * @Todo vibecode - 라이브러리가 도구 호출 판단 후 호스트에 실행 위임\n */\n onToolCall?: (name: string, params: Record<string, unknown>) => Promise<ToolCallResult>;\n\n // Project Options\n /**\n * @description 프로젝트 기능 활성화 여부 (기본: false)\n * @Todo vibecode - true 시 프로젝트 그룹핑, 지침, 메모리 계층 활성화\n */\n enableProjects?: boolean;\n /** @Todo vibecode - 프로젝트 목록 로드 콜백 */\n onLoadProjects?: () => Promise<{ id: string; title: string }[]>;\n /** @Todo vibecode - 프로젝트 생성 콜백 */\n onCreateProject?: (data: Partial<ChatProject>) => Promise<{ id: string; title: string }>;\n /** @Todo vibecode - 프로젝트 상세 로드 콜백 */\n onLoadProject?: (projectId: string) => Promise<ChatProject>;\n /** @Todo vibecode - 프로젝트 수정 콜백 */\n onUpdateProject?: (projectId: string, data: Partial<ChatProject>) => Promise<void>;\n /** @Todo vibecode - 프로젝트 삭제 콜백 */\n onDeleteProject?: (projectId: string) => Promise<void>;\n /** @Todo vibecode - 프로젝트 파일 추가 콜백 */\n onAddProjectFile?: (projectId: string, file: File) => Promise<ProjectFile>;\n /** @Todo vibecode - 프로젝트 파일 삭제 콜백 */\n onDeleteProjectFile?: (projectId: string, fileId: string) => Promise<void>;\n\n // Stream Control\n /**\n * @description 도구 실행 후 AI 스트리밍 계속 여부 (기본: true, 하위호환)\n * @Todo vibecode - false 시 도구 결과만 표시하고 AI 후속 응답 생략\n */\n continueAfterToolResult?: boolean;\n /**\n * @description 스킬 완료 시 콜백 (스트림 제어)\n * @Todo vibecode - 'continue' 반환 시 AI 응답 생성, 'stop' 반환 시 중단\n */\n onSkillComplete?: (skillName: string, result: SkillExecutionResult) => 'continue' | 'stop';\n\n // Dynamic Model Loading\n /**\n * @description 모델 목록 비동기 로드 콜백\n * @Todo vibecode - 제공 시 마운트 시 호출, 완료 전까지 models prop 사용\n */\n onLoadModels?: () => Promise<ModelConfig[]>;\n}\n\n// ============================================================================\n// Main Hook\n// ============================================================================\n\nexport const useChatUI = (options: UseChatUIOptions): UseChatUIReturn => {\n const {\n models,\n actions = [],\n initialPersonalization,\n apiKey,\n apiEndpoint = '/api/chat',\n initialModel,\n storageKey = DEFAULT_STORAGE_KEY,\n contextCompressionThreshold = DEFAULT_COMPRESSION_THRESHOLD,\n keepRecentMessages = DEFAULT_KEEP_RECENT,\n onSendMessage,\n onSessionChange,\n onError,\n onTitleChange,\n generateTitle: generateTitleCallback,\n // Memory options\n useGlobalMemoryEnabled = true,\n globalMemoryConfig,\n enableAutoExtraction: enableAutoExtractionProp,\n // External storage options\n useExternalStorage = false,\n onLoadSessions,\n onCreateSession,\n onLoadSession,\n onDeleteSession: onDeleteSessionCallback,\n onUpdateSessionTitle,\n onSaveMessages,\n // Deep Research options\n deepResearch,\n // Poll options\n enablePoll = true,\n // Skills options\n skills,\n // Tool options\n tools,\n onToolCall,\n // Project options\n enableProjects = false,\n onLoadProjects,\n onCreateProject,\n onLoadProject,\n onUpdateProject,\n onDeleteProject,\n onAddProjectFile,\n onDeleteProjectFile,\n // Stream control\n continueAfterToolResult = true,\n onSkillComplete,\n // Dynamic model loading\n onLoadModels,\n } = options;\n\n /** @Todo vibecode - 외부 스토리지 모드에서는 자동 추출 기본 비활성화 (404 방지) */\n const enableAutoExtraction = enableAutoExtractionProp ?? !useExternalStorage;\n\n // ============================================================================\n // State\n // ============================================================================\n\n const [sessions, setSessions] = useState<ChatSession[]>([]);\n const [currentSessionId, setCurrentSessionId] = useState<string | null>(null);\n const [input, setInput] = useState('');\n const [isLoading, setIsLoading] = useState(false);\n const [selectedModel, setSelectedModel] = useState(initialModel || models[0]?.id || '');\n const [sidebarOpen, setSidebarOpen] = useState(true);\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [quotedText, setQuotedText] = useState<string | null>(null);\n const [selectedAction, setSelectedAction] = useState<ActionItem | null>(null);\n const [copiedMessageId, setCopiedMessageId] = useState<string | null>(null);\n const [editingMessageId, setEditingMessageId] = useState<string | null>(null);\n const [personalization, setPersonalization] = useState<PersonalizationConfig>({\n ...DEFAULT_PERSONALIZATION,\n ...initialPersonalization,\n });\n const [activeAlternatives, setActiveAlternatives] = useState<Record<string, number>>({});\n /**\n * @description 다른 모델 응답 생성 중인 메시지 ID\n * @Todo vibecode - 로딩 인디케이터 표시용\n */\n const [loadingAlternativeFor, setLoadingAlternativeFor] = useState<string | null>(null);\n\n /**\n * @description 외부 스토리지 로딩 상태\n * @Todo vibecode - 세션 목록 로드 중\n */\n const [isSessionsLoading, setIsSessionsLoading] = useState(false);\n /**\n * @description 외부 스토리지 로딩 상태\n * @Todo vibecode - 단일 세션 로드 중\n */\n const [isSessionLoading, setIsSessionLoading] = useState(false);\n\n /**\n * @description 심층연구 모드 활성화 여부\n * @Todo vibecode - 심층연구 버튼 토글 상태\n */\n const [isDeepResearchMode, setIsDeepResearchMode] = useState(false);\n\n /**\n * @description 첨부파일 상태 (이미지/파일)\n * @Todo vibecode - 입력창 파일 첨부 상태 관리\n */\n const [attachments, setAttachments] = useState<ChatAttachment[]>([]);\n\n /**\n * @description 모델 목록 동적 로드 상태\n * @Todo vibecode - onLoadModels 제공 시 비동기 모델 목록 관리\n */\n const [isModelsLoading, setIsModelsLoading] = useState(false);\n const [loadedModels, setLoadedModels] = useState<ModelConfig[] | null>(null);\n\n /**\n * @description 심층연구 진행 상태\n * @Todo vibecode - 4단계 심층연구 프로세스 상태\n */\n const [deepResearchProgress, setDeepResearchProgress] = useState<DeepResearchProgress | null>(\n null\n );\n\n /** @Todo vibecode - 최신 sessions 접근용 ref (stale closure 방지) */\n const sessionsRef = useRef(sessions);\n useEffect(() => { sessionsRef.current = sessions; }, [sessions]);\n\n // ============================================================================\n // Callback Refs (stale closure 방지)\n // ============================================================================\n\n /** @Todo vibecode - 외부 콜백 useRef 래핑 (Provider 리렌더 시 참조 안정성 보장) */\n const onSendMessageRef = useRef(onSendMessage);\n const onSessionChangeRef = useRef(onSessionChange);\n const onErrorRef = useRef(onError);\n const onTitleChangeRef = useRef(onTitleChange);\n const generateTitleRef = useRef(generateTitleCallback);\n const onPersonalizationChangeRef = useRef(options.onPersonalizationChange);\n const onPersonalizationSaveRef = useRef(options.onPersonalizationSave);\n const onLoadSessionsRef = useRef(onLoadSessions);\n const onCreateSessionRef = useRef(onCreateSession);\n const onLoadSessionRef = useRef(onLoadSession);\n const onDeleteSessionCallbackRef = useRef(onDeleteSessionCallback);\n const onUpdateSessionTitleRef = useRef(onUpdateSessionTitle);\n const onSaveMessagesRef = useRef(onSaveMessages);\n const onToolCallRef = useRef(onToolCall);\n const onSkillCompleteRef = useRef(onSkillComplete);\n const onLoadModelsRef = useRef(onLoadModels);\n\n /** @Todo vibecode - 매 렌더 시 ref.current 동기화 (deps 없는 useEffect) */\n useEffect(() => {\n onSendMessageRef.current = onSendMessage;\n onSessionChangeRef.current = onSessionChange;\n onErrorRef.current = onError;\n onTitleChangeRef.current = onTitleChange;\n generateTitleRef.current = generateTitleCallback;\n onPersonalizationChangeRef.current = options.onPersonalizationChange;\n onPersonalizationSaveRef.current = options.onPersonalizationSave;\n onLoadSessionsRef.current = onLoadSessions;\n onCreateSessionRef.current = onCreateSession;\n onLoadSessionRef.current = onLoadSession;\n onDeleteSessionCallbackRef.current = onDeleteSessionCallback;\n onUpdateSessionTitleRef.current = onUpdateSessionTitle;\n onSaveMessagesRef.current = onSaveMessages;\n onToolCallRef.current = onToolCall;\n onSkillCompleteRef.current = onSkillComplete;\n onLoadModelsRef.current = onLoadModels;\n });\n\n const abortControllerRef = useRef<AbortController | null>(null);\n\n /**\n * @description Poll 응답 후 다음 AI 응답에서 poll 파싱 스킵 여부\n * @Todo vibecode - 사용자가 poll에 응답한 직후 AI가 또 poll을 생성하는 것을 방지\n */\n const skipNextPollParsingRef = useRef(false);\n\n /**\n * @description Skill 실행 후 다음 AI 응답에서 skill_use 파싱 스킵 여부\n * @Todo vibecode - 스킬 결과 전달 후 AI가 또 스킬을 호출하는 무한루프 방지\n */\n const skipNextSkillParsingRef = useRef(false);\n\n /**\n * @description 마지막 정보 추출 시점의 메시지 수\n * @Todo vibecode - 주기적 정보 추출 트리거용\n */\n const lastExtractionMsgCountRef = useRef(0);\n\n // ============================================================================\n // Memory Hooks\n // ============================================================================\n\n // 글로벌 메모리 설정\n const memoryOptions = useMemo(\n () => ({\n storageType: globalMemoryConfig?.storageType || 'localStorage',\n storageKey: globalMemoryConfig?.localStorage?.key || `${storageKey}_memory`,\n apiEndpoint: globalMemoryConfig?.postgresql?.apiEndpoint,\n userId: globalMemoryConfig?.postgresql?.userId,\n authToken: globalMemoryConfig?.postgresql?.authToken,\n }),\n [globalMemoryConfig, storageKey]\n );\n\n const globalMemory = useGlobalMemoryEnabled ? useGlobalMemory(memoryOptions) : null;\n\n // ============================================================================\n // Skills Hook\n // ============================================================================\n\n /**\n * @description Tools → Skills 병합 (도구가 같은 이름의 스킬 덮어씀)\n * @Todo vibecode - tools + skills 통합\n */\n /** @Todo vibecode - onToolCallRef 래핑으로 콜백 안정성 보장 */\n const stableToolCall = useCallback(\n (name: string, params: Record<string, unknown>) => onToolCallRef.current!(name, params),\n []\n );\n const mergedSkills = useMemo(() => {\n if (!tools || !onToolCall) return skills || {};\n const toolSkills = convertToolsToSkills(tools, stableToolCall);\n return { ...(skills || {}), ...toolSkills };\n }, [skills, tools, !!onToolCall, stableToolCall]);\n\n const {\n buildSkillsPrompt,\n handleSkillCall,\n manualSkills,\n executeManualSkill,\n activeSkillExecution,\n resolvedSkills,\n } = useSkills({\n skills: mergedSkills,\n deepResearch,\n });\n\n // ============================================================================\n // Project Hook\n // ============================================================================\n\n /** @Todo vibecode - 항상 호출 (Hook 규칙 준수), enabled로 내부 활성화 제어 */\n const projectHook = useProject({\n enabled: enableProjects,\n useExternalStorage,\n storageKey: `${storageKey}_projects`,\n onLoadProjects,\n onCreateProject,\n onLoadProject,\n onUpdateProject,\n onDeleteProject,\n onAddProjectFile,\n onDeleteProjectFile,\n onError,\n });\n\n /**\n * @description 프로젝트 설정 모달 열림 상태\n * @Todo vibecode - 프로젝트 설정 UI\n */\n const [projectSettingsOpen, setProjectSettingsOpen] = useState(false);\n\n /**\n * @description 프로젝트 메모리 (계층형 3-tier 중 프로젝트 레벨)\n * @Todo vibecode - currentProjectId 기반 스코프 키로 useGlobalMemory 재활용\n * Hook 규칙 때문에 항상 호출하되 키에 projectId 포함\n */\n const projectMemoryKey = enableProjects && projectHook.currentProjectId\n ? `${storageKey}_project_memory_${projectHook.currentProjectId}`\n : `${storageKey}_project_memory_none`;\n\n const projectMemoryOptions = useMemo(\n () => ({\n storageType: globalMemoryConfig?.storageType || 'localStorage',\n storageKey: projectMemoryKey,\n apiEndpoint: globalMemoryConfig?.postgresql?.apiEndpoint,\n userId: globalMemoryConfig?.postgresql?.userId,\n authToken: globalMemoryConfig?.postgresql?.authToken,\n }),\n [globalMemoryConfig, projectMemoryKey]\n );\n\n /** @Todo vibecode - 항상 호출 (Hook 규칙 준수), enableProjects=false이면 noop 키 사용 */\n const projectMemoryRaw = useGlobalMemory(projectMemoryOptions);\n const projectMemory = enableProjects ? projectMemoryRaw : null;\n\n // ============================================================================\n // Internal LLM Call (압축/추출용)\n // ============================================================================\n\n /**\n * @description 내부 LLM 호출 유틸 (압축, 정보 추출 등)\n * @Todo vibecode - onSendMessage 모드에서도 내부 LLM 호출 지원\n * apiEndpoint 없이 onSendMessage만 제공한 경우 호스트 콜백 재활용\n */\n const callInternalLLM = useCallback(async (prompt: string, model: string): Promise<string> => {\n if (onSendMessageRef.current) {\n const modelConfig = models.find((m) => m.id === model);\n const provider = modelConfig?.provider || 'ollama';\n\n const result = await onSendMessageRef.current({\n messages: [{ role: 'user', content: prompt }],\n model,\n provider,\n apiKey,\n });\n\n if (typeof result === 'string') return result;\n if (typeof result === 'object' && 'content' in result) return result.content;\n /** @Todo vibecode - ReadableStream 반환 시 SSE 파싱 */\n return parseSSEResponse(new Response(result as ReadableStream<Uint8Array>));\n }\n\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [{ role: 'user', content: prompt }],\n model,\n }),\n });\n if (!response.ok) return '';\n return parseSSEResponse(response);\n }, [apiEndpoint, apiKey, models]);\n\n // 정보 추출 설정\n const infoExtraction = useInfoExtraction({\n apiEndpoint,\n model: selectedModel,\n minConfidence: 0.8,\n globalMemory: globalMemory!,\n onCallLLM: callInternalLLM,\n });\n\n // ============================================================================\n // Derived State\n // ============================================================================\n\n const currentSession = sessions.find((s) => s.id === currentSessionId) || null;\n /** @description UI에 표시할 메시지 (hidden 제외) */\n const messages = currentSession?.messages.filter((m) => !m.hidden) || [];\n const compressionState = currentSession?.compressionState || null;\n\n /**\n * @description 프로젝트별 세션 필터링\n * @Todo vibecode - enableProjects 시 현재 프로젝트 소속 세션만 표시\n */\n const visibleSessions = useMemo(() => {\n if (!enableProjects || !projectHook.currentProjectId) return sessions;\n return sessions.filter((s) => s.projectId === projectHook.currentProjectId);\n }, [sessions, enableProjects, projectHook.currentProjectId]);\n\n // ============================================================================\n // Persistence\n // ============================================================================\n\n /**\n * @description 초기 세션 로드\n * @Todo vibecode - 외부 스토리지 사용 시 onLoadSessions 콜백 호출\n */\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n // 외부 스토리지 사용 시 콜백으로 세션 목록 로드\n if (useExternalStorage && onLoadSessionsRef.current) {\n setIsSessionsLoading(true);\n onLoadSessionsRef.current()\n .then((sessionList) => {\n // 세션 목록만 로드 (메시지는 selectSession에서 lazy load)\n const sessionsWithoutMessages: ChatSession[] = sessionList.map((s) => ({\n id: s.id,\n title: s.title,\n messages: [], // 메시지는 세션 선택 시 로드\n model: initialModel || models[0]?.id || '',\n createdAt: Date.now(),\n updatedAt: Date.now(),\n }));\n setSessions(sessionsWithoutMessages);\n /** @Todo vibecode - initialSessionId 우선 선택, 없으면 첫 번째 세션 */\n if (sessionsWithoutMessages.length > 0) {\n const targetId = options.initialSessionId && sessionsWithoutMessages.some(s => s.id === options.initialSessionId)\n ? options.initialSessionId\n : sessionsWithoutMessages[0].id;\n setCurrentSessionId(targetId);\n }\n })\n .catch((error) => {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to load sessions'));\n })\n .finally(() => {\n setIsSessionsLoading(false);\n });\n\n /** @Todo vibecode - 개인화 설정은 localStorage에서 로드 (외부 스토리지 모드에서도) */\n if (typeof window !== 'undefined') {\n const savedPersonalization = localStorage.getItem(`${storageKey}_personalization`);\n if (savedPersonalization) {\n try {\n setPersonalization(JSON.parse(savedPersonalization));\n } catch {\n // Ignore parse errors\n }\n }\n }\n return;\n }\n\n /** @Todo vibecode - enableProjects 시 기존 세션 마이그레이션 */\n if (enableProjects) {\n migrateSessionsToProjects(storageKey);\n }\n\n // 기존 localStorage 로직\n if (typeof window === 'undefined') return;\n const saved = localStorage.getItem(storageKey);\n if (saved) {\n try {\n const parsed = JSON.parse(saved) as ChatSession[];\n setSessions(parsed);\n /** @Todo vibecode - initialSessionId 우선 선택, 없으면 첫 번째 세션 */\n if (parsed.length > 0) {\n const targetSession = options.initialSessionId\n ? parsed.find(s => s.id === options.initialSessionId)\n : null;\n const selected = targetSession || parsed[0];\n setCurrentSessionId(selected.id);\n setSelectedModel(selected.model);\n }\n } catch {\n // Ignore parse errors\n }\n }\n\n const savedPersonalization = localStorage.getItem(`${storageKey}_personalization`);\n if (savedPersonalization) {\n try {\n setPersonalization(JSON.parse(savedPersonalization));\n } catch {\n // Ignore parse errors\n }\n }\n }, [storageKey, useExternalStorage, initialModel, models]);\n\n /**\n * @description 모델 목록 비동기 로드\n * @Todo vibecode - onLoadModels 제공 시 마운트 시 호출\n */\n useEffect(() => {\n if (!onLoadModelsRef.current) return;\n setIsModelsLoading(true);\n onLoadModelsRef.current()\n .then((modelList) => {\n setLoadedModels(modelList);\n if (modelList.length > 0 && !modelList.find((m) => m.id === selectedModel)) {\n setSelectedModel(modelList[0].id);\n }\n })\n .catch((error) => {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to load models'));\n })\n .finally(() => {\n setIsModelsLoading(false);\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n /** @Todo vibecode - 동적 로드 모델 우선, 없으면 props.models 사용 */\n const effectiveModels = loadedModels || models;\n\n /**\n * @description 세션 자동 저장\n * @Todo vibecode - 외부 스토리지 사용 시 localStorage 저장 스킵\n */\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n // 외부 스토리지 사용 시 localStorage 저장 스킵\n if (useExternalStorage) return;\n\n if (sessions.length > 0) {\n localStorage.setItem(storageKey, JSON.stringify(sessions));\n }\n }, [sessions, storageKey, useExternalStorage]);\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n localStorage.setItem(`${storageKey}_personalization`, JSON.stringify(personalization));\n }, [personalization, storageKey]);\n\n // ============================================================================\n // Session Change Callback\n // ============================================================================\n\n useEffect(() => {\n onSessionChangeRef.current?.(currentSession);\n }, [currentSession]);\n\n // ============================================================================\n // System Prompt Builder\n // ============================================================================\n\n const buildSystemPrompt = useCallback((): string => {\n const parts: string[] = [];\n const { userProfile, responseStyle, language } = personalization;\n\n /** @Todo vibecode - 닉네임 뒤 '님' 호칭 + 존대말 기본 지시 */\n if (userProfile.nickname) {\n parts.push(`사용자의 이름/닉네임: ${userProfile.nickname}님 (항상 '님'을 붙여서 호칭하고, 존대말(합쇼체/해요체)로 응답해주세요)`);\n }\n if (userProfile.occupation) {\n parts.push(`사용자의 직업: ${userProfile.occupation}`);\n }\n if (userProfile.additionalInfo) {\n parts.push(`사용자 추가 정보: ${userProfile.additionalInfo}`);\n }\n\n const styleDescriptions: string[] = [];\n if (responseStyle.warmth === 'high') styleDescriptions.push('따뜻하고 친근하게');\n else if (responseStyle.warmth === 'low') styleDescriptions.push('간결하고 사무적으로');\n\n if (responseStyle.enthusiasm === 'high') styleDescriptions.push('열정적이고 적극적으로');\n else if (responseStyle.enthusiasm === 'low') styleDescriptions.push('차분하게');\n\n if (responseStyle.emojiUsage === 'high') styleDescriptions.push('이모지를 적극 활용해서');\n else if (responseStyle.emojiUsage === 'low') styleDescriptions.push('이모지 사용을 자제해서');\n\n if (responseStyle.verbosity === 'concise') styleDescriptions.push('핵심만 간결하게');\n else if (responseStyle.verbosity === 'detailed') styleDescriptions.push('상세하고 자세하게');\n\n if (styleDescriptions.length > 0) {\n parts.push(`응답 스타일: ${styleDescriptions.join(', ')} 응답해주세요.`);\n }\n\n if (language !== 'auto') {\n const languageNames: Record<string, string> = { ko: '한국어', en: '영어', ja: '일본어' };\n parts.push(`응답 언어: ${languageNames[language] || language}로 응답해주세요.`);\n }\n\n // 글로벌 메모리 컨텍스트 추가\n if (useGlobalMemoryEnabled && globalMemory && personalization.useMemory) {\n const memoryContext = globalMemory.toPromptContext();\n if (memoryContext) {\n parts.push('');\n parts.push(memoryContext);\n }\n }\n\n /**\n * @description 프로젝트 지침 + 프로젝트 메모리 주입\n * @Todo vibecode - 계층형 메모리: Global → Project → Session\n */\n if (enableProjects && projectHook.currentProject) {\n if (projectHook.currentProject.instructions) {\n parts.push('');\n parts.push(`[프로젝트 지침]\\n${projectHook.currentProject.instructions}`);\n }\n if (projectMemory) {\n const projectMemoryContext = projectMemory.toPromptContext();\n if (projectMemoryContext) {\n parts.push('');\n parts.push(`[프로젝트 기억]\\n${projectMemoryContext}`);\n }\n }\n }\n\n // 스킬 가이드 추가\n const skillsPrompt = buildSkillsPrompt();\n if (skillsPrompt) {\n parts.push('');\n parts.push(skillsPrompt);\n }\n\n // Poll 기능 가이드 추가 (Claude Code 스타일)\n if (enablePoll) {\n parts.push('');\n parts.push(`## 선택지 질문 기능\n\n사용자 요청에 명확화가 필요하면 <poll> 태그로 질문하세요.\n**중요: 필요한 모든 질문을 한 번에 작성하세요. 질문을 나눠서 하지 마세요.**\n\n**예시 - 3개 질문을 한 번에:**\n<poll question=\"로고 용도는?\" multiSelect=\"false\">\n- 서비스/앱: 디지털 서비스용\n- 브랜드: 회사 아이덴티티\n- 개인: 개인 프로젝트\n</poll>\n\n<poll question=\"선호하는 스타일은?\" multiSelect=\"true\">\n- 미니멀: 심플하고 깔끔한\n- 모던: 트렌디하고 세련된\n- 클래식: 전통적이고 신뢰감 있는\n</poll>\n\n<poll question=\"주요 색상은?\" multiSelect=\"false\">\n- 블루 계열: 신뢰, 전문성\n- 그린 계열: 성장, 친환경\n- 다크 계열: 고급, 세련됨\n</poll>\n\n**규칙:**\n- 필요한 질문 1~3개를 **한 번에 모두** 작성\n- 각 질문은 서로 다른 내용\n- 옵션마다 짧은 설명 포함\n- 사용자가 모두 선택 후 진행`);\n }\n\n return parts.length > 0 ? parts.join('\\n') : '';\n }, [personalization, globalMemory, useGlobalMemoryEnabled, enablePoll, buildSkillsPrompt, enableProjects, projectHook.currentProject, projectMemory]);\n\n // ============================================================================\n // Context Compression\n // ============================================================================\n\n const compressContext = useCallback(async (\n messagesToCompress: ChatMessage[],\n model: string\n ): Promise<string> => {\n const conversationText = messagesToCompress\n .map((m) => `${m.role === 'user' ? '사용자' : 'AI'}: ${m.content}`)\n .join('\\n\\n');\n\n const summaryPrompt = `다음 대화 내용을 핵심 정보만 유지하면서 간결하게 요약해주세요.\n중요한 결정사항, 사용자 요구사항, 맥락 정보를 보존하세요.\n\n대화:\n${conversationText}\n\n요약:`;\n\n try {\n return await callInternalLLM(summaryPrompt, model);\n } catch {\n return '';\n }\n }, [callInternalLLM]);\n\n /**\n * @description 점진적 압축 - 기존 요약과 새 대화를 통합\n * @param existingSummary 기존 요약\n * @param newMessages 새로 추가된 메시지들\n * @param model 사용할 모델\n */\n const incrementalCompressContext = useCallback(\n async (\n existingSummary: string,\n newMessages: ChatMessage[],\n model: string\n ): Promise<string> => {\n const newConversation = newMessages\n .map((m) => `${m.role === 'user' ? '사용자' : 'AI'}: ${m.content}`)\n .join('\\n\\n');\n\n const mergePrompt = `기존 대화 요약과 새로운 대화 내용을 통합하여 하나의 요약으로 만들어주세요.\n\n[기존 요약]\n${existingSummary}\n\n[새로운 대화]\n${newConversation}\n\n통합 요약 작성 시 다음을 지켜주세요:\n1. 핵심 결정사항, 사용자 요구사항, 맥락 정보 보존\n2. 중복 정보 제거\n3. 시간순 흐름 유지\n4. 300자 이내로 간결하게\n\n통합 요약:`;\n\n try {\n const summary = await callInternalLLM(mergePrompt, model);\n return summary || existingSummary;\n } catch {\n return existingSummary;\n }\n },\n [callInternalLLM]\n );\n\n /**\n * @description 토큰 수 추정 (문자 길이 / 4)\n */\n const estimateTokens = useCallback((messages: ChatMessage[]): number => {\n return messages.reduce((sum, m) => sum + Math.ceil(m.content.length / 4), 0);\n }, []);\n\n // ============================================================================\n // Actions\n // ============================================================================\n\n /**\n * @description 새 세션 생성\n * @Todo vibecode - 외부 스토리지 사용 시 onCreateSession 콜백 호출\n */\n const newSession = useCallback(async () => {\n /** @Todo vibecode - 현재 프로젝트 ID (enableProjects 시 할당) */\n const projectId = enableProjects\n ? (projectHook.currentProjectId || DEFAULT_PROJECT_ID)\n : undefined;\n\n // 외부 스토리지 사용 시 콜백으로 세션 생성\n if (useExternalStorage && onCreateSessionRef.current) {\n setIsSessionLoading(true);\n try {\n const created = await onCreateSessionRef.current();\n const now = Date.now();\n const newSess: ChatSession = {\n id: created.id,\n title: created.title,\n messages: [],\n model: selectedModel,\n createdAt: now,\n updatedAt: now,\n ...(projectId && { projectId }),\n };\n setSessions((prev) => [newSess, ...prev]);\n setCurrentSessionId(newSess.id);\n } catch (error) {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to create session'));\n } finally {\n setIsSessionLoading(false);\n }\n return;\n }\n\n // 기존 로직\n const now = Date.now();\n const newSess: ChatSession = {\n id: generateId('session'),\n title: '새 대화',\n messages: [],\n model: selectedModel,\n createdAt: now,\n updatedAt: now,\n ...(projectId && { projectId }),\n };\n setSessions((prev) => [newSess, ...prev]);\n setCurrentSessionId(newSess.id);\n }, [selectedModel, useExternalStorage, enableProjects, projectHook.currentProjectId]);\n\n /**\n * @description 세션 선택\n * @Todo vibecode - 외부 스토리지 사용 시 onLoadSession 콜백 호출 (lazy loading)\n */\n const selectSession = useCallback(async (id: string) => {\n // 외부 스토리지 사용 시 세션 상세 로드\n if (useExternalStorage && onLoadSessionRef.current) {\n setIsSessionLoading(true);\n try {\n const sessionDetail = await onLoadSessionRef.current(id);\n\n /**\n * @description role 및 content 형식 변환\n * @Todo vibecode - API 응답 형식(message) -> 내부 형식(content) 변환\n */\n let loadedMessages: ChatMessage[] = sessionDetail.messages.map((m, idx) => ({\n id: m.id || generateId('msg'),\n role: (typeof m.role === 'string' ? m.role.toLowerCase() : m.role) as 'user' | 'assistant' | 'system',\n // API는 message 필드, 내부는 content 필드 사용\n content: m.content || m.message || '',\n timestamp: m.created_at ? new Date(m.created_at).getTime() : Date.now() - (sessionDetail.messages.length - idx) * 1000,\n model: (m as ChatMessage).model,\n alternatives: (m as ChatMessage).alternatives,\n sources: (m as ChatMessage).sources,\n /** @Todo vibecode - 백엔드에서 전달받은 contentParts 복원 (이미지/파일 등) */\n ...(m.contentParts && { contentParts: m.contentParts }),\n }));\n\n /**\n * @description 빈 응답 시 localStorage 캐시 fallback\n * @Todo vibecode - 서버가 빈 messages 반환 시 캐시에서 복원\n */\n let resolvedTitle = sessionDetail.title;\n if (loadedMessages.length === 0) {\n const cached = readSessionCache(storageKey, id);\n if (cached && cached.messages.length > 0) {\n console.warn('[useChatUI] Server returned empty messages, using localStorage cache');\n loadedMessages = cached.messages;\n if (!resolvedTitle && cached.title) {\n resolvedTitle = cached.title;\n }\n }\n }\n\n setSessions((prev) =>\n prev.map((s) =>\n s.id === id\n ? { ...s, title: resolvedTitle, messages: loadedMessages, updatedAt: Date.now() }\n : s\n )\n );\n setCurrentSessionId(id);\n\n /**\n * @description 성공적으로 로드된 세션을 캐시에 저장\n * @Todo vibecode - 다음 번 fallback 시 사용할 최신 데이터 보장\n */\n if (loadedMessages.length > 0) {\n const existingSession = sessions.find((s) => s.id === id);\n writeSessionCache(storageKey, {\n id,\n title: resolvedTitle,\n messages: loadedMessages,\n model: existingSession?.model || initialModel || models[0]?.id || '',\n createdAt: existingSession?.createdAt || Date.now(),\n updatedAt: Date.now(),\n });\n }\n\n // 세션의 모델 설정\n const existingSession = sessions.find((s) => s.id === id);\n if (existingSession) {\n setSelectedModel(existingSession.model);\n }\n } catch (error) {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to load session'));\n\n /**\n * @description onLoadSession 에러 시 localStorage 캐시 fallback\n * @Todo vibecode - 서버 장애 시에도 이전 대화 복원\n */\n const cached = readSessionCache(storageKey, id);\n if (cached && cached.messages.length > 0) {\n console.warn('[useChatUI] onLoadSession failed, using localStorage cache');\n setSessions((prev) =>\n prev.map((s) =>\n s.id === id\n ? { ...s, title: cached.title || s.title, messages: cached.messages, updatedAt: Date.now() }\n : s\n )\n );\n setCurrentSessionId(id);\n const existingSession = sessions.find((s) => s.id === id);\n if (existingSession) {\n setSelectedModel(existingSession.model);\n }\n }\n } finally {\n setIsSessionLoading(false);\n }\n return;\n }\n\n // 기존 로직\n const session = sessions.find((s) => s.id === id);\n if (session) {\n setCurrentSessionId(id);\n setSelectedModel(session.model);\n }\n }, [sessions, useExternalStorage, storageKey, initialModel, models]);\n\n /**\n * @description 세션 삭제\n * @Todo vibecode - 외부 스토리지 사용 시 onDeleteSession 콜백 호출\n */\n const deleteSession = useCallback(async (id: string) => {\n // 외부 스토리지 사용 시 콜백으로 삭제\n if (useExternalStorage && onDeleteSessionCallbackRef.current) {\n try {\n await onDeleteSessionCallbackRef.current(id);\n /** @Todo vibecode - localStorage 캐시도 함께 삭제 */\n removeSessionCache(storageKey, id);\n setSessions((prev) => {\n const filtered = prev.filter((s) => s.id !== id);\n if (currentSessionId === id) {\n setCurrentSessionId(filtered.length > 0 ? filtered[0].id : null);\n }\n return filtered;\n });\n } catch (error) {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to delete session'));\n }\n return;\n }\n\n // 기존 로직\n setSessions((prev) => {\n const filtered = prev.filter((s) => s.id !== id);\n if (currentSessionId === id) {\n setCurrentSessionId(filtered.length > 0 ? filtered[0].id : null);\n }\n if (filtered.length === 0 && typeof window !== 'undefined') {\n localStorage.removeItem(storageKey);\n }\n return filtered;\n });\n }, [currentSessionId, storageKey, useExternalStorage]);\n\n /**\n * @description 세션 제목 변경\n * @Todo vibecode - 외부 스토리지 사용 시 onUpdateSessionTitle 콜백 호출\n */\n const renameSession = useCallback(async (id: string, newTitle: string) => {\n if (!newTitle.trim()) return;\n\n // 외부 스토리지 사용 시 콜백으로 제목 변경\n if (useExternalStorage && onUpdateSessionTitleRef.current) {\n try {\n await onUpdateSessionTitleRef.current(id, newTitle.trim());\n setSessions((prev) =>\n prev.map((s) =>\n s.id === id ? { ...s, title: newTitle.trim(), updatedAt: Date.now() } : s\n )\n );\n onTitleChangeRef.current?.(id, newTitle.trim());\n } catch (error) {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to update session title'));\n }\n return;\n }\n\n // 기존 로직\n setSessions((prev) =>\n prev.map((s) =>\n s.id === id ? { ...s, title: newTitle.trim(), updatedAt: Date.now() } : s\n )\n );\n onTitleChangeRef.current?.(id, newTitle.trim());\n }, [useExternalStorage]);\n\n const setModel = useCallback((model: string) => {\n setSelectedModel(model);\n if (currentSessionId) {\n setSessions((prev) =>\n prev.map((s) => (s.id === currentSessionId ? { ...s, model } : s))\n );\n }\n }, [currentSessionId]);\n\n const toggleSidebar = useCallback(() => setSidebarOpen((prev) => !prev), []);\n const openSettings = useCallback(() => setSettingsOpen(true), []);\n const closeSettings = useCallback(() => setSettingsOpen(false), []);\n\n const copyMessage = useCallback((content: string, id: string) => {\n if (typeof navigator !== 'undefined') {\n navigator.clipboard.writeText(content).then(() => {\n setCopiedMessageId(id);\n setTimeout(() => setCopiedMessageId(null), 2000);\n });\n }\n }, []);\n\n const startEdit = useCallback((message: ChatMessage) => {\n if (message.role === 'user') {\n setEditingMessageId(message.id);\n }\n }, []);\n\n const cancelEdit = useCallback(() => {\n setEditingMessageId(null);\n }, []);\n\n const stopGeneration = useCallback(() => {\n abortControllerRef.current?.abort();\n }, []);\n\n /**\n * @description 개인화 설정 업데이트 + 외부 콜백 호출\n * @Todo vibecode - 로컬 상태 업데이트 후 onPersonalizationChange로 백엔드 저장 트리거\n */\n const updatePersonalization = useCallback((config: Partial<PersonalizationConfig>) => {\n setPersonalization((prev) => {\n const next = { ...prev, ...config };\n onPersonalizationChangeRef.current?.(next);\n return next;\n });\n }, []);\n\n /**\n * @description 개인화 설정 저장 (저장 버튼 클릭 시)\n * @Todo vibecode - onPersonalizationSave 콜백 1회 호출\n */\n const savePersonalization = useCallback(() => {\n onPersonalizationSaveRef.current?.(personalization);\n }, [personalization]);\n\n /**\n * @description 파일 첨부 추가 (File[] → ChatAttachment[] 변환)\n * @Todo vibecode - 이미지는 URL.createObjectURL로 프리뷰 생성\n */\n const addAttachments = useCallback((files: File[]) => {\n const newAttachments: ChatAttachment[] = files.map((file) => {\n const isImage = file.type.startsWith('image/');\n return {\n id: generateId('attach'),\n file,\n name: file.name,\n type: isImage ? 'image' : 'file',\n previewUrl: isImage ? URL.createObjectURL(file) : undefined,\n mimeType: file.type,\n size: file.size,\n };\n });\n setAttachments((prev) => [...prev, ...newAttachments]);\n }, []);\n\n /**\n * @description 첨부파일 제거 (objectURL 해제 포함)\n * @Todo vibecode - 프리뷰에서 X 버튼 클릭 시\n */\n const removeAttachment = useCallback((id: string) => {\n setAttachments((prev) => {\n const target = prev.find((a) => a.id === id);\n if (target?.previewUrl) {\n URL.revokeObjectURL(target.previewUrl);\n }\n return prev.filter((a) => a.id !== id);\n });\n }, []);\n\n /**\n * @description 심층연구 모드 토글\n * @Todo vibecode - 심층연구 버튼 클릭 핸들러\n */\n const toggleDeepResearchMode = useCallback(() => {\n setIsDeepResearchMode((prev) => !prev);\n }, []);\n\n // ============================================================================\n // Send Message\n // ============================================================================\n\n const sendMessage = useCallback(async (content?: string, options?: { hiddenUserMessage?: boolean }) => {\n const messageContent = content || input;\n /** @Todo vibecode - 텍스트 없이 첨부파일만 전송 허용 */\n if ((!messageContent.trim() && attachments.length === 0) || isLoading) return;\n\n /** @Todo vibecode - 중복 전송 방지: entry guard 직후 즉시 로딩 상태 전환 */\n setIsLoading(true);\n\n let sessionId = currentSessionId;\n if (!sessionId) {\n /**\n * @description 세션 없이 메시지 전송 시 자동 세션 생성\n * @Todo vibecode - useExternalStorage 모드에서 onCreateSession 콜백 호출 보장\n */\n if (useExternalStorage && onCreateSessionRef.current) {\n try {\n const created = await onCreateSessionRef.current();\n const now = Date.now();\n const newSess: ChatSession = {\n id: created.id,\n title: created.title,\n messages: [],\n model: selectedModel,\n createdAt: now,\n updatedAt: now,\n };\n setSessions((prev) => [newSess, ...prev]);\n sessionId = newSess.id;\n setCurrentSessionId(sessionId);\n } catch (error) {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to create session'));\n setIsLoading(false);\n return;\n }\n } else {\n const now = Date.now();\n const newSess: ChatSession = {\n id: generateId('session'),\n title: '새 대화',\n messages: [],\n model: selectedModel,\n createdAt: now,\n updatedAt: now,\n };\n setSessions((prev) => [newSess, ...prev]);\n sessionId = newSess.id;\n setCurrentSessionId(sessionId);\n }\n }\n\n // 메시지 조합\n let finalContent = messageContent.trim();\n if (quotedText) {\n finalContent = `\"${quotedText}\"\\n\\n${finalContent}`;\n }\n if (selectedAction) {\n finalContent = `[${selectedAction.label}] ${finalContent}`;\n }\n\n const actionPrompt = selectedAction?.systemPrompt;\n const isHidden = options?.hiddenUserMessage ?? false;\n\n /**\n * @description 첨부파일 → contentParts 변환\n * @Todo vibecode - 텍스트 + 이미지/파일을 contentParts 배열로 구성\n */\n const currentAttachments = attachments;\n let userContentParts: MessageContentPart[] | undefined;\n if (currentAttachments.length > 0) {\n userContentParts = [];\n if (finalContent.trim()) {\n userContentParts.push({ type: 'text', content: finalContent });\n }\n for (const att of currentAttachments) {\n if (att.type === 'image' && att.previewUrl) {\n userContentParts.push({ type: 'image', url: att.previewUrl, alt: att.name });\n } else {\n userContentParts.push({ type: 'file', name: att.name, url: att.previewUrl || '', mimeType: att.mimeType, size: att.size });\n }\n }\n }\n\n const userMessage: ChatMessage = {\n id: generateId('msg'),\n role: 'user',\n content: finalContent,\n timestamp: Date.now(),\n ...(isHidden && { hidden: true }),\n ...(userContentParts && { contentParts: userContentParts }),\n };\n\n /**\n * @description 세션 상태 캡처 + 메시지 추가 (attachment 스킬 실행 전)\n * @Todo vibecode - React 상태 업데이트는 비동기이므로 setSessions 이전에 기존 상태 캡처 필수\n */\n const capturedSessionId = sessionId;\n const currentSession = sessions.find((s) => s.id === capturedSessionId);\n const existingMessages = currentSession?.messages || [];\n const isFirstMessage = !existingMessages.length;\n const contextSummary = currentSession?.compressionState?.contextSummary || currentSession?.contextSummary;\n const summaryAfterIndex = currentSession?.compressionState?.summaryAfterIndex || currentSession?.summaryAfterIndex || 0;\n let compressionCount = currentSession?.compressionState?.compressionCount || 0;\n\n const assistantMessageId = generateId('msg');\n const assistantMessage: ChatMessage = {\n id: assistantMessageId,\n role: 'assistant',\n content: '',\n model: selectedModel,\n timestamp: Date.now(),\n };\n\n // Clear input state\n setInput('');\n setQuotedText(null);\n setSelectedAction(null);\n setAttachments([]);\n\n // Add messages to session\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n const newMessages = [...s.messages, userMessage, assistantMessage];\n return {\n ...s,\n messages: newMessages,\n title: s.messages.length === 0 ? generateTitle([userMessage]) : s.title,\n updatedAt: Date.now(),\n };\n }\n return s;\n })\n );\n\n /**\n * @description attachment trigger 스킬 자동 실행 (로딩 → 완료 UI 전환 포함)\n * @Todo vibecode - 파일 첨부 시 trigger:'attachment' 스킬 찾아서 File 객체 전달\n */\n let attachmentResults: MessageContentPart[] = [];\n if (currentAttachments.length > 0) {\n const attachmentSkills = Object.entries(resolvedSkills).filter(\n ([, config]) => config.trigger === 'attachment'\n );\n\n for (const [skillName, skillConfig] of attachmentSkills) {\n /** @Todo vibecode - acceptedTypes MIME 매칭 (와일드카드, 확장자 지원) */\n const matchedFiles = currentAttachments.filter((att) => {\n if (!skillConfig.acceptedTypes || skillConfig.acceptedTypes.length === 0) return true;\n return skillConfig.acceptedTypes.some((type) => {\n if (type.startsWith('.')) return att.name.toLowerCase().endsWith(type.toLowerCase());\n if (type.includes('*')) {\n const regex = new RegExp('^' + type.replace('*', '.*') + '$');\n return regex.test(att.mimeType);\n }\n return att.mimeType === type;\n });\n });\n\n if (matchedFiles.length === 0) continue;\n\n /** @Todo vibecode - tool_loading 상태 표시 후 execute → tool_result로 전환 */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n contentParts: [...(m.contentParts || []), {\n type: 'tool_loading' as const,\n toolName: skillName,\n label: skillConfig.label,\n }],\n };\n }),\n };\n })\n );\n\n try {\n /** @Todo vibecode - autoConvertBase64 시 File → base64 자동 변환 */\n const filesToPass = skillConfig.autoConvertBase64\n ? await convertAttachmentsToBase64(matchedFiles)\n : matchedFiles;\n const result = await skillConfig.execute({ files: filesToPass, userMessage: finalContent });\n const toolResultPart: MessageContentPart = {\n type: 'tool_result',\n toolName: skillName,\n label: skillConfig.label,\n icon: skillConfig.icon,\n result: {\n type: 'text',\n content: result.content,\n metadata: result.metadata,\n sources: result.sources,\n },\n };\n attachmentResults.push(toolResultPart);\n\n /** @Todo vibecode - tool_loading → tool_result 전환 */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n contentParts: (m.contentParts || []).map((p) =>\n p.type === 'tool_loading' && (p as any).toolName === skillName ? toolResultPart : p\n ),\n };\n }),\n };\n })\n );\n } catch (error) {\n console.error(`[useChatUI] attachment skill ${skillName} failed:`, error);\n /** @Todo vibecode - 실패 시 tool_loading 제거 */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n contentParts: (m.contentParts || []).filter((p) =>\n !(p.type === 'tool_loading' && (p as any).toolName === skillName)\n ),\n };\n }),\n };\n })\n );\n }\n }\n }\n\n /**\n * @description attachment trigger 후 스트림 제어\n * @Todo vibecode - onSkillComplete 우선, continueAfterToolResult fallback\n */\n let shouldContinueAfterAttachment = continueAfterToolResult;\n if (attachmentResults.length > 0) {\n for (const part of attachmentResults) {\n if (part.type === 'tool_result' && onSkillCompleteRef.current) {\n const decision = onSkillCompleteRef.current(part.toolName, {\n content: part.result.content,\n metadata: part.result.metadata,\n sources: part.result.sources,\n });\n shouldContinueAfterAttachment = decision === 'continue';\n if (!shouldContinueAfterAttachment) break;\n }\n }\n }\n\n /**\n * @description 첫 메시지일 때 generateTitleCallback 호출\n * @Todo vibecode - 비동기 제목 생성 로직\n */\n if (isFirstMessage && generateTitleRef.current) {\n // 비동기로 제목 생성 (백그라운드에서 실행)\n Promise.resolve(generateTitleRef.current(finalContent))\n .then((generatedTitle) => {\n if (generatedTitle && generatedTitle.trim()) {\n setSessions((prev) =>\n prev.map((s) =>\n s.id === capturedSessionId\n ? { ...s, title: generatedTitle.trim(), updatedAt: Date.now() }\n : s\n )\n );\n onTitleChangeRef.current?.(capturedSessionId, generatedTitle.trim());\n }\n })\n .catch(() => {\n /* 제목 생성 실패 시 기존 제목 유지 */\n });\n }\n\n /**\n * @description attachment 결과만 표시하고 AI 호출 생략 (shouldContinueAfterAttachment === false)\n * @Todo vibecode - 'stop' 시 contentParts에 결과가 이미 있으므로 추가 AI 호출 불필요\n */\n if (attachmentResults.length > 0 && !shouldContinueAfterAttachment) {\n setIsLoading(false);\n return;\n }\n\n abortControllerRef.current = new AbortController();\n\n try {\n /**\n * @description skipNextSkillParsing 플래그를 로컬 변수로 캡처 후 즉시 리셋\n * @Todo vibecode - ref가 true로 남아 후속 sendMessage에서 skill 파싱이 영구 스킵되는 버그 방지\n * 이전 스킬 실행이 설정한 플래그를 이번 호출에서 소비하고, ref는 즉시 초기화\n */\n const shouldSkipSkillParsing = skipNextSkillParsingRef.current;\n skipNextSkillParsingRef.current = false;\n\n /**\n * @description 위에서 캡처한 existingMessages, contextSummary 등을 사용\n * @Todo vibecode - stale closure 방지를 위해 이미 캡처된 값 사용\n */\n let messagesToSend = [...existingMessages, userMessage];\n\n // Context compression (점진적 압축 지원)\n const recompressionThreshold = DEFAULT_RECOMPRESSION_THRESHOLD;\n const tokenLimit = DEFAULT_TOKEN_LIMIT;\n\n let currentContextSummary = contextSummary;\n\n // 새 메시지 수 계산\n const newMessageCount = messagesToSend.length - summaryAfterIndex;\n // 토큰 추정\n const estimatedTokensCount = estimateTokens(messagesToSend);\n\n // 압축 조건: 초기 압축 또는 재압축\n const needsInitialCompression =\n !currentContextSummary && messagesToSend.length > contextCompressionThreshold;\n const needsRecompression =\n currentContextSummary &&\n (newMessageCount > recompressionThreshold ||\n estimatedTokensCount > tokenLimit * 0.7);\n\n if (needsInitialCompression || needsRecompression) {\n const toCompress = messagesToSend.slice(0, -keepRecentMessages);\n let summary: string;\n\n if (needsRecompression && currentContextSummary) {\n // 점진적 압축: 기존 요약 + 새 대화\n const newMessages = toCompress.slice(summaryAfterIndex);\n summary = await incrementalCompressContext(currentContextSummary, newMessages, selectedModel);\n } else {\n // 초기 압축\n summary = await compressContext(toCompress, selectedModel);\n }\n\n if (summary) {\n currentContextSummary = summary;\n compressionCount += 1;\n setSessions((prev) =>\n prev.map((s) =>\n s.id === capturedSessionId\n ? {\n ...s,\n contextSummary: summary,\n summaryAfterIndex: toCompress.length,\n compressionState: {\n contextSummary: summary,\n summaryAfterIndex: toCompress.length,\n compressionCount,\n lastCompressionAt: Date.now(),\n },\n }\n : s\n )\n );\n\n // 압축 시점에 정보 추출 (백그라운드)\n if (enableAutoExtraction && globalMemory) {\n const messagesForExtraction = toCompress.map((m) => ({\n role: m.role,\n content: m.content,\n }));\n // 비동기로 실행, 결과를 기다리지 않음\n infoExtraction.extractInfo(messagesForExtraction).catch(() => {\n /* @Todo vibecode - 정보 추출 실패 시 무시 */\n });\n }\n }\n }\n\n // Build chat messages\n let chatMessages: { role: 'user' | 'assistant' | 'system'; content: string }[];\n if (currentContextSummary) {\n const recentMessages = messagesToSend.slice(-keepRecentMessages);\n chatMessages = [\n { role: 'system', content: `[이전 대화 요약]\\n${currentContextSummary}` },\n ...recentMessages.map((m) => ({ role: m.role, content: m.content })),\n ];\n } else {\n chatMessages = messagesToSend.map((m) => ({ role: m.role, content: m.content }));\n }\n\n /**\n * @description attachment 스킬 결과를 AI 컨텍스트에 주입\n * @Todo vibecode - contentParts의 tool_result 내용을 chatMessages에 추가 (API 전용, UI 미저장)\n */\n if (attachmentResults.length > 0 && shouldContinueAfterAttachment) {\n /** @Todo vibecode - attachment 결과 기반 AI 응답에서 skill_use 태그 파싱 방지 */\n skipNextSkillParsingRef.current = true;\n const attachmentContext = attachmentResults\n .filter((part) => part.type === 'tool_result')\n .map((part) => `[${(part as any).label || (part as any).toolName} 결과]\\n${(part as any).result.content}`)\n .join('\\n\\n');\n if (attachmentContext) {\n chatMessages.push({\n role: 'user',\n /** @Todo vibecode - 원본 파일 재요청 방지 + skill_use 태그 사용 금지 명시 */\n content: `사용자가 첨부한 파일의 분석 결과입니다. 원본 파일 내용이 이미 아래에 포함되어 있으므로 원본 파일을 다시 요청하지 마세요.\\n\\n${attachmentContext}\\n\\n위 분석 결과만으로 사용자의 질문에 답변해주세요. skill_use 태그는 사용하지 마세요.`,\n });\n }\n }\n\n console.log('[ChatUI] Messages to send:', chatMessages.length, chatMessages.map(m => ({ role: m.role, content: m.content.slice(0, 50) })));\n\n // Build system prompt\n const baseSystemPrompt = buildSystemPrompt();\n const combinedSystemPrompt = [baseSystemPrompt, actionPrompt].filter(Boolean).join('\\n\\n');\n const messagesForApi = combinedSystemPrompt\n ? [{ role: 'system' as const, content: combinedSystemPrompt }, ...chatMessages]\n : chatMessages;\n\n // Get provider\n const modelConfig = models.find((m) => m.id === selectedModel);\n const provider = modelConfig?.provider || 'ollama';\n\n // Send request\n let response: Response;\n /** @Todo vibecode - ref 패턴으로 stale closure 방지 */\n if (onSendMessageRef.current) {\n const result = await onSendMessageRef.current({\n messages: messagesForApi,\n model: selectedModel,\n provider,\n apiKey,\n systemPrompt: combinedSystemPrompt,\n });\n\n if (typeof result === 'string') {\n // Direct string response\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) =>\n m.id === assistantMessageId ? { ...m, content: result } : m\n ),\n };\n }\n return s;\n })\n );\n return;\n }\n\n // Check for structured response with sources\n if (typeof result === 'object' && 'content' in result) {\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) =>\n m.id === assistantMessageId\n ? { ...m, content: result.content, sources: result.sources }\n : m\n ),\n };\n }\n return s;\n })\n );\n return;\n }\n\n // Create fake response from stream\n response = new Response(result as ReadableStream<Uint8Array>);\n } else {\n /**\n * @description Ollama는 직접 API 호출, 다른 provider는 프록시 경유\n * @Todo vibecode - provider별 요청 포맷 분기\n */\n const isOllama = provider === 'ollama' || apiEndpoint.includes('ollama') || apiEndpoint.includes('11434');\n const requestBody = isOllama\n ? { model: selectedModel, messages: messagesForApi, stream: true }\n : {\n messages: messagesForApi,\n model: selectedModel,\n provider,\n apiKey: provider === 'devdive' ? apiKey : undefined,\n stream: true,\n };\n\n response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(requestBody),\n signal: abortControllerRef.current.signal,\n });\n }\n\n if (!response.ok) throw new Error('API error');\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader');\n\n const decoder = new TextDecoder();\n let buffer = '';\n /** @Todo vibecode - 스트리밍 중 누적 content (stale closure 방지용) */\n let accumulatedContent = '';\n /**\n * @description </skill_use> 태그 감지 플래그\n * @Todo vibecode - 스트리밍 중 스킬 태그 닫힘 감지 시 즉시 중단\n */\n let skillTagDetected = false;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.trim()) continue;\n\n /**\n * @description SSE 형식 (data: ...) 또는 Ollama NDJSON 형식 처리\n * @Todo vibecode - 스트리밍 포맷 호환성\n */\n let data = line;\n if (line.startsWith('data: ')) {\n data = line.slice(6);\n if (data === '[DONE]') continue;\n }\n\n try {\n const parsed = JSON.parse(data);\n\n /**\n * @description Ollama 형식 처리 (thinking 모델 지원)\n * @Todo vibecode - thinking 필드가 있으면 <thinking> 태그로 감싸서 표시\n */\n const content = parsed.message?.content || parsed.content || parsed.text || '';\n const thinking = parsed.message?.thinking || '';\n\n // content 또는 thinking이 있으면 추가\n if (content || thinking) {\n /** @Todo vibecode - 로컬 변수에도 누적 (stale closure 방지) */\n if (content) accumulatedContent += content;\n\n /**\n * @description </skill_use> 닫힘 태그 감지 시 스트림 즉시 트런케이트\n * @Todo vibecode - 태그 이후 불필요한 AI 텍스트 차단 (이미지 설명 반복 방지)\n */\n if (!shouldSkipSkillParsing && accumulatedContent.includes('</skill_use>')) {\n const endIdx = accumulatedContent.indexOf('</skill_use>');\n accumulatedContent = accumulatedContent.substring(0, endIdx + '</skill_use>'.length);\n skillTagDetected = true;\n }\n\n /** @Todo vibecode - skillTag 감지 시 트런케이트된 content로 세션 업데이트 */\n const displayContent = skillTagDetected ? accumulatedContent : null;\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n\n /** @Todo vibecode - 트런케이트 시 전체 교체, 아니면 기존 누적 */\n if (displayContent) {\n return { ...m, content: displayContent };\n }\n\n let newContent = m.content;\n\n // thinking 처리: <thinking> 태그 안에 추가\n if (thinking) {\n if (!newContent.includes('<thinking>')) {\n newContent = '<thinking>' + thinking;\n } else if (!newContent.includes('</thinking>')) {\n // 아직 닫히지 않은 thinking 블록에 추가\n newContent += thinking;\n }\n }\n\n // content 처리: thinking 블록 닫고 실제 내용 추가\n if (content) {\n if (newContent.includes('<thinking>') && !newContent.includes('</thinking>')) {\n newContent += '</thinking>\\n\\n';\n }\n newContent += content;\n }\n\n return { ...m, content: newContent };\n }),\n };\n }\n return s;\n })\n );\n\n /** @Todo vibecode - skillTag 감지 후 for 루프 탈출 */\n if (skillTagDetected) break;\n }\n\n } catch {\n // Ignore parse errors\n }\n }\n\n /** @Todo vibecode - skillTag 감지 후 while 루프 탈출 (스트리밍 중단) */\n if (skillTagDetected) break;\n }\n\n /**\n * @description 남은 버퍼 처리\n * @Todo vibecode - 마지막 줄이 개행 없이 끝나는 경우\n */\n if (buffer.trim()) {\n try {\n const parsed = JSON.parse(buffer);\n const content = parsed.message?.content || parsed.content || parsed.text;\n if (content) {\n /** @Todo vibecode - 남은 버퍼도 로컬 변수에 누적 */\n accumulatedContent += content;\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) =>\n m.id === assistantMessageId\n ? { ...m, content: m.content + content }\n : m\n ),\n };\n }\n return s;\n })\n );\n }\n } catch {\n // Ignore parse errors\n }\n }\n\n /**\n * @description AI 응답에서 Skill 호출 감지 및 실행\n * @Todo vibecode - <skill_use> 태그 파싱 → 스킬 실행 (onProgress/onStream 콜백 연결)\n * 고도화: 스트리밍 보고서 스킬은 hidden 메시지 불필요, 단순 스킬은 기존 흐름 유지\n */\n if (!shouldSkipSkillParsing) {\n /** @Todo vibecode - accumulatedContent 사용 (stale closure 방지) */\n const assistantContent = accumulatedContent;\n\n const { skillCall: detectedSkill, cleanContent: skillCleanContent } =\n parseSkillCallFromContent(assistantContent);\n\n if (detectedSkill && resolvedSkills[detectedSkill.name]) {\n /** @Todo vibecode - skill_use 태그 제거 + 실행 상태 첨부 */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n content: skillCleanContent,\n skillExecution: {\n skillName: detectedSkill.name,\n params: detectedSkill.params,\n status: 'executing' as const,\n },\n };\n }),\n };\n })\n );\n\n /**\n * @Todo vibecode - 스킬 실행 (onProgress/onStream 콜백으로 실시간 UI 업데이트)\n * onStream이 호출되면 보고서가 스킬 내부에서 이미 생성된 것이므로 hidden 메시지 불필요\n */\n let streamedReport = '';\n const { result } = await handleSkillCall(assistantContent, {\n onProgress: (progress) => {\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n skillExecution: { ...m.skillExecution!, progress },\n };\n }),\n };\n })\n );\n },\n onStream: (chunk) => {\n streamedReport += chunk;\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return { ...m, content: streamedReport };\n }),\n };\n })\n );\n },\n signal: abortControllerRef.current?.signal,\n });\n\n if (result) {\n /**\n * @description 도구 결과 처리 (metadata.__toolResult__ 플래그로 식별)\n * @Todo vibecode - 도구 결과를 contentParts로 변환 + AI 피드백 전송\n */\n if (result.metadata?.__toolResult__) {\n const resultType = result.metadata.resultType as string;\n const toolName = result.metadata.toolName as string;\n const toolLabel = result.metadata.toolLabel as string | undefined;\n const toolIcon = result.metadata.toolIcon as string | undefined;\n\n /**\n * @Todo vibecode - 도구 결과를 tool_result 타입으로 통일\n * ToolStatusCard에서 상태 표시 + 접이식 소스 렌더링\n */\n const parts: MessageContentPart[] = [];\n if (skillCleanContent.trim()) {\n parts.push({ type: 'text', content: skillCleanContent });\n }\n\n parts.push({\n type: 'tool_result',\n toolName,\n label: toolLabel,\n icon: toolIcon,\n result: {\n type: resultType as 'text' | 'image' | 'file' | 'error',\n content: result.content,\n metadata: result.metadata,\n sources: result.sources,\n },\n });\n\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n contentParts: parts,\n skillExecution: {\n ...m.skillExecution!,\n status: 'done' as const,\n result,\n },\n };\n }),\n };\n })\n );\n\n /**\n * @description 이미지/파일 결과는 후속 API 호출 생략 (자체 완결)\n * @Todo vibecode - 이미지는 contentParts로 직접 표시, 텍스트 결과만 AI 피드백 필요\n */\n if (resultType === 'image' || resultType === 'file') {\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n\n /**\n * @description 도구 실행 후 스트림 제어\n * @Todo vibecode - onSkillComplete 콜백 또는 continueAfterToolResult 옵션으로 중단 결정\n */\n let shouldContinue = continueAfterToolResult;\n if (onSkillCompleteRef.current) {\n const decision = onSkillCompleteRef.current(toolName, result);\n shouldContinue = decision === 'continue';\n }\n\n if (!shouldContinue) {\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n\n skipNextSkillParsingRef.current = true;\n const feedbackPrompt = resultType === 'error'\n ? `도구 \"${toolName}\" 실행 중 오류 발생: ${result.content}\\n\\n사용자에게 오류를 안내해주세요. skill_use 태그는 사용하지 마세요.`\n : `도구 \"${toolName}\" 결과:\\n\\n${result.content}\\n\\n위 결과를 바탕으로 답변해주세요. skill_use 태그는 사용하지 마세요.`;\n setTimeout(() => {\n sendMessage(feedbackPrompt, { hiddenUserMessage: true });\n }, 100);\n\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n\n /** @Todo vibecode - 실행 완료 상태 + sources 저장 */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n sources: result.sources || m.sources,\n skillExecution: {\n ...m.skillExecution!,\n status: 'done' as const,\n result,\n },\n };\n }),\n };\n })\n );\n\n if (streamedReport) {\n /**\n * @Todo vibecode - 스트리밍 보고서 완료: hidden 메시지 불필요\n * 보고서가 스킬 내부 LLM에서 이미 생성되어 onStream으로 전달됨\n */\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n\n /**\n * @description 일반 스킬 완료 후 스트림 제어\n * @Todo vibecode - onSkillComplete / continueAfterToolResult로 중단 결정\n */\n let shouldContinueSkill = continueAfterToolResult;\n if (onSkillCompleteRef.current) {\n const decision = onSkillCompleteRef.current(detectedSkill.name, result);\n shouldContinueSkill = decision === 'continue';\n }\n\n if (!shouldContinueSkill) {\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n\n /** @Todo vibecode - 단순 스킬: 결과를 hidden 메시지로 AI에 전달하여 최종 응답 생성 */\n skipNextSkillParsingRef.current = true;\n const resultPrompt = `스킬 \"${detectedSkill.name}\" 실행 결과:\\n\\n${result.content}\\n\\n위 결과를 바탕으로 사용자의 원래 질문에 답변해주세요. skill_use 태그는 사용하지 마세요.`;\n setTimeout(() => {\n sendMessage(resultPrompt, { hiddenUserMessage: true });\n }, 100);\n\n /** @Todo vibecode - 스킬 실행 후에는 poll 파싱도 스킵 (최종 응답에서만 파싱) */\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n }\n }\n\n /**\n * @description AI 응답에서 Poll 파싱\n * @Todo vibecode - <poll> 태그 감지 및 pollBlock 추가\n * Poll 응답 직후에는 파싱 스킵하되, 태그는 항상 제거\n */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n const { pollBlock, cleanContent } = parsePollFromContent(m.content);\n // poll 태그는 항상 제거, 단 skipNextPollParsing이면 pollBlock은 추가 안 함\n if (skipNextPollParsingRef.current) {\n skipNextPollParsingRef.current = false;\n return { ...m, content: cleanContent }; // 태그만 제거, pollBlock 없음\n }\n if (pollBlock) {\n return { ...m, content: cleanContent, pollBlock };\n }\n return m;\n }),\n };\n })\n );\n\n /**\n * @description 외부 스토리지에 메시지 저장 + localStorage 캐시 동시 저장\n * @Todo vibecode - accumulatedContent 사용 (stale closure 방지), 캐시로 fallback 복원 보장\n */\n if (useExternalStorage && capturedSessionId) {\n /** @Todo vibecode - stale closure 방지: sessions.find() 대신 accumulatedContent 직접 사용 */\n const assistantContentForSave = accumulatedContent;\n\n if (assistantContentForSave && onSaveMessagesRef.current) {\n /**\n * @Todo vibecode - contentParts 포함 저장 (이미지/파일 등 복원용)\n * sessionsRef에서 최신 메시지를 가져와 contentParts 추출\n */\n const latestSession = sessionsRef.current.find((s) => s.id === capturedSessionId);\n const latestMessages = latestSession?.messages || [];\n const userMsg = latestMessages.find((m) => m.role === 'user' && m.content === finalContent);\n const assistantMsg = [...latestMessages].reverse().find((m: ChatMessage) => m.role === 'assistant');\n\n const messagesToSave = [\n { role: 'user' as const, message: finalContent, ...(userMsg?.contentParts && { contentParts: userMsg.contentParts }) },\n { role: 'assistant' as const, message: assistantContentForSave, ...(assistantMsg?.contentParts && { contentParts: assistantMsg.contentParts }) },\n ];\n\n onSaveMessagesRef.current!(capturedSessionId, messagesToSave).catch((saveError) => {\n console.error('[useChatUI] Failed to save messages:', saveError);\n });\n }\n\n /** @Todo vibecode - localStorage 캐시 저장 (sessionsRef로 최신 상태 접근) */\n queueMicrotask(() => {\n const sessionToCache = sessionsRef.current.find((s) => s.id === capturedSessionId);\n if (sessionToCache && sessionToCache.messages.length > 0) {\n writeSessionCache(storageKey, sessionToCache);\n }\n });\n }\n /**\n * @description 주기적 정보 추출 (매 4개 메시지 = 약 2회 대화마다)\n * @Todo vibecode - 압축 시점까지 기다리지 않고 조기에 메모리 축적\n */\n if (enableAutoExtraction && globalMemory) {\n const currentMsgCount = existingMessages.length + 2; // +user +assistant\n const sinceLastExtraction = currentMsgCount - lastExtractionMsgCountRef.current;\n if (sinceLastExtraction >= 4) {\n lastExtractionMsgCountRef.current = currentMsgCount;\n const recentForExtraction = [...existingMessages.slice(-6), userMessage].map(\n (m) => ({ role: m.role, content: m.content })\n );\n infoExtraction.extractInfo(recentForExtraction).catch(() => {\n /* @Todo vibecode - 정보 추출 실패 시 무시 */\n });\n }\n }\n\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n return;\n }\n const err = error instanceof Error ? error : new Error('Unknown error');\n onErrorRef.current?.(err);\n\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) =>\n m.id === assistantMessageId\n ? { ...m, content: '오류가 발생했습니다. 다시 시도해주세요.' }\n : m\n ),\n };\n }\n return s;\n })\n );\n } finally {\n setIsLoading(false);\n abortControllerRef.current = null;\n }\n }, [\n input,\n isLoading,\n currentSessionId,\n sessions,\n selectedModel,\n quotedText,\n selectedAction,\n apiEndpoint,\n apiKey,\n models,\n contextCompressionThreshold,\n keepRecentMessages,\n buildSystemPrompt,\n compressContext,\n useExternalStorage,\n handleSkillCall,\n resolvedSkills,\n /** @Todo vibecode - attachments, continueAfterToolResult를 deps에 추가하여 stale closure 방지 */\n attachments,\n continueAfterToolResult,\n ]);\n\n /**\n * @description Poll 응답 처리 (여러 질문의 응답)\n * @Todo vibecode - 사용자가 모든 선택지 선택 완료 시 호출\n * 상태 업데이트와 메시지 발송을 분리하여 순서대로 실행\n */\n const handlePollSubmit = useCallback(\n (messageId: string, responses: PollResponse[]) => {\n // 1. 현재 세션에서 해당 메시지의 pollBlock 정보 추출\n const currentSess = sessions.find((s) => s.id === currentSessionId);\n const targetMessage = currentSess?.messages.find((m) => m.id === messageId);\n if (!targetMessage?.pollBlock) return;\n\n const pollBlock = targetMessage.pollBlock;\n\n // 2. 응답 포맷팅\n const formattedParts: string[] = [];\n responses.forEach((response) => {\n const question = pollBlock.questions.find((q) => q.id === response.questionId);\n if (!question) return;\n if (response.skipped || (response.selectedOptions.length === 0 && !response.otherText)) return;\n\n const formatted = formatPollResponse(question, response.selectedOptions, response.otherText);\n formattedParts.push(`- ${question.question}: ${formatted}`);\n });\n\n const hasValidResponses = formattedParts.length > 0;\n const isAutoGenerate = responses.every((r) => r.skipped);\n\n // 3. pollBlock 제거 + 안내 메시지 직접 추가\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== currentSessionId) return s;\n const updatedMessages = s.messages.map((m) => {\n if (m.id !== messageId) return m;\n return { ...m, pollBlock: undefined };\n });\n\n /**\n * @description 안내 메시지를 assistant로 직접 추가\n * @Todo vibecode - API 호출 없이 즉시 표시\n */\n updatedMessages.push({\n id: generateId('msg'),\n role: 'assistant',\n content: isAutoGenerate\n ? '자동으로 최적의 옵션을 선택하여 응답하겠습니다. 이제 시작하겠습니다.'\n : '선택하신 내용을 기반으로 응답하겠습니다. 이제 시작하겠습니다.',\n model: selectedModel,\n timestamp: Date.now(),\n });\n\n return { ...s, messages: updatedMessages };\n })\n );\n\n // 4. 숨겨진 프롬프트로 실제 답변 요청 (유저에게 안 보임)\n skipNextPollParsingRef.current = true;\n const hiddenPrompt = isAutoGenerate\n ? '사용자가 직접 선택하지 않고 자동생성을 요청했습니다. 원래 요청에 대해 가장 적절한 옵션을 스스로 판단하여 구체적이고 실질적으로 답변해주세요. poll 태그는 사용하지 마세요.'\n : `사용자의 선택 결과:\\n${formattedParts.join('\\n')}\\n\\n위 선택을 반영하여 원래 요청에 대해 구체적이고 실질적으로 답변해주세요. poll 태그는 사용하지 마세요.`;\n setTimeout(() => {\n sendMessage(hiddenPrompt, { hiddenUserMessage: true });\n }, 100);\n },\n [sessions, currentSessionId, selectedModel, sendMessage]\n );\n\n // ============================================================================\n // Edit & Regenerate\n // ============================================================================\n\n const saveEdit = useCallback(async (content: string) => {\n if (!editingMessageId || !currentSession || !currentSessionId) return;\n\n const messageIndex = currentSession.messages.findIndex((m) => m.id === editingMessageId);\n if (messageIndex === -1) return;\n\n const capturedSessionId = currentSessionId;\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n const newMessages = s.messages.slice(0, messageIndex);\n return { ...s, messages: newMessages, updatedAt: Date.now() };\n }\n return s;\n })\n );\n\n setEditingMessageId(null);\n await sendMessage(content);\n }, [editingMessageId, currentSession, currentSessionId, sendMessage]);\n\n const regenerate = useCallback(async (messageId: string) => {\n console.log('[ChatUI] Regenerate called:', { messageId, currentSessionId, isLoading });\n if (!currentSession || !currentSessionId || isLoading) {\n console.log('[ChatUI] Regenerate early return - missing session or loading');\n return;\n }\n\n const assistantIndex = currentSession.messages.findIndex((m) => m.id === messageId);\n console.log('[ChatUI] Assistant index:', assistantIndex);\n if (assistantIndex === -1) return;\n\n const userMessage = currentSession.messages[assistantIndex - 1];\n console.log('[ChatUI] User message:', userMessage?.content?.slice(0, 50));\n if (!userMessage || userMessage.role !== 'user') return;\n\n const capturedSessionId = currentSessionId;\n\n /**\n * @description user 메시지는 유지하고 assistant 메시지만 제거 후 재생성\n * @Todo vibecode - 기존 user 메시지 유지, assistant 응답만 재생성\n */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n // user 메시지까지만 유지 (assistant 메시지 제거)\n return {\n ...s,\n messages: s.messages.slice(0, assistantIndex),\n updatedAt: Date.now(),\n };\n }\n return s;\n })\n );\n\n // 기존 user 메시지의 content로 재생성 (새 user 메시지 추가하지 않음)\n // sendMessage 대신 직접 API 호출하여 assistant 응답만 생성\n setIsLoading(true);\n abortControllerRef.current = new AbortController();\n\n try {\n const assistantMessageId = `msg_${Date.now()}_assistant`;\n\n // 빈 assistant 메시지 추가\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: [\n ...s.messages,\n {\n id: assistantMessageId,\n role: 'assistant' as const,\n content: '',\n model: selectedModel,\n timestamp: Date.now(),\n },\n ],\n };\n }\n return s;\n })\n );\n\n // 메시지 준비\n const messagesUpToUser = currentSession.messages.slice(0, assistantIndex);\n const chatMessages = messagesUpToUser.map((m) => ({ role: m.role, content: m.content }));\n const baseSystemPrompt = buildSystemPrompt();\n const messagesForApi = baseSystemPrompt\n ? [{ role: 'system' as const, content: baseSystemPrompt }, ...chatMessages]\n : chatMessages;\n\n const modelConfig = models.find((m) => m.id === selectedModel);\n const provider = modelConfig?.provider || 'ollama';\n\n /**\n * @description Ollama는 직접 API 호출, 다른 provider는 프록시 경유\n * @Todo vibecode - provider별 요청 포맷 분기\n */\n const isOllama = provider === 'ollama' || apiEndpoint.includes('ollama') || apiEndpoint.includes('11434');\n const requestBody = isOllama\n ? { model: selectedModel, messages: messagesForApi, stream: true }\n : {\n messages: messagesForApi,\n model: selectedModel,\n provider,\n apiKey: provider === 'devdive' ? apiKey : undefined,\n stream: true,\n };\n\n console.log('[ChatUI] Regenerate fetch:', { apiEndpoint, isOllama, model: selectedModel });\n\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(requestBody),\n signal: abortControllerRef.current.signal,\n });\n\n console.log('[ChatUI] Regenerate response status:', response.status);\n if (!response.ok) throw new Error(`API error: ${response.status}`);\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.trim()) continue;\n\n let data = line;\n if (line.startsWith('data: ')) {\n data = line.slice(6);\n if (data === '[DONE]') continue;\n }\n\n try {\n const parsed = JSON.parse(data);\n const content = parsed.message?.content || parsed.content || parsed.text || '';\n const thinking = parsed.message?.thinking || '';\n\n if (content || thinking) {\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n\n let newContent = m.content;\n if (thinking) {\n if (!newContent.includes('<thinking>')) {\n newContent = '<thinking>' + thinking;\n } else if (!newContent.includes('</thinking>')) {\n newContent += thinking;\n }\n }\n if (content) {\n if (newContent.includes('<thinking>') && !newContent.includes('</thinking>')) {\n newContent += '</thinking>\\n\\n';\n }\n newContent += content;\n }\n return { ...m, content: newContent };\n }),\n };\n }\n return s;\n })\n );\n }\n } catch {\n // Ignore parse errors\n }\n }\n }\n\n // 남은 버퍼 처리\n if (buffer.trim()) {\n try {\n const parsed = JSON.parse(buffer);\n const content = parsed.message?.content || parsed.content || parsed.text || '';\n const thinking = parsed.message?.thinking || '';\n if (content || thinking) {\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n let newContent = m.content;\n if (thinking) {\n if (!newContent.includes('<thinking>')) {\n newContent = '<thinking>' + thinking;\n } else if (!newContent.includes('</thinking>')) {\n newContent += thinking;\n }\n }\n if (content) {\n if (newContent.includes('<thinking>') && !newContent.includes('</thinking>')) {\n newContent += '</thinking>\\n\\n';\n }\n newContent += content;\n }\n return { ...m, content: newContent };\n }),\n };\n }\n return s;\n })\n );\n }\n } catch {\n // Ignore parse errors\n }\n }\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n return;\n }\n console.error('[ChatUI] Regenerate error:', error);\n // 에러 발생 시에도 빈 assistant 메시지는 유지 (UI에서 에러 상태 표시)\n onErrorRef.current?.(error instanceof Error ? error : new Error('Unknown error'));\n } finally {\n setIsLoading(false);\n }\n }, [currentSession, currentSessionId, isLoading, selectedModel, models, apiEndpoint, apiKey, buildSystemPrompt]);\n\n // ============================================================================\n // Ask Other Model (Alternative Response)\n // ============================================================================\n\n const askOtherModel = useCallback(async (messageId: string, targetModel: string) => {\n if (!currentSession || !currentSessionId || isLoading) return;\n\n // Find the assistant message\n const assistantIndex = currentSession.messages.findIndex((m) => m.id === messageId);\n if (assistantIndex === -1) return;\n\n const assistantMessage = currentSession.messages[assistantIndex];\n if (assistantMessage.role !== 'assistant') return;\n\n // Find the user message before this assistant message\n const userMessage = currentSession.messages[assistantIndex - 1];\n if (!userMessage || userMessage.role !== 'user') return;\n\n setIsLoading(true);\n setLoadingAlternativeFor(messageId);\n abortControllerRef.current = new AbortController();\n\n try {\n // Build messages to send (all messages up to and including user message)\n const messagesToSend = currentSession.messages.slice(0, assistantIndex);\n\n // Build chat messages\n let chatMessages: { role: 'user' | 'assistant' | 'system'; content: string }[];\n if (currentSession.contextSummary) {\n const recentMessages = messagesToSend.slice(-keepRecentMessages);\n chatMessages = [\n { role: 'system', content: `[이전 대화 요약]\\n${currentSession.contextSummary}` },\n ...recentMessages.map((m) => ({ role: m.role, content: m.content })),\n ];\n } else {\n chatMessages = messagesToSend.map((m) => ({ role: m.role, content: m.content }));\n }\n\n // Build system prompt\n const baseSystemPrompt = buildSystemPrompt();\n const messagesForApi = baseSystemPrompt\n ? [{ role: 'system' as const, content: baseSystemPrompt }, ...chatMessages]\n : chatMessages;\n\n // Get provider for target model\n const modelConfig = models.find((m) => m.id === targetModel);\n const provider = modelConfig?.provider || 'ollama';\n\n // Collect response content and sources\n let responseContent = '';\n let responseSources: import('../types').SourceItem[] | undefined;\n\n /** @Todo vibecode - ref 패턴으로 stale closure 방지 (poll 경로) */\n if (onSendMessageRef.current) {\n const result = await onSendMessageRef.current({\n messages: messagesForApi,\n model: targetModel,\n provider,\n apiKey,\n systemPrompt: baseSystemPrompt,\n });\n\n if (typeof result === 'string') {\n responseContent = result;\n } else if (typeof result === 'object' && 'content' in result) {\n // Structured response with sources\n responseContent = result.content;\n responseSources = result.sources;\n } else {\n // Stream response\n const reader = (result as ReadableStream<Uint8Array>).getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n try {\n const parsed = JSON.parse(data);\n { const chunk = parsed.content ?? parsed.text ?? ''; if (chunk) responseContent += chunk; }\n } catch {\n // Ignore parse errors\n }\n }\n }\n }\n }\n } else {\n /**\n * @description Ollama는 직접 API 호출, 다른 provider는 프록시 경유\n * @Todo vibecode - provider별 요청 포맷 분기\n */\n const isOllama = provider === 'ollama' || apiEndpoint.includes('ollama') || apiEndpoint.includes('11434');\n const requestBody = isOllama\n ? { model: targetModel, messages: messagesForApi, stream: true }\n : {\n messages: messagesForApi,\n model: targetModel,\n provider,\n apiKey: provider === 'devdive' ? apiKey : undefined,\n stream: true,\n };\n\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(requestBody),\n signal: abortControllerRef.current.signal,\n });\n\n if (!response.ok) throw new Error('API error');\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n try {\n const parsed = JSON.parse(data);\n { const chunk = parsed.content ?? parsed.text ?? ''; if (chunk) responseContent += chunk; }\n } catch {\n // Ignore parse errors\n }\n }\n }\n }\n }\n\n // Add alternative to the assistant message\n const alternative = {\n id: generateId('alt'),\n model: targetModel,\n content: responseContent,\n timestamp: Date.now(),\n sources: responseSources,\n };\n\n const capturedSessionId = currentSessionId;\n\n // 현재 alternatives 개수 계산 (새 응답의 인덱스 결정용)\n const currentAltsCount = currentSession.messages.find(m => m.id === messageId)?.alternatives?.length || 0;\n const newAlternativeIndex = currentAltsCount + 1; // 0은 원본, 1부터 alternatives\n\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id === messageId) {\n const existingAlts = m.alternatives || [];\n return {\n ...m,\n alternatives: [...existingAlts, alternative],\n };\n }\n return m;\n }),\n updatedAt: Date.now(),\n };\n }\n return s;\n })\n );\n\n // 새 응답으로 자동 이동\n setActiveAlternatives((prev) => ({\n ...prev,\n [messageId]: newAlternativeIndex,\n }));\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n return;\n }\n const err = error instanceof Error ? error : new Error('Unknown error');\n onErrorRef.current?.(err);\n } finally {\n setIsLoading(false);\n setLoadingAlternativeFor(null);\n abortControllerRef.current = null;\n }\n }, [\n currentSession,\n currentSessionId,\n isLoading,\n keepRecentMessages,\n buildSystemPrompt,\n models,\n apiEndpoint,\n apiKey,\n onSendMessage,\n onError,\n ]);\n\n // ============================================================================\n // Alternative Navigation\n // ============================================================================\n\n const setActiveAlternative = useCallback((assistantMessageId: string, index: number) => {\n setActiveAlternatives((prev) => ({\n ...prev,\n [assistantMessageId]: index,\n }));\n }, []);\n\n const getActiveAlternative = useCallback((assistantMessageId: string): number => {\n return activeAlternatives[assistantMessageId] ?? 0;\n }, [activeAlternatives]);\n\n // ============================================================================\n // Return\n // ============================================================================\n\n return {\n // State (enableProjects 시 프로젝트별 필터링된 세션)\n sessions: enableProjects ? visibleSessions : sessions,\n currentSession,\n currentSessionId,\n messages,\n input,\n isLoading,\n selectedModel,\n sidebarOpen,\n settingsOpen,\n quotedText,\n selectedAction,\n copiedMessageId,\n editingMessageId,\n personalization,\n activeAlternatives,\n loadingAlternativeFor,\n\n // Actions\n setInput,\n sendMessage,\n stopGeneration,\n newSession,\n selectSession,\n deleteSession,\n renameSession,\n setModel,\n toggleSidebar,\n openSettings,\n closeSettings,\n setQuotedText,\n setSelectedAction,\n copyMessage,\n startEdit,\n cancelEdit,\n saveEdit,\n regenerate,\n askOtherModel,\n setActiveAlternative,\n getActiveAlternative,\n updatePersonalization,\n savePersonalization,\n models: effectiveModels,\n isModelsLoading,\n\n // Memory\n globalMemory,\n compressionState,\n extractUserInfo: async () => {\n if (!enableAutoExtraction || !globalMemory) return;\n const recentMessages = messages.slice(-10).map((m) => ({\n role: m.role,\n content: m.content,\n }));\n await infoExtraction.extractInfo(recentMessages);\n },\n\n // External Storage Loading States\n /**\n * @description 세션 목록 로딩 상태\n * @Todo vibecode - 외부 스토리지 사용 시\n */\n isSessionsLoading,\n /**\n * @description 단일 세션 로딩 상태\n * @Todo vibecode - 외부 스토리지 사용 시\n */\n isSessionLoading,\n\n // Deep Research\n /**\n * @description 심층연구 모드 활성화 여부\n * @Todo vibecode - 심층연구 버튼 토글 상태\n */\n isDeepResearchMode,\n /**\n * @description 심층연구 모드 토글\n * @Todo vibecode - 심층연구 버튼 클릭 핸들러\n */\n toggleDeepResearchMode,\n /**\n * @description 심층연구 진행 상태\n * @Todo vibecode - 현재 진행 중인 심층연구 상태\n */\n deepResearchProgress,\n\n // Poll (AI-driven choices)\n /**\n * @description Poll 응답 처리\n * @Todo vibecode - 사용자가 선택지 선택 완료 시 호출\n */\n handlePollSubmit,\n\n // Attachments\n /**\n * @description 현재 첨부된 파일 목록\n * @Todo vibecode - 입력창 파일 첨부 상태\n */\n attachments,\n /**\n * @description 파일 첨부 추가 핸들러\n * @Todo vibecode - File[] → ChatAttachment 변환\n */\n addAttachments,\n /**\n * @description 첨부 파일 제거 핸들러\n * @Todo vibecode - objectURL 해제 포함\n */\n removeAttachment,\n\n // Skills\n /**\n * @description 현재 실행 중인 스킬 상태\n * @Todo vibecode - 스킬 실행 상태 추적\n */\n activeSkillExecution,\n /**\n * @description manual 트리거 스킬 목록 (UI 표시용)\n * @Todo vibecode - 입력창 메뉴에 표시\n */\n manualSkills,\n /**\n * @description manual 스킬/도구 선택 핸들러\n * @Todo vibecode - 도구 스킬은 selectedAction으로 변환, 일반 스킬은 즉시 실행\n */\n executeManualSkill: (skillName: string) => {\n const isToolSkill = tools?.some((t) => t.name === skillName);\n if (isToolSkill) {\n /** @Todo vibecode - 도구는 즉시 실행하지 않고 selectedAction으로 설정 */\n const toolConfig = tools!.find((t) => t.name === skillName)!;\n setSelectedAction({\n id: `tool_${skillName}`,\n label: toolConfig.label || toolConfig.name,\n icon: toolConfig.icon || 'sparkling',\n description: toolConfig.description,\n systemPrompt: `사용자가 \"${toolConfig.label || skillName}\" 도구를 사용하려고 합니다. 사용자의 메시지를 바탕으로 반드시 <skill_use name=\"${skillName}\"> 태그를 사용하여 이 도구를 호출하세요. 도구를 사용하지 않고 텍스트로만 답변하지 마세요.`,\n });\n } else {\n /** @Todo vibecode - manual 스킬 실행 후 AI 후속 응답 지원 */\n const currentQuery = input;\n executeManualSkill(skillName, { query: currentQuery }).then((result) => {\n if (!result || !result.content) return;\n\n let shouldContinue = continueAfterToolResult;\n if (onSkillCompleteRef.current) {\n const decision = onSkillCompleteRef.current(skillName, result);\n shouldContinue = decision === 'continue';\n }\n if (!shouldContinue) return;\n\n skipNextSkillParsingRef.current = true;\n const resultPrompt = `스킬 \"${skillName}\" 실행 결과:\\n\\n${result.content}\\n\\n위 결과를 바탕으로 사용자의 원래 질문에 답변해주세요. skill_use 태그는 사용하지 마세요.`;\n setTimeout(() => {\n sendMessage(resultPrompt, { hiddenUserMessage: true });\n }, 100);\n });\n }\n },\n\n // Project\n /** @Todo vibecode - 프로젝트 목록 (enableProjects=false이면 빈 배열) */\n projects: projectHook.projects,\n currentProjectId: projectHook.currentProjectId,\n currentProject: projectHook.currentProject,\n isProjectsLoading: projectHook.isProjectsLoading,\n createProject: projectHook.createProject,\n selectProject: async (projectId: string) => {\n if (!enableProjects) return;\n await projectHook.selectProject(projectId);\n /** @Todo vibecode - 프로젝트 전환 시 해당 프로젝트의 첫 번째 세션 선택 */\n const projectSessions = sessionsRef.current.filter((s) => s.projectId === projectId);\n if (projectSessions.length > 0) {\n setCurrentSessionId(projectSessions[0].id);\n } else {\n setCurrentSessionId(null);\n }\n },\n updateProject: projectHook.updateProject,\n deleteProject: async (projectId: string) => {\n if (!enableProjects) return;\n /** @Todo vibecode - 프로젝트 삭제 시 소속 세션도 함께 삭제 */\n const projectSessions = sessionsRef.current.filter((s) => s.projectId === projectId);\n for (const sess of projectSessions) {\n if (useExternalStorage && onDeleteSessionCallbackRef.current) {\n await onDeleteSessionCallbackRef.current(sess.id).catch(() => {});\n }\n removeSessionCache(storageKey, sess.id);\n }\n setSessions((prev) => prev.filter((s) => s.projectId !== projectId));\n await projectHook.deleteProject(projectId);\n },\n addProjectFile: projectHook.addFile,\n deleteProjectFile: projectHook.deleteFile,\n projectSettingsOpen,\n openProjectSettings: () => setProjectSettingsOpen(true),\n closeProjectSettings: () => setProjectSettingsOpen(false),\n projectMemory,\n };\n};\n\nexport default useChatUI;\n","/**\n * Core types for devdive-chatLLM\n */\n\n// ============================================================================\n// Provider Types\n// ============================================================================\n\nexport type ProviderType = 'openai' | 'anthropic' | 'google' | 'naver' | 'ollama';\n\nexport interface ProviderConfigs {\n openai?: OpenAIConfig;\n anthropic?: AnthropicConfig;\n google?: GoogleConfig;\n naver?: NaverConfig;\n ollama?: OllamaConfig;\n}\n\nexport interface OpenAIConfig {\n apiKey: string;\n baseUrl?: string;\n}\n\nexport interface AnthropicConfig {\n apiKey: string;\n baseUrl?: string;\n}\n\nexport interface GoogleConfig {\n apiKey: string;\n}\n\nexport interface NaverConfig {\n apiKey: string;\n apiGatewayKey: string;\n baseUrl?: string;\n}\n\nexport interface OllamaConfig {\n baseUrl?: string; // default: http://localhost:11434\n}\n\n// ============================================================================\n// Message Types\n// ============================================================================\n\nexport type Role = 'system' | 'user' | 'assistant' | 'tool';\n\nexport interface Message {\n id: string;\n role: Role;\n content: string;\n provider?: ProviderType;\n model?: string;\n toolCalls?: ToolCall[];\n toolCallId?: string;\n timestamp: number;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ToolCall {\n id: string;\n name: string;\n arguments: Record<string, unknown>;\n}\n\nexport interface ToolResult {\n toolCallId: string;\n result: unknown;\n error?: string;\n}\n\n// ============================================================================\n// Tool/Function Types\n// ============================================================================\n\nexport interface ParameterSchema {\n type: 'string' | 'number' | 'boolean' | 'object' | 'array';\n description?: string;\n enum?: string[];\n items?: ParameterSchema;\n properties?: Record<string, ParameterSchema>;\n required?: string[];\n}\n\nexport interface ToolDefinition {\n name: string;\n description: string;\n parameters: {\n type: 'object';\n properties: Record<string, ParameterSchema>;\n required?: string[];\n };\n handler: (params: Record<string, unknown>) => Promise<unknown> | unknown;\n}\n\n// ============================================================================\n// Chat & Session Types\n// ============================================================================\n\nexport interface ChatConfig {\n id?: string;\n providers: ProviderConfigs;\n defaultProvider: ProviderType;\n defaultModel?: string;\n storagePath?: string;\n systemPrompt?: string;\n /** 개인화 설정 */\n personalization?: Partial<PersonalizationConfig>;\n}\n\nexport interface Chat {\n id: string;\n config: ChatConfig;\n messages: Message[];\n tools: Map<string, ToolDefinition>;\n memory: Map<string, MemoryEntry>;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface SendOptions {\n provider?: ProviderType;\n model?: string;\n temperature?: number;\n maxTokens?: number;\n tools?: ToolDefinition[];\n systemPrompt?: string;\n}\n\n// ============================================================================\n// Streaming Types\n// ============================================================================\n\nexport type StreamEventType = 'text' | 'tool_call' | 'tool_result' | 'done' | 'error';\n\nexport interface StreamEvent {\n type: StreamEventType;\n content?: string;\n toolCall?: ToolCall;\n toolResult?: ToolResult;\n error?: Error;\n message?: Message;\n}\n\n// ============================================================================\n// Memory Types\n// ============================================================================\n\nexport interface MemoryEntry {\n key: string;\n value: unknown;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface GlobalMemoryStore {\n entries: Map<string, MemoryEntry>;\n storagePath: string;\n}\n\n// ============================================================================\n// Acontext Types\n// ============================================================================\n\nexport type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'failed';\n\nexport interface ObservedTask {\n id: string;\n description: string;\n status: TaskStatus;\n progress: number; // 0-100\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface UserPreference {\n key: string;\n value: unknown;\n confidence: number; // 0-1\n source: string; // which message extracted this\n}\n\nexport interface LearnedSkill {\n id: string;\n name: string;\n description: string;\n category: string;\n steps: SkillStep[];\n successRate: number;\n usageCount: number;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface SkillStep {\n order: number;\n action: string;\n expectedInput?: string;\n expectedOutput?: string;\n}\n\nexport interface ObserverConfig {\n extractTasks: boolean;\n extractPreferences: boolean;\n autoLearn: boolean;\n}\n\nexport interface ObserverState {\n enabled: boolean;\n config: ObserverConfig;\n tasks: ObservedTask[];\n preferences: UserPreference[];\n}\n\n// ============================================================================\n// Personalization Types (ChatGPT-style settings)\n// ============================================================================\n\nexport type StyleLevel = 'low' | 'medium' | 'high';\nexport type FormattingStyle = 'minimal' | 'default' | 'rich';\n\n/**\n * 응답 스타일 설정\n */\nexport interface ResponseStyle {\n /** 따뜻함 수준 */\n warmth: StyleLevel;\n /** 열정/에너지 수준 */\n enthusiasm: StyleLevel;\n /** 이모지 사용 수준 */\n emojiUsage: StyleLevel;\n /** 포맷팅 스타일 (헤더, 목록 등) */\n formatting: FormattingStyle;\n /** 응답 길이 선호 */\n verbosity: 'concise' | 'balanced' | 'detailed';\n}\n\n/**\n * 사용자 프로필 정보\n */\nexport interface UserProfile {\n /** 사용자 닉네임/호칭 */\n nickname?: string;\n /** 직업/역할 */\n occupation?: string;\n /** 추가 정보 (관심사, 가치, 선호 사항) */\n additionalInfo?: string;\n /** 선호 언어 */\n preferredLanguage?: string;\n /** 전문 분야 */\n expertise?: string[];\n /** 커스텀 지시사항 */\n customInstructions?: string;\n}\n\n/**\n * 개인화 설정 전체\n */\nexport interface PersonalizationConfig {\n /** 응답 스타일 */\n responseStyle: ResponseStyle;\n /** 사용자 프로필 */\n userProfile: UserProfile;\n /** 메모리 참조 활성화 */\n useMemory: boolean;\n /** 언어 설정 ('auto' | 'ko' | 'en' | etc.) */\n language: string;\n}\n\n/**\n * 개인화 설정 기본값\n */\nexport const DEFAULT_PERSONALIZATION: PersonalizationConfig = {\n responseStyle: {\n warmth: 'medium',\n enthusiasm: 'medium',\n emojiUsage: 'low',\n formatting: 'default',\n verbosity: 'balanced',\n },\n userProfile: {},\n useMemory: true,\n language: 'auto',\n};\n\n// ============================================================================\n// LLM Chat Hook Integration Types\n// ============================================================================\n\n/**\n * @description Hook 결과 타입 (React Query UseMutationResult 호환)\n */\nexport interface MutationResult<TData = unknown, TError = Error, TVariables = unknown> {\n mutate: (variables: TVariables) => void;\n mutateAsync: (variables: TVariables) => Promise<TData>;\n isPending: boolean;\n isError: boolean;\n isSuccess: boolean;\n data?: TData;\n error?: TError;\n reset: () => void;\n}\n\n/**\n * @description Tool/Action Hook 타입\n */\nexport type ToolHook<TRequest = unknown, TResponse = unknown> = () => MutationResult<TResponse, Error, TRequest>;\n\n/**\n * @description AI가 자동으로 호출하는 Tool 설정\n * AI가 사용자 메시지를 분석해서 필요시 자동 호출\n */\nexport interface LLMToolConfig<TRequest = unknown, TResponse = unknown> {\n /** Tool hook */\n hook: ToolHook<TRequest, TResponse>;\n /** AI가 판단할 때 사용하는 설명 */\n description: string;\n /** JSON Schema 형태의 파라미터 정의 (선택) */\n parameters?: {\n type: 'object';\n properties: Record<string, {\n type: string;\n description?: string;\n enum?: string[];\n }>;\n required?: string[];\n };\n}\n\n/**\n * @description 사용자가 UI에서 직접 선택하는 Action 설정\n */\nexport interface LLMActionConfig<TRequest = unknown, TResponse = unknown> {\n /** Action hook */\n hook: ToolHook<TRequest, TResponse>;\n /** UI에 표시할 레이블 */\n label: string;\n /** 아이콘 이름 또는 컴포넌트 */\n icon?: string;\n /** 비활성화 여부 */\n disabled?: boolean;\n}\n\n/**\n * @description 기본 채팅(텍스트 생성) 설정\n */\nexport interface LLMChatHookConfig<TRequest = unknown, TResponse = unknown> {\n /** 텍스트 생성 hook */\n hook: ToolHook<TRequest, TResponse>;\n /** 기본 시스템 프롬프트 */\n systemPrompt?: string;\n}\n\n/**\n * @description LLM Chat 컴포넌트 Props\n */\nexport interface LLMChatComponentProps {\n /** AI가 자동 호출하는 Tools */\n tools?: Record<string, LLMToolConfig>;\n /** 사용자가 직접 선택하는 Actions */\n actions?: Record<string, LLMActionConfig>;\n /** 기본 채팅 설정 */\n chat: LLMChatHookConfig;\n /** 스타일 클래스 */\n className?: string;\n /** 개인화 설정 */\n personalization?: Partial<PersonalizationConfig>;\n}\n","/**\n * @description 글로벌 메모리 관리 훅\n * localStorage 또는 PostgreSQL API를 통해 세션 간 정보 유지\n * @license MIT\n */\n\nimport { useState, useCallback, useEffect, useRef } from 'react';\nimport type {\n UseGlobalMemoryOptions,\n UseGlobalMemoryReturn,\n GlobalMemoryState,\n ExtendedMemoryEntry,\n MemoryStorageAdapter,\n} from '../types/memory';\nimport { LocalStorageAdapter } from '../adapters/LocalStorageAdapter';\nimport { PostgreSQLAdapter } from '../adapters/PostgreSQLAdapter';\n\n/**\n * @description 저장소 어댑터 생성\n */\nfunction createAdapter(options: UseGlobalMemoryOptions): MemoryStorageAdapter {\n switch (options.storageType) {\n case 'postgresql':\n if (!options.apiEndpoint || !options.userId) {\n console.warn('[useGlobalMemory] PostgreSQL requires apiEndpoint and userId, falling back to localStorage');\n return new LocalStorageAdapter(options.storageKey);\n }\n return new PostgreSQLAdapter(options.apiEndpoint, options.userId, options.authToken);\n case 'localStorage':\n case 'memory':\n default:\n return new LocalStorageAdapter(options.storageKey);\n }\n}\n\n/**\n * @description 글로벌 메모리 훅\n * @param options 설정 옵션\n */\nexport function useGlobalMemory(options: UseGlobalMemoryOptions): UseGlobalMemoryReturn {\n const [state, setState] = useState<GlobalMemoryState>({\n entries: new Map(),\n isLoading: true,\n error: null,\n });\n\n const adapterRef = useRef<MemoryStorageAdapter>(createAdapter(options));\n\n /**\n * @description 메모리 새로고침\n */\n const refresh = useCallback(async () => {\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n try {\n const allData = await adapterRef.current.getAll();\n const entries = new Map<string, ExtendedMemoryEntry>();\n\n for (const [key, value] of allData) {\n if (typeof value === 'object' && value !== null && 'value' in value) {\n // 이미 ExtendedMemoryEntry 형식인 경우\n entries.set(key, value as ExtendedMemoryEntry);\n } else {\n // 단순 값인 경우 래핑\n entries.set(key, {\n key,\n value,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n });\n }\n }\n\n setState({ entries, isLoading: false, error: null });\n } catch (error) {\n setState((prev) => ({\n ...prev,\n isLoading: false,\n error: error instanceof Error ? error : new Error('Unknown error'),\n }));\n }\n }, []);\n\n /**\n * @description 메모리 설정\n */\n const set = useCallback(\n async (key: string, value: unknown, meta?: Partial<ExtendedMemoryEntry>) => {\n const now = Date.now();\n const existingEntry = state.entries.get(key);\n\n const entry: ExtendedMemoryEntry = {\n key,\n value,\n createdAt: existingEntry?.createdAt ?? now,\n updatedAt: now,\n category: meta?.category ?? existingEntry?.category,\n confidence: meta?.confidence ?? existingEntry?.confidence,\n source: meta?.source ?? existingEntry?.source,\n };\n\n try {\n await adapterRef.current.write(key, entry);\n setState((prev) => {\n const newEntries = new Map(prev.entries);\n newEntries.set(key, entry);\n return { ...prev, entries: newEntries };\n });\n } catch (error) {\n console.error('[useGlobalMemory] Failed to set:', error);\n }\n },\n [state.entries]\n );\n\n /**\n * @description 메모리 조회\n */\n const get = useCallback(\n <T>(key: string): T | undefined => {\n const entry = state.entries.get(key);\n return entry?.value as T | undefined;\n },\n [state.entries]\n );\n\n /**\n * @description 메모리 삭제\n */\n const remove = useCallback(async (key: string) => {\n try {\n await adapterRef.current.delete(key);\n setState((prev) => {\n const newEntries = new Map(prev.entries);\n newEntries.delete(key);\n return { ...prev, entries: newEntries };\n });\n } catch (error) {\n console.error('[useGlobalMemory] Failed to remove:', error);\n }\n }, []);\n\n /**\n * @description 키 존재 여부 확인\n */\n const has = useCallback(\n (key: string): boolean => {\n return state.entries.has(key);\n },\n [state.entries]\n );\n\n /**\n * @description 전체 삭제\n */\n const clear = useCallback(async () => {\n try {\n // 모든 키 삭제\n for (const key of state.entries.keys()) {\n await adapterRef.current.delete(key);\n }\n setState((prev) => ({ ...prev, entries: new Map() }));\n } catch (error) {\n console.error('[useGlobalMemory] Failed to clear:', error);\n }\n }, [state.entries]);\n\n /**\n * @description 시스템 프롬프트용 컨텍스트 문자열 생성\n */\n const toPromptContext = useCallback((): string => {\n if (state.entries.size === 0) return '';\n\n const lines: string[] = ['[사용자 기억 정보]'];\n\n /**\n * @description 카테고리별 그룹화 (fact/skill/preference + 기존 호환)\n * @Todo vibecode - 추출 카테고리와 UI 카테고리 통일\n */\n const categorized: Record<string, Array<{ key: string; value: unknown }>> = {\n fact: [],\n skill: [],\n preference: [],\n other: [],\n };\n\n // 기존 카테고리 → 통일 카테고리 매핑\n const categoryMapping: Record<string, string> = {\n basic: 'fact',\n professional: 'skill',\n preferences: 'preference',\n context: 'other', // 대화 맥락은 세션별 compressionState로 관리\n fact: 'fact',\n skill: 'skill',\n preference: 'preference',\n };\n\n for (const [key, entry] of state.entries) {\n const rawCategory = entry.category || 'other';\n const category = categoryMapping[rawCategory] || 'other';\n categorized[category].push({ key, value: entry.value });\n }\n\n // 카테고리별 출력\n const categoryLabels: Record<string, string> = {\n fact: '사용자 정보',\n skill: '전문 분야/기술',\n preference: '선호도',\n other: '기타',\n };\n\n for (const [category, items] of Object.entries(categorized)) {\n if (items.length > 0) {\n lines.push(`\\n${categoryLabels[category]}:`);\n for (const { key, value } of items) {\n const valueStr = typeof value === 'object' ? JSON.stringify(value) : String(value);\n lines.push(`- ${key}: ${valueStr}`);\n }\n }\n }\n\n return lines.join('\\n');\n }, [state.entries]);\n\n // 초기 로드\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n // 옵션 변경 시 어댑터 재생성\n useEffect(() => {\n adapterRef.current = createAdapter(options);\n refresh();\n }, [options.storageType, options.storageKey, options.apiEndpoint, options.userId]);\n\n return {\n state,\n set,\n get,\n remove,\n has,\n clear,\n toPromptContext,\n refresh,\n };\n}\n\nexport default useGlobalMemory;\n","/**\n * @description localStorage 기반 메모리 저장소 어댑터\n * @license MIT\n */\n\nimport type { MemoryStorageAdapter } from '../types/memory';\n\n/**\n * @description localStorage 어댑터 구현\n */\nexport class LocalStorageAdapter implements MemoryStorageAdapter {\n private storageKey: string;\n\n constructor(storageKey: string = 'chatllm_global_memory') {\n this.storageKey = storageKey;\n }\n\n /**\n * @description 전체 데이터 로드\n */\n private loadData(): Record<string, unknown> {\n if (typeof window === 'undefined') return {};\n try {\n const data = localStorage.getItem(this.storageKey);\n return data ? JSON.parse(data) : {};\n } catch {\n return {};\n }\n }\n\n /**\n * @description 전체 데이터 저장\n */\n private saveData(data: Record<string, unknown>): void {\n if (typeof window === 'undefined') return;\n try {\n localStorage.setItem(this.storageKey, JSON.stringify(data));\n } catch (error) {\n console.error('[LocalStorageAdapter] Failed to save data:', error);\n }\n }\n\n async read<T>(key: string): Promise<T | null> {\n const data = this.loadData();\n const value = data[key];\n return value !== undefined ? (value as T) : null;\n }\n\n async write<T>(key: string, value: T): Promise<void> {\n const data = this.loadData();\n data[key] = value;\n this.saveData(data);\n }\n\n async delete(key: string): Promise<boolean> {\n const data = this.loadData();\n if (key in data) {\n delete data[key];\n this.saveData(data);\n return true;\n }\n return false;\n }\n\n async exists(key: string): Promise<boolean> {\n const data = this.loadData();\n return key in data;\n }\n\n async getAll(): Promise<Map<string, unknown>> {\n const data = this.loadData();\n return new Map(Object.entries(data));\n }\n\n /**\n * @description 전체 삭제\n */\n async clear(): Promise<void> {\n if (typeof window === 'undefined') return;\n localStorage.removeItem(this.storageKey);\n }\n}\n\nexport default LocalStorageAdapter;\n","/**\n * @description PostgreSQL REST API 기반 메모리 저장소 어댑터\n * @license MIT\n */\n\nimport type { MemoryStorageAdapter } from '../types/memory';\n\n/**\n * @description PostgreSQL 어댑터 구현\n * REST API를 통해 서버의 PostgreSQL DB와 통신\n */\nexport class PostgreSQLAdapter implements MemoryStorageAdapter {\n private apiEndpoint: string;\n private userId: string;\n private authToken?: string;\n\n constructor(apiEndpoint: string, userId: string, authToken?: string) {\n this.apiEndpoint = apiEndpoint.replace(/\\/$/, ''); // 끝의 슬래시 제거\n this.userId = userId;\n this.authToken = authToken;\n }\n\n /**\n * @description HTTP 헤더 생성\n */\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n return headers;\n }\n\n /**\n * @description API 요청 헬퍼\n */\n private async request<T>(\n path: string,\n options: RequestInit = {}\n ): Promise<T | null> {\n try {\n const response = await fetch(`${this.apiEndpoint}${path}`, {\n ...options,\n headers: {\n ...this.getHeaders(),\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n if (response.status === 404) return null;\n throw new Error(`API error: ${response.status}`);\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) {\n return response.json();\n }\n return null;\n } catch (error) {\n console.error('[PostgreSQLAdapter] Request failed:', error);\n return null;\n }\n }\n\n async read<T>(key: string): Promise<T | null> {\n const result = await this.request<{ value: T }>(\n `/memory/${this.userId}/${encodeURIComponent(key)}`\n );\n return result?.value ?? null;\n }\n\n async write<T>(key: string, value: T): Promise<void> {\n await this.request(`/memory/${this.userId}`, {\n method: 'POST',\n body: JSON.stringify({ key, value }),\n });\n }\n\n async delete(key: string): Promise<boolean> {\n const result = await this.request<{ success: boolean }>(\n `/memory/${this.userId}/${encodeURIComponent(key)}`,\n { method: 'DELETE' }\n );\n return result?.success ?? false;\n }\n\n async exists(key: string): Promise<boolean> {\n try {\n const response = await fetch(\n `${this.apiEndpoint}/memory/${this.userId}/${encodeURIComponent(key)}`,\n {\n method: 'HEAD',\n headers: this.getHeaders(),\n }\n );\n return response.ok;\n } catch {\n return false;\n }\n }\n\n async getAll(): Promise<Map<string, unknown>> {\n const result = await this.request<{ entries: Record<string, unknown> }>(\n `/memory/${this.userId}`\n );\n\n if (!result?.entries) {\n return new Map();\n }\n\n return new Map(Object.entries(result.entries));\n }\n\n /**\n * @description 전체 삭제\n */\n async clear(): Promise<void> {\n await this.request(`/memory/${this.userId}`, {\n method: 'DELETE',\n });\n }\n}\n\nexport default PostgreSQLAdapter;\n","/**\n * @description 자동 정보 추출 훅\n * LLM을 사용하여 대화에서 중요 정보를 자동으로 추출\n * @license MIT\n */\n\nimport { useState, useCallback } from 'react';\nimport type {\n UseInfoExtractionOptions,\n UseInfoExtractionReturn,\n ExtractedInfo,\n ExtractionResult,\n UseGlobalMemoryReturn,\n} from '../types/memory';\n\n/**\n * @description 정보 추출 프롬프트 생성\n */\nconst buildExtractionPrompt = (\n messages: Array<{ role: string; content: string }>\n): string => {\n const conversationText = messages\n .map((m) => `${m.role === 'user' ? '사용자' : 'AI'}: ${m.content}`)\n .join('\\n\\n');\n\n return `다음 대화에서 사용자에 대해 **세션을 넘어 기억해둘 만한** 중요한 정보를 추출해주세요.\n현재 대화의 맥락(진행 중인 작업, 일시적 요청 등)은 제외합니다.\n\n대화:\n${conversationText}\n\n다음 JSON 형식으로만 응답하세요 (JSON만 출력, 다른 텍스트 없이):\n{\n \"extracted\": [\n {\n \"category\": \"fact|skill|preference\",\n \"key\": \"정보 키 (예: userName, occupation, preferredLanguage)\",\n \"value\": \"정보 값\",\n \"confidence\": 0.0-1.0,\n \"source\": \"근거가 된 원문 일부\"\n }\n ],\n \"shouldStore\": true\n}\n\n카테고리 설명:\n- fact: 이름, 나이, 위치, 회사 등 사용자 기본 정보\n- skill: 직업, 전문 분야, 사용 기술, 개발 언어\n- preference: 선호하는 응답 스타일, 언어, 관심사\n\n규칙:\n1. 명시적으로 언급된 정보만 추출 (추론 금지)\n2. 개인정보 민감도가 높은 정보(주민번호, 비밀번호, 카드번호 등)는 제외\n3. confidence는 정보의 확실성 (0.8 이상 권장)\n4. 대화에서 중요 정보가 없으면 extracted를 빈 배열로 반환\n5. key는 영문 camelCase로 작성 (예: userName, currentProject)\n6. 현재 대화에서만 유효한 일시적 맥락은 추출하지 않음`;\n};\n\n/**\n * @description 추출 결과 파싱\n */\nconst parseExtractionResult = (text: string): ExtractionResult => {\n try {\n // JSON 블록 추출 시도\n const jsonMatch = text.match(/\\{[\\s\\S]*\\}/);\n if (!jsonMatch) {\n return { extracted: [], shouldStore: false };\n }\n\n const parsed = JSON.parse(jsonMatch[0]);\n\n if (!parsed.extracted || !Array.isArray(parsed.extracted)) {\n return { extracted: [], shouldStore: false };\n }\n\n // 유효성 검증\n const validExtracted = parsed.extracted.filter(\n (item: ExtractedInfo) =>\n item.category &&\n item.key &&\n item.value !== undefined &&\n typeof item.confidence === 'number'\n );\n\n return {\n extracted: validExtracted,\n shouldStore: parsed.shouldStore ?? validExtracted.length > 0,\n };\n } catch {\n return { extracted: [], shouldStore: false };\n }\n};\n\n/**\n * @description 자동 정보 추출 훅\n */\nexport function useInfoExtraction(options: UseInfoExtractionOptions): UseInfoExtractionReturn {\n const [isExtracting, setIsExtracting] = useState(false);\n const [lastExtraction, setLastExtraction] = useState<ExtractedInfo[] | null>(null);\n\n const { apiEndpoint, model, minConfidence = 0.8, globalMemory, onCallLLM } = options;\n\n /**\n * @description 대화에서 정보 추출\n * @Todo vibecode - onCallLLM 제공 시 호스트 콜백 재활용 (onSendMessage 모드 지원)\n */\n const extractInfo = useCallback(\n async (messages: Array<{ role: string; content: string }>): Promise<ExtractedInfo[]> => {\n if (messages.length === 0) {\n return [];\n }\n\n setIsExtracting(true);\n\n try {\n const prompt = buildExtractionPrompt(messages);\n let fullResponse: string;\n\n if (onCallLLM) {\n /** @Todo vibecode - onSendMessage 모드: callInternalLLM 재활용 */\n fullResponse = await onCallLLM(prompt, model || 'default');\n } else {\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [{ role: 'user', content: prompt }],\n model: model || 'default',\n }),\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n return [];\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n fullResponse = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n try {\n const parsed = JSON.parse(data);\n const chunk = parsed.content ?? parsed.text ?? '';\n if (chunk) fullResponse += chunk;\n } catch {\n // Ignore parse errors\n }\n }\n }\n }\n }\n\n // 결과 파싱\n const result = parseExtractionResult(fullResponse);\n const extracted = result.extracted.filter(\n (item) => item.confidence >= minConfidence\n );\n\n // 글로벌 메모리에 저장\n if (result.shouldStore && globalMemory) {\n for (const item of extracted) {\n await globalMemory.set(`${item.category}.${item.key}`, item.value, {\n category: item.category,\n confidence: item.confidence,\n source: item.source,\n });\n }\n }\n\n setLastExtraction(extracted);\n return extracted;\n } catch (error) {\n console.error('[useInfoExtraction] Failed to extract:', error);\n return [];\n } finally {\n setIsExtracting(false);\n }\n },\n [apiEndpoint, model, minConfidence, globalMemory, onCallLLM]\n );\n\n return {\n extractInfo,\n isExtracting,\n lastExtraction,\n };\n}\n\nexport default useInfoExtraction;\n","/**\n * @description 스킬 관리 훅\n * @Todo vibecode - 시스템 프롬프트 생성, auto 스킬 실행, manual 스킬 관리\n *\n * useChatUI에서 호출하여 스킬 관련 로직을 분리합니다.\n */\n\nimport { useState, useCallback, useMemo, useRef } from 'react';\nimport type {\n SkillConfig,\n SkillExecution,\n SkillExecutionResult,\n SkillProgress,\n SkillExecuteCallbacks,\n ManualSkillItem,\n DeepResearchCallbacks,\n} from '../types';\nimport { parseSkillCallFromContent } from '../utils/skillParser';\nimport type { ParsedSkillCall } from '../utils/skillParser';\nimport { createDeepResearchSkill } from '../utils/deepResearchAdapter';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface UseSkillsOptions {\n /** 사용자 등록 스킬 */\n skills?: Record<string, SkillConfig>;\n /** @deprecated 하위 호환용 deepResearch */\n deepResearch?: DeepResearchCallbacks;\n}\n\nexport interface UseSkillsReturn {\n /** 시스템 프롬프트에 추가할 스킬 가이드 텍스트 */\n buildSkillsPrompt: () => string;\n /**\n * @description 스트리밍 완료 후 skill_use 태그 감지 및 실행\n * @Todo vibecode - callbacks로 진행 상태/스트리밍/중단 시그널 전달\n * @returns skillCall이 있으면 실행하고 결과 반환, 없으면 null\n */\n handleSkillCall: (\n content: string,\n callbacks?: SkillExecuteCallbacks\n ) => Promise<{\n skillCall: ParsedSkillCall | null;\n cleanContent: string;\n result: SkillExecutionResult | null;\n }>;\n /** manual 스킬 목록 (UI 표시용) */\n manualSkills: ManualSkillItem[];\n /** manual 스킬 직접 실행 */\n executeManualSkill: (\n skillName: string,\n params?: Record<string, unknown>,\n callbacks?: SkillExecuteCallbacks\n ) => Promise<SkillExecutionResult | null>;\n /** 현재 실행 중인 스킬 */\n activeSkillExecution: SkillExecution | null;\n /** 통합된 스킬 맵 (deepResearch 포함) */\n resolvedSkills: Record<string, SkillConfig>;\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport const useSkills = (options: UseSkillsOptions): UseSkillsReturn => {\n const [activeSkillExecution, setActiveSkillExecution] = useState<SkillExecution | null>(null);\n const executionAbortRef = useRef<AbortController | null>(null);\n\n /**\n * @description 통합 스킬 맵 생성\n * @Todo vibecode - deepResearch prop이 존재하면 내장 스킬로 자동 변환 (하위 호환)\n */\n const resolvedSkills = useMemo((): Record<string, SkillConfig> => {\n const skills: Record<string, SkillConfig> = { ...(options.skills || {}) };\n\n if (options.deepResearch?.onWebSearch && !skills.deepResearch) {\n skills.deepResearch = createDeepResearchSkill(options.deepResearch);\n }\n\n return skills;\n }, [options.skills, options.deepResearch]);\n\n /**\n * @description manual/both 트리거 스킬 목록 (UI 메뉴 표시용)\n */\n const manualSkills = useMemo((): ManualSkillItem[] => {\n return Object.entries(resolvedSkills)\n .filter(([, config]) => config.trigger === 'manual' || config.trigger === 'both')\n .map(([name, config]) => ({\n name,\n label: config.label,\n icon: config.icon,\n description: config.description,\n disabled: config.disabled,\n }));\n }, [resolvedSkills]);\n\n /**\n * @description auto/both 스킬을 시스템 프롬프트 텍스트로 변환\n * @Todo vibecode - AI가 필요시 <skill_use> 태그로 호출할 수 있도록 가이드\n * enum, required/optional, 예시 포함하여 AI가 도구를 확실히 호출하도록 강화\n */\n const buildSkillsPrompt = useCallback((): string => {\n const autoSkills = Object.entries(resolvedSkills).filter(\n ([, config]) => config.trigger === 'auto' || config.trigger === 'both'\n );\n\n if (autoSkills.length === 0) return '';\n\n const skillDescriptions = autoSkills\n .map(([name, config]) => {\n let desc = `### ${name}\\n${config.description}`;\n\n if (config.parameters?.properties) {\n desc += '\\n파라미터:';\n const props = config.parameters.properties;\n const requiredList = config.parameters.required || [];\n\n Object.entries(props).forEach(([key, prop]) => {\n const isRequired = requiredList.includes(key);\n const tag = isRequired ? '(필수)' : '(선택)';\n let line = `\\n- ${key} ${tag}: ${prop.description || prop.type}`;\n if (prop.enum) {\n line += ` [가능한 값: ${prop.enum.join(', ')}]`;\n }\n desc += line;\n });\n\n /** @Todo vibecode - 각 스킬별 호출 예시 자동 생성 */\n const exampleParams: Record<string, string> = {};\n Object.entries(props).forEach(([key, prop]) => {\n if (prop.enum) {\n exampleParams[key] = prop.enum[0];\n } else if (prop.description) {\n exampleParams[key] = `${prop.description}`;\n } else {\n exampleParams[key] = key;\n }\n });\n desc += `\\n예시: <skill_use name=\"${name}\">${JSON.stringify(exampleParams)}</skill_use>`;\n }\n\n return desc;\n })\n .join('\\n\\n');\n\n return `## 사용 가능한 도구\n\n아래 도구를 적극적으로 사용하세요. 사용자의 요청에 맞는 도구가 있으면 반드시 호출해야 합니다.\n\n호출 형식:\n<skill_use name=\"도구이름\">{\"파라미터\": \"값\"}</skill_use>\n\n${skillDescriptions}\n\n**규칙:**\n- 이미지 생성/그림/일러스트 요청 → 반드시 generate_image 도구 호출\n- 최신 정보/검색/뉴스 요청 → 반드시 web_search 도구 호출\n- 도구 호출 시 짧은 안내 메시지를 먼저 작성하고, 그 뒤에 skill_use 태그를 포함하세요\n- 한 번에 하나의 도구만 호출하세요\n- 도구 없이 텍스트로만 답변하지 마세요 (해당 도구가 있는 경우)\n- 도구가 실행되면 결과가 자동으로 전달됩니다`;\n }, [resolvedSkills]);\n\n /**\n * @description 스트리밍 완료 후 <skill_use> 태그 감지 및 실행\n * @Todo vibecode - 태그 파싱 → 스킬 execute 호출 → 결과 반환\n * callbacks로 진행 상태(onProgress), 스트리밍(onStream), 중단(signal) 전달\n */\n const handleSkillCall = useCallback(\n async (\n content: string,\n callbacks?: SkillExecuteCallbacks\n ): Promise<{\n skillCall: ParsedSkillCall | null;\n cleanContent: string;\n result: SkillExecutionResult | null;\n }> => {\n const { skillCall, cleanContent } = parseSkillCallFromContent(content);\n\n if (!skillCall) {\n return { skillCall: null, cleanContent: content, result: null };\n }\n\n const skill = resolvedSkills[skillCall.name];\n if (!skill) {\n console.warn(`[useSkills] 등록되지 않은 스킬: ${skillCall.name}`);\n return { skillCall, cleanContent, result: null };\n }\n\n /** @Todo vibecode - 스킬 실행 상태 추적 시작 */\n setActiveSkillExecution({\n skillName: skillCall.name,\n params: skillCall.params,\n status: 'executing',\n });\n\n const abortController = new AbortController();\n executionAbortRef.current = abortController;\n\n try {\n /** @Todo vibecode - 콜백 머지: 내부 상태 업데이트 + 외부 콜백 전달 */\n const mergedCallbacks: SkillExecuteCallbacks = {\n onProgress: (progress) => {\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, progress } : null\n );\n callbacks?.onProgress?.(progress);\n },\n onStream: callbacks?.onStream,\n signal: callbacks?.signal || abortController.signal,\n };\n\n const result = await skill.execute(skillCall.params, mergedCallbacks);\n\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, status: 'done', result } : null\n );\n\n return { skillCall, cleanContent, result };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, status: 'error', error: errorMsg } : null\n );\n\n return {\n skillCall,\n cleanContent,\n result: { content: `스킬 실행 오류: ${errorMsg}` },\n };\n } finally {\n executionAbortRef.current = null;\n }\n },\n [resolvedSkills]\n );\n\n /**\n * @description manual 스킬 직접 실행\n * @Todo vibecode - 사용자가 UI에서 스킬 선택 시 호출\n * callbacks로 진행 상태/스트리밍/중단 시그널 전달\n */\n const executeManualSkill = useCallback(\n async (\n skillName: string,\n params?: Record<string, unknown>,\n callbacks?: SkillExecuteCallbacks\n ): Promise<SkillExecutionResult | null> => {\n const skill = resolvedSkills[skillName];\n if (!skill) return null;\n\n setActiveSkillExecution({\n skillName,\n params: params || {},\n status: 'executing',\n });\n\n const abortController = new AbortController();\n executionAbortRef.current = abortController;\n\n try {\n /** @Todo vibecode - 콜백 머지: 내부 상태 업데이트 + 외부 콜백 전달 */\n const mergedCallbacks: SkillExecuteCallbacks = {\n onProgress: (progress) => {\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, progress } : null\n );\n callbacks?.onProgress?.(progress);\n },\n onStream: callbacks?.onStream,\n signal: callbacks?.signal || abortController.signal,\n };\n\n const result = await skill.execute(params || {}, mergedCallbacks);\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, status: 'done', result } : null\n );\n return result;\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, status: 'error', error: errorMsg } : null\n );\n return null;\n } finally {\n executionAbortRef.current = null;\n }\n },\n [resolvedSkills]\n );\n\n return {\n buildSkillsPrompt,\n handleSkillCall,\n manualSkills,\n executeManualSkill,\n activeSkillExecution,\n resolvedSkills,\n };\n};\n\nexport default useSkills;\n","/**\n * @description Skill 파싱 유틸리티\n * @Todo vibecode - AI 응답에서 <skill_use> 태그 파싱\n *\n * 형식:\n * <skill_use name=\"deepResearch\">{\"query\":\"검색어\"}</skill_use>\n */\n\n/**\n * @description 파싱된 스킬 호출 정보\n */\nexport interface ParsedSkillCall {\n /** 스킬 이름 */\n name: string;\n /** 실행 파라미터 */\n params: Record<string, unknown>;\n /** 원본 매칭 문자열 */\n rawMatch: string;\n}\n\n/**\n * @description AI 응답에서 <skill_use> 태그 파싱\n * @Todo vibecode - 첫 번째 매칭만 처리 (스킬은 한번에 하나씩)\n */\nexport const parseSkillCallFromContent = (\n content: string\n): { skillCall: ParsedSkillCall | null; cleanContent: string } => {\n const skillRegex = /<skill_use\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/skill_use>/i;\n const match = skillRegex.exec(content);\n\n if (!match) {\n return { skillCall: null, cleanContent: content };\n }\n\n const name = match[1];\n let params: Record<string, unknown> = {};\n try {\n params = JSON.parse(match[2].trim());\n } catch {\n /** @Todo vibecode - JSON 파싱 실패 시 텍스트를 query 파라미터로 사용 */\n params = { query: match[2].trim() };\n }\n\n const cleanContent = content.replace(match[0], '').trim();\n return {\n skillCall: { name, params, rawMatch: match[0] },\n cleanContent,\n };\n};\n\nexport default parseSkillCallFromContent;\n","/**\n * @description 고급 딥리서치 스킬 생성기\n * @Todo vibecode - useDeepResearch 4단계 파이프라인을 SkillConfig으로 통합\n *\n * 4단계 아키텍처:\n * 1. 쿼리 분석 - LLM이 서브토픽 + 검색 쿼리 분해\n * 2. 병렬 검색 - 토픽별 병렬 서브에이전트\n * 3. 충분성 평가 - 소스 부족 시 추가 검색\n * 4. 보고서 생성 - LLM 스트리밍 보고서 + 인라인 인용\n */\n\nimport type {\n SkillConfig,\n SkillExecutionResult,\n SkillExecuteCallbacks,\n SkillProgress,\n SearchResult,\n SourceItem,\n SubAgentProgress,\n DeepResearchCallbacks,\n} from '../types';\n\n// ============================================================================\n// 옵션 타입\n// ============================================================================\n\n/**\n * @description 고급 딥리서치 스킬 옵션\n * @Todo vibecode - 라이브러리 사용자가 제공하는 검색 API + LLM 엔드포인트\n */\nexport interface AdvancedResearchOptions {\n /** 웹 검색 API 호출 (필수) */\n onWebSearch: (query: string) => Promise<SearchResult[]>;\n /** 페이지 본문 추출 (선택) */\n onExtractContent?: (url: string) => Promise<string>;\n /** LLM API 엔드포인트 */\n apiEndpoint: string;\n /** API 키 */\n apiKey?: string;\n /** 사용할 모델 */\n model: string;\n /** 프로바이더 */\n provider: string;\n}\n\n// ============================================================================\n// 프롬프트 템플릿\n// ============================================================================\n\n/** @Todo vibecode - 1단계: 쿼리 분석 프롬프트 */\nconst QUERY_ANALYSIS_PROMPT = `사용자 질문을 분석하여 심층연구를 위한 검색 계획을 수립하세요.\n\n<user_question>\n{question}\n</user_question>\n\n응답은 반드시 다음 JSON 형식으로만 작성하세요:\n{\n \"questionType\": \"factCheck\" | \"comparison\" | \"comprehensive\",\n \"topics\": [\"서브토픽1\", \"서브토픽2\", \"서브토픽3\"],\n \"searchQueries\": [\"검색어1\", \"검색어2\", \"검색어3\", \"검색어4\", \"검색어5\"]\n}\n\n규칙:\n- topics: 3-5개의 핵심 서브토픽\n- searchQueries: 5-8개의 다양한 검색 쿼리 (한국어/영어 혼합)\n- JSON 외 다른 텍스트 출력 금지`;\n\n/** @Todo vibecode - 4단계: 보고서 생성 프롬프트 */\nconst REPORT_GENERATION_PROMPT = `당신은 리서치 보고서 작성 전문가입니다.\n\n<collected_sources>\n{sources_json}\n</collected_sources>\n\n<user_question>\n{question}\n</user_question>\n\n<format_rules>\n1. 핵심 요약 2-3문장으로 시작 (헤더 없이)\n2. ## 헤더로 섹션 구분\n3. 문장 끝에 인라인 인용 [1][2] 형태로 출처 표시\n4. 종합 결론으로 마무리\n5. 이모지 사용 금지\n</format_rules>\n\n<structure>\n[요약 2-3문장]\n\n## 상세 분석\n깊이 있는 분석 [1][2]\n\n## 주요 발견\n- 핵심 포인트 1 [3]\n- 핵심 포인트 2 [4]\n\n## 결론\n종합적인 결론\n</structure>`;\n\n// ============================================================================\n// 내부 타입\n// ============================================================================\n\ninterface ResearchPlan {\n questionType: 'factCheck' | 'comparison' | 'comprehensive';\n topics: string[];\n searchQueries: string[];\n}\n\ninterface SubAgentResult {\n topic: string;\n sources: SearchResult[];\n}\n\n// ============================================================================\n// 순수 함수: LLM 호출\n// ============================================================================\n\n/**\n * @description LLM API 비스트리밍 호출\n * @Todo vibecode - useDeepResearch.callLLM 순수 함수 버전\n */\nconst callLLM = async (\n prompt: string,\n opts: { apiEndpoint: string; apiKey?: string; model: string; provider: string; signal?: AbortSignal }\n): Promise<string> => {\n const response = await fetch(opts.apiEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(opts.apiKey && { Authorization: `Bearer ${opts.apiKey}` }),\n },\n body: JSON.stringify({\n model: opts.model,\n provider: opts.provider,\n messages: [{ role: 'user', content: prompt }],\n stream: false,\n }),\n signal: opts.signal,\n });\n\n if (!response.ok) throw new Error(`API 오류: ${response.status}`);\n const data = await response.json();\n return data.choices?.[0]?.message?.content || data.content || '';\n};\n\n/**\n * @description LLM API 스트리밍 호출\n * @Todo vibecode - 보고서 생성 시 실시간 청크 전달\n */\nconst callLLMStream = async (\n prompt: string,\n opts: { apiEndpoint: string; apiKey?: string; model: string; provider: string; signal?: AbortSignal },\n onChunk: (chunk: string) => void\n): Promise<string> => {\n const response = await fetch(opts.apiEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(opts.apiKey && { Authorization: `Bearer ${opts.apiKey}` }),\n },\n body: JSON.stringify({\n model: opts.model,\n provider: opts.provider,\n messages: [{ role: 'user', content: prompt }],\n stream: true,\n }),\n signal: opts.signal,\n });\n\n if (!response.ok) throw new Error(`API 오류: ${response.status}`);\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader');\n\n const decoder = new TextDecoder();\n let fullContent = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n const lines = chunk.split('\\n');\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n\n try {\n const parsed = JSON.parse(data);\n const content = parsed.choices?.[0]?.delta?.content || parsed.delta?.content || parsed.message?.content || parsed.content || parsed.text || '';\n if (content) {\n fullContent += content;\n onChunk(content);\n }\n } catch {\n /** @Todo vibecode - JSON 파싱 실패 시 무시 */\n }\n }\n }\n }\n\n return fullContent;\n};\n\n// ============================================================================\n// 순수 함수: 4단계 파이프라인\n// ============================================================================\n\n/**\n * @description 1단계: 쿼리 분석 - LLM이 서브토픽과 검색 쿼리 분해\n * @Todo vibecode - useDeepResearch.analyzeQuery 순수 함수 버전\n */\nconst analyzeQuery = async (\n query: string,\n llmOpts: { apiEndpoint: string; apiKey?: string; model: string; provider: string; signal?: AbortSignal }\n): Promise<ResearchPlan> => {\n const prompt = QUERY_ANALYSIS_PROMPT.replace('{question}', query);\n const response = await callLLM(prompt, llmOpts);\n\n try {\n const jsonMatch = response.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n return JSON.parse(jsonMatch[0]) as ResearchPlan;\n }\n } catch {\n /** @Todo vibecode - JSON 파싱 실패 시 기본 플랜 */\n }\n\n return {\n questionType: 'comprehensive',\n topics: [query],\n searchQueries: [query, `${query} 최신`, `${query} 상세`],\n };\n};\n\n/**\n * @description 2단계: 서브에이전트 실행 - 토픽별 병렬 검색\n * @Todo vibecode - useDeepResearch.runSubAgent 순수 함수 버전\n */\nconst runSubAgent = async (\n topic: string,\n queries: string[],\n onWebSearch: (query: string) => Promise<SearchResult[]>,\n onExtractContent: ((url: string) => Promise<string>) | undefined,\n updateProgress: (update: Partial<SubAgentProgress>) => void\n): Promise<SubAgentResult> => {\n updateProgress({ status: 'searching', searchCount: 0, resultsCount: 0 });\n\n const allResults: SearchResult[] = [];\n let searchCount = 0;\n\n for (const query of queries.slice(0, 3)) {\n try {\n searchCount++;\n updateProgress({ searchCount });\n\n const results = await onWebSearch(query);\n allResults.push(...results);\n updateProgress({ resultsCount: allResults.length });\n\n if (allResults.length >= 10) break;\n } catch (error) {\n /** @Todo vibecode - 개별 검색 실패 시 무시하고 계속 */\n console.error(`검색 오류 (${query}):`, error);\n }\n }\n\n /** @Todo vibecode - 본문 추출 (선택) */\n if (onExtractContent && allResults.length > 0) {\n updateProgress({ status: 'extracting' });\n\n const topResults = allResults.slice(0, 5);\n await Promise.all(\n topResults.map(async (result) => {\n try {\n const content = await onExtractContent(result.url);\n result.content = content.slice(0, 2000);\n } catch {\n /** @Todo vibecode - 추출 실패 시 스니펫 사용 */\n }\n })\n );\n }\n\n updateProgress({ status: 'done' });\n return { topic, sources: allResults };\n};\n\n/**\n * @description 4단계: 보고서 생성 - LLM 스트리밍\n * @Todo vibecode - useDeepResearch.generateReport 순수 함수 버전\n */\nconst generateReport = async (\n query: string,\n results: SubAgentResult[],\n llmOpts: { apiEndpoint: string; apiKey?: string; model: string; provider: string; signal?: AbortSignal },\n onChunk: (chunk: string) => void\n): Promise<{ content: string; sources: SourceItem[] }> => {\n const allSources: SourceItem[] = [];\n const sourcesForPrompt: { index: number; title: string; url: string; snippet: string }[] = [];\n\n results.forEach((result) => {\n result.sources.forEach((source) => {\n const index = allSources.length + 1;\n allSources.push({\n id: `source-${index}`,\n title: source.title,\n url: source.url,\n snippet: source.snippet,\n });\n sourcesForPrompt.push({\n index,\n title: source.title,\n url: source.url,\n snippet: source.content || source.snippet,\n });\n });\n });\n\n const prompt = REPORT_GENERATION_PROMPT\n .replace('{sources_json}', JSON.stringify(sourcesForPrompt, null, 2))\n .replace('{question}', query);\n\n const content = await callLLMStream(prompt, llmOpts, onChunk);\n return { content, sources: allSources };\n};\n\n// ============================================================================\n// 공개 API\n// ============================================================================\n\n/**\n * @description 고급 딥리서치 SkillConfig 생성\n * @Todo vibecode - 4단계 파이프라인을 SkillConfig으로 래핑\n *\n * @example\n * ```tsx\n * skills={{\n * deepResearch: createAdvancedResearchSkill({\n * onWebSearch: mySearchAPI,\n * apiEndpoint: '/api/chat',\n * model: 'gpt-4o-mini',\n * provider: 'devdive',\n * })\n * }}\n * ```\n */\nexport const createAdvancedResearchSkill = (\n options: AdvancedResearchOptions\n): SkillConfig => {\n const { onWebSearch, onExtractContent, apiEndpoint, apiKey, model, provider } = options;\n\n return {\n description: '심층 리서치 수행 - 웹 검색을 통해 여러 소스를 조사하고 종합 보고서를 생성합니다',\n trigger: 'both',\n execute: async (params, callbacks?): Promise<SkillExecutionResult> => {\n const query = (params as { query: string }).query;\n if (!query) {\n return { content: '검색어가 필요합니다.' };\n }\n\n const llmOpts = { apiEndpoint, apiKey, model, provider, signal: callbacks?.signal };\n const subAgentStates = new Map<string, SubAgentProgress>();\n\n /** @Todo vibecode - 서브에이전트 진행 상태를 통합하여 onProgress 호출 */\n const emitProgress = (phase: string, phaseLabel: string) => {\n callbacks?.onProgress?.({\n phase,\n phaseLabel,\n subAgents: Array.from(subAgentStates.values()),\n totalSources: Array.from(subAgentStates.values()).reduce(\n (sum, a) => sum + a.resultsCount, 0\n ),\n });\n };\n\n const updateSubAgent = (id: string, update: Partial<SubAgentProgress>) => {\n const current = subAgentStates.get(id) || {\n id, topic: '', status: 'pending' as const, searchCount: 0, resultsCount: 0,\n };\n subAgentStates.set(id, { ...current, ...update });\n emitProgress('researching', '정보 수집 중...');\n };\n\n // ── 1단계: 쿼리 분석 ──\n callbacks?.onProgress?.({\n phase: 'analyzing',\n phaseLabel: '질문 분석 중...',\n subAgents: [],\n totalSources: 0,\n });\n\n const plan = await analyzeQuery(query, llmOpts);\n\n // ── 2단계: 병렬 서브에이전트 실행 ──\n plan.topics.forEach((topic, index) => {\n subAgentStates.set(`agent-${index}`, {\n id: `agent-${index}`,\n topic,\n status: 'pending',\n searchCount: 0,\n resultsCount: 0,\n });\n });\n emitProgress('researching', '정보 수집 중...');\n\n const results = await Promise.all(\n plan.topics.map((topic, index) => {\n const agentId = `agent-${index}`;\n const relatedQueries = plan.searchQueries.filter(\n (q) =>\n q.toLowerCase().includes(topic.toLowerCase()) ||\n topic.toLowerCase().includes(q.toLowerCase().split(' ')[0])\n );\n const queries = relatedQueries.length > 0\n ? relatedQueries\n : [topic, ...plan.searchQueries.slice(0, 2)];\n\n return runSubAgent(\n topic,\n queries,\n onWebSearch,\n onExtractContent,\n (update) => updateSubAgent(agentId, { ...update, topic })\n );\n })\n );\n\n // ── 3단계: 충분성 평가 ──\n callbacks?.onProgress?.({\n phase: 'evaluating',\n phaseLabel: '결과 평가 중...',\n subAgents: Array.from(subAgentStates.values()),\n totalSources: results.reduce((sum, r) => sum + r.sources.length, 0),\n });\n\n const totalSources = results.reduce((sum, r) => sum + r.sources.length, 0);\n\n /** @Todo vibecode - 소스 부족 시 추가 검색 */\n if (totalSources < 5) {\n const additionalId = 'agent-additional';\n subAgentStates.set(additionalId, {\n id: additionalId,\n topic: query,\n status: 'pending',\n searchCount: 0,\n resultsCount: 0,\n });\n emitProgress('researching', '추가 검색 중...');\n\n const additionalResult = await runSubAgent(\n query,\n [query, `${query} 정보`, `${query} 최신 뉴스`],\n onWebSearch,\n onExtractContent,\n (update) => updateSubAgent(additionalId, { ...update, topic: query })\n );\n results.push(additionalResult);\n }\n\n // ── 4단계: 보고서 생성 ──\n callbacks?.onProgress?.({\n phase: 'generating',\n phaseLabel: '보고서 작성 중...',\n subAgents: Array.from(subAgentStates.values()),\n totalSources: results.reduce((sum, r) => sum + r.sources.length, 0),\n });\n\n const report = await generateReport(\n query,\n results,\n llmOpts,\n (chunk) => callbacks?.onStream?.(chunk)\n );\n\n callbacks?.onProgress?.({\n phase: 'done',\n phaseLabel: '완료',\n subAgents: Array.from(subAgentStates.values()),\n totalSources: report.sources.length,\n });\n\n return {\n content: report.content,\n sources: report.sources,\n };\n },\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string', description: '검색할 질문' },\n },\n required: ['query'],\n },\n icon: 'search',\n label: '심층연구',\n };\n};\n\n/**\n * @description 하위 호환용 단순 딥리서치 스킬 생성 (기존 DeepResearchCallbacks 래핑)\n * @deprecated createAdvancedResearchSkill 사용 권장\n * @Todo vibecode - 기존 deepResearch prop 사용자를 위한 하위 호환\n */\nexport const createDeepResearchSkill = (\n callbacks: DeepResearchCallbacks\n): SkillConfig => {\n return {\n description: '심층 리서치 수행 - 웹 검색을 통해 여러 소스를 조사하고 종합 보고서를 생성합니다',\n trigger: 'both',\n execute: async (params, skillCallbacks?): Promise<SkillExecutionResult> => {\n const query = (params as { query: string }).query;\n if (!query) {\n return { content: '검색어가 필요합니다.' };\n }\n\n const allSources: SourceItem[] = [];\n const searchQueries = [query, `${query} 최신`, `${query} 상세`];\n\n skillCallbacks?.onProgress?.({\n phase: 'researching',\n phaseLabel: '정보 수집 중...',\n subAgents: searchQueries.map((q, i) => ({\n id: `agent-${i}`,\n topic: q,\n status: 'searching' as const,\n searchCount: 0,\n resultsCount: 0,\n })),\n totalSources: 0,\n });\n\n for (const q of searchQueries) {\n try {\n const results = await callbacks.onWebSearch(q);\n results.forEach((r) => {\n allSources.push({\n id: `source-${allSources.length + 1}`,\n title: r.title,\n url: r.url,\n snippet: r.snippet,\n });\n });\n } catch {\n /** @Todo vibecode - 개별 검색 실패 시 무시하고 계속 */\n }\n }\n\n skillCallbacks?.onProgress?.({\n phase: 'done',\n phaseLabel: '완료',\n subAgents: [],\n totalSources: allSources.length,\n });\n\n const sourceSummary = allSources\n .slice(0, 15)\n .map((s, i) => `[${i + 1}] ${s.title}\\n${s.snippet}\\nURL: ${s.url}`)\n .join('\\n\\n');\n\n return {\n content: sourceSummary || '검색 결과가 없습니다.',\n sources: allSources.slice(0, 15),\n };\n },\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string', description: '검색할 질문' },\n },\n required: ['query'],\n },\n icon: 'search',\n label: '심층연구',\n };\n};\n\nexport default createAdvancedResearchSkill;\n","/**\n * @description 프로젝트 관리 훅 - CRUD, lazy loading, 기본 프로젝트 관리\n * @Todo vibecode - useChatUI의 세션 관리 패턴을 따름\n */\n\nimport { useState, useCallback, useEffect, useRef } from 'react';\nimport type { ChatProject, ProjectFile } from '../types';\nimport { DEFAULT_PROJECT_ID, createDefaultProject } from '../utils/projectMigration';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface UseProjectOptions {\n /** @Todo vibecode - false이면 Hook 내부 로직 비활성 (Hook 규칙 준수용) */\n enabled?: boolean;\n /** 외부 스토리지 사용 여부 */\n useExternalStorage?: boolean;\n /** 스토리지 키 (localStorage 사용 시) */\n storageKey?: string;\n /** @Todo vibecode - 외부 스토리지 콜백들 */\n onLoadProjects?: () => Promise<{ id: string; title: string }[]>;\n onCreateProject?: (data: Partial<ChatProject>) => Promise<{ id: string; title: string }>;\n onLoadProject?: (projectId: string) => Promise<ChatProject>;\n onUpdateProject?: (projectId: string, data: Partial<ChatProject>) => Promise<void>;\n onDeleteProject?: (projectId: string) => Promise<void>;\n onAddProjectFile?: (projectId: string, file: File) => Promise<ProjectFile>;\n onDeleteProjectFile?: (projectId: string, fileId: string) => Promise<void>;\n onError?: (error: Error) => void;\n}\n\nexport interface UseProjectReturn {\n projects: ChatProject[];\n currentProjectId: string | null;\n currentProject: ChatProject | null;\n isProjectsLoading: boolean;\n createProject: (data: { title: string; description?: string; instructions?: string }) => Promise<string>;\n selectProject: (projectId: string) => Promise<void>;\n updateProject: (projectId: string, data: Partial<ChatProject>) => Promise<void>;\n deleteProject: (projectId: string) => Promise<void>;\n addFile: (projectId: string, file: File) => Promise<void>;\n deleteFile: (projectId: string, fileId: string) => Promise<void>;\n}\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\nconst generateId = (prefix: string): string =>\n `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport const useProject = (options: UseProjectOptions): UseProjectReturn => {\n const {\n enabled = true,\n useExternalStorage,\n storageKey = 'chatllm_sessions_projects',\n onLoadProjects,\n onCreateProject,\n onLoadProject,\n onUpdateProject,\n onDeleteProject,\n onAddProjectFile,\n onDeleteProjectFile,\n onError,\n } = options;\n\n const [projects, setProjects] = useState<ChatProject[]>([]);\n const [currentProjectId, setCurrentProjectId] = useState<string | null>(null);\n const [isProjectsLoading, setIsProjectsLoading] = useState(false);\n const initializedRef = useRef(false);\n\n // ============================================================================\n // Derived state\n // ============================================================================\n\n const currentProject = projects.find((p) => p.id === currentProjectId) || null;\n\n // ============================================================================\n // localStorage 저장\n // ============================================================================\n\n /** @Todo vibecode - localStorage 모드에서 프로젝트 상태 자동 저장 */\n useEffect(() => {\n if (!enabled || useExternalStorage || !initializedRef.current) return;\n if (projects.length > 0 && typeof window !== 'undefined') {\n localStorage.setItem(storageKey, JSON.stringify(projects));\n }\n }, [enabled, projects, storageKey, useExternalStorage]);\n\n // ============================================================================\n // 초기 로드\n // ============================================================================\n\n useEffect(() => {\n if (!enabled || initializedRef.current) return;\n initializedRef.current = true;\n\n const loadProjects = async () => {\n if (useExternalStorage && onLoadProjects) {\n /** @Todo vibecode - 외부 스토리지에서 프로젝트 목록 로드 */\n setIsProjectsLoading(true);\n try {\n const projectList = await onLoadProjects();\n const loadedProjects: ChatProject[] = projectList.map((p) => ({\n id: p.id,\n title: p.title,\n files: [],\n createdAt: Date.now(),\n updatedAt: Date.now(),\n }));\n\n /** @Todo vibecode - 기본 프로젝트 없으면 추가 */\n if (!loadedProjects.find((p) => p.id === DEFAULT_PROJECT_ID)) {\n loadedProjects.unshift(createDefaultProject());\n }\n\n setProjects(loadedProjects);\n setCurrentProjectId(loadedProjects[0]?.id || DEFAULT_PROJECT_ID);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n /** @Todo vibecode - 로드 실패 시 기본 프로젝트만 생성 */\n const fallback = [createDefaultProject()];\n setProjects(fallback);\n setCurrentProjectId(DEFAULT_PROJECT_ID);\n } finally {\n setIsProjectsLoading(false);\n }\n } else {\n /** @Todo vibecode - localStorage에서 프로젝트 로드 */\n try {\n const saved = typeof window !== 'undefined' ? localStorage.getItem(storageKey) : null;\n if (saved) {\n const parsed: ChatProject[] = JSON.parse(saved);\n if (!parsed.find((p) => p.id === DEFAULT_PROJECT_ID)) {\n parsed.unshift(createDefaultProject());\n }\n setProjects(parsed);\n setCurrentProjectId(parsed[0]?.id || DEFAULT_PROJECT_ID);\n } else {\n /** @Todo vibecode - 최초 사용 시 기본 프로젝트 생성 */\n const initial = [createDefaultProject()];\n setProjects(initial);\n setCurrentProjectId(DEFAULT_PROJECT_ID);\n }\n } catch {\n const initial = [createDefaultProject()];\n setProjects(initial);\n setCurrentProjectId(DEFAULT_PROJECT_ID);\n }\n }\n };\n\n loadProjects();\n }, [useExternalStorage, onLoadProjects, onError, storageKey]);\n\n // ============================================================================\n // Actions\n // ============================================================================\n\n /** @Todo vibecode - 프로젝트 생성 */\n const createProject = useCallback(\n async (data: { title: string; description?: string; instructions?: string }): Promise<string> => {\n const now = Date.now();\n\n if (useExternalStorage && onCreateProject) {\n try {\n const created = await onCreateProject(data);\n const newProject: ChatProject = {\n id: created.id,\n title: created.title,\n description: data.description,\n instructions: data.instructions,\n files: [],\n createdAt: now,\n updatedAt: now,\n };\n setProjects((prev) => [newProject, ...prev]);\n setCurrentProjectId(newProject.id);\n return newProject.id;\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n throw err;\n }\n }\n\n /** @Todo vibecode - localStorage 모드 로컬 생성 */\n const newProject: ChatProject = {\n id: generateId('project'),\n title: data.title,\n description: data.description,\n instructions: data.instructions,\n files: [],\n createdAt: now,\n updatedAt: now,\n };\n setProjects((prev) => [newProject, ...prev]);\n setCurrentProjectId(newProject.id);\n return newProject.id;\n },\n [useExternalStorage, onCreateProject, onError]\n );\n\n /** @Todo vibecode - 프로젝트 선택 (lazy loading) */\n const selectProject = useCallback(\n async (projectId: string) => {\n setCurrentProjectId(projectId);\n\n /** @Todo vibecode - 외부 스토리지 시 상세 정보 로드 */\n if (useExternalStorage && onLoadProject) {\n try {\n const detail = await onLoadProject(projectId);\n setProjects((prev) =>\n prev.map((p) =>\n p.id === projectId\n ? { ...p, ...detail, updatedAt: Date.now() }\n : p\n )\n );\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n }\n },\n [useExternalStorage, onLoadProject, onError]\n );\n\n /** @Todo vibecode - 프로젝트 수정 */\n const updateProject = useCallback(\n async (projectId: string, data: Partial<ChatProject>) => {\n setProjects((prev) =>\n prev.map((p) =>\n p.id === projectId\n ? { ...p, ...data, updatedAt: Date.now() }\n : p\n )\n );\n\n if (useExternalStorage && onUpdateProject) {\n try {\n await onUpdateProject(projectId, data);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n }\n },\n [useExternalStorage, onUpdateProject, onError]\n );\n\n /** @Todo vibecode - 프로젝트 삭제 (기본 프로젝트 삭제 불가) */\n const deleteProject = useCallback(\n async (projectId: string) => {\n if (projectId === DEFAULT_PROJECT_ID) return;\n\n setProjects((prev) => prev.filter((p) => p.id !== projectId));\n\n /** @Todo vibecode - 삭제된 프로젝트가 현재 프로젝트면 기본으로 전환 */\n setCurrentProjectId((prev) =>\n prev === projectId ? DEFAULT_PROJECT_ID : prev\n );\n\n if (useExternalStorage && onDeleteProject) {\n try {\n await onDeleteProject(projectId);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n }\n },\n [useExternalStorage, onDeleteProject, onError]\n );\n\n /** @Todo vibecode - 프로젝트 파일 추가 */\n const addFile = useCallback(\n async (projectId: string, file: File) => {\n if (useExternalStorage && onAddProjectFile) {\n try {\n const fileMeta = await onAddProjectFile(projectId, file);\n setProjects((prev) =>\n prev.map((p) =>\n p.id === projectId\n ? { ...p, files: [...p.files, fileMeta], updatedAt: Date.now() }\n : p\n )\n );\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n return;\n }\n\n /** @Todo vibecode - localStorage 모드 메타데이터만 저장 */\n const fileMeta: ProjectFile = {\n id: generateId('file'),\n name: file.name,\n type: file.type.startsWith('image/') ? 'image'\n : file.type === 'application/pdf' ? 'pdf'\n : file.type.startsWith('text/') ? 'text'\n : 'other',\n url: URL.createObjectURL(file),\n size: file.size,\n mimeType: file.type,\n uploadedAt: Date.now(),\n };\n setProjects((prev) =>\n prev.map((p) =>\n p.id === projectId\n ? { ...p, files: [...p.files, fileMeta], updatedAt: Date.now() }\n : p\n )\n );\n },\n [useExternalStorage, onAddProjectFile, onError]\n );\n\n /** @Todo vibecode - 프로젝트 파일 삭제 */\n const deleteFile = useCallback(\n async (projectId: string, fileId: string) => {\n setProjects((prev) =>\n prev.map((p) =>\n p.id === projectId\n ? { ...p, files: p.files.filter((f) => f.id !== fileId), updatedAt: Date.now() }\n : p\n )\n );\n\n if (useExternalStorage && onDeleteProjectFile) {\n try {\n await onDeleteProjectFile(projectId, fileId);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n }\n },\n [useExternalStorage, onDeleteProjectFile, onError]\n );\n\n return {\n projects,\n currentProjectId,\n currentProject,\n isProjectsLoading,\n createProject,\n selectProject,\n updateProject,\n deleteProject,\n addFile,\n deleteFile,\n };\n};\n","/**\n * @description localStorage 세션을 프로젝트 구조로 마이그레이션\n * @Todo vibecode - enableProjects 활성화 시 기존 세션에 projectId 할당\n */\n\nimport type { ChatProject, ChatSession } from '../types';\n\n/** @Todo vibecode - 기본 프로젝트 ID 상수 */\nexport const DEFAULT_PROJECT_ID = 'default';\n\n/** @Todo vibecode - 기본 프로젝트 제목 */\nexport const DEFAULT_PROJECT_TITLE = '기본 프로젝트';\n\n/**\n * @description 기본 프로젝트 객체 생성\n * @Todo vibecode - 프로젝트 초기화 시 사용\n */\nexport const createDefaultProject = (): ChatProject => ({\n id: DEFAULT_PROJECT_ID,\n title: DEFAULT_PROJECT_TITLE,\n description: '기존 대화를 포함하는 기본 프로젝트',\n instructions: '',\n files: [],\n createdAt: Date.now(),\n updatedAt: Date.now(),\n});\n\n/**\n * @description localStorage 세션 데이터를 프로젝트 구조로 마이그레이션\n * @Todo vibecode - 기존 세션에 projectId: 'default' 할당, 기본 프로젝트 생성\n */\nexport const migrateSessionsToProjects = (storageKey: string): void => {\n if (typeof window === 'undefined') return;\n\n const migratedFlag = `${storageKey}_project_migrated`;\n\n /** @Todo vibecode - 이미 마이그레이션 완료된 경우 스킵 */\n if (localStorage.getItem(migratedFlag)) return;\n\n const sessionsJson = localStorage.getItem(storageKey);\n if (!sessionsJson) {\n localStorage.setItem(migratedFlag, 'true');\n return;\n }\n\n try {\n const sessions: ChatSession[] = JSON.parse(sessionsJson);\n\n /** @Todo vibecode - 기존 세션에 projectId 할당 */\n const migratedSessions = sessions.map((session) => ({\n ...session,\n projectId: session.projectId || DEFAULT_PROJECT_ID,\n }));\n\n /** @Todo vibecode - 기본 프로젝트 생성 (없는 경우) */\n const projectsKey = `${storageKey}_projects`;\n const projectsJson = localStorage.getItem(projectsKey);\n let projects: ChatProject[] = projectsJson ? JSON.parse(projectsJson) : [];\n\n if (!projects.find((p) => p.id === DEFAULT_PROJECT_ID)) {\n projects = [createDefaultProject(), ...projects];\n }\n\n localStorage.setItem(storageKey, JSON.stringify(migratedSessions));\n localStorage.setItem(projectsKey, JSON.stringify(projects));\n localStorage.setItem(migratedFlag, 'true');\n } catch {\n /** @Todo vibecode - 파싱 실패 시 마이그레이션 스킵 */\n localStorage.setItem(migratedFlag, 'true');\n }\n};\n","/**\n * @description Poll 파싱 유틸리티\n * @Todo vibecode - AI 응답에서 <poll> 태그 파싱\n */\n\nimport type { PollBlock, PollQuestion, PollOption } from '../types';\n\n/**\n * @description 고유 ID 생성\n * @Todo vibecode - Poll 요소 식별용\n */\nconst generateId = (): string => {\n return Math.random().toString(36).substring(2, 11);\n};\n\n/**\n * @description 마크다운 인라인 서식 제거 (bold, italic, code, strikethrough)\n * @Todo vibecode - AI에게 전달하는 응답 텍스트에서만 사용 (formatPollResponse)\n * 파싱 단계에서는 마크다운 보존 → PollCard의 renderInlineMarkdown이 렌더 시 처리\n */\nconst stripInlineMarkdown = (text: string): string =>\n text\n .replace(/\\*\\*(.+?)\\*\\*/g, '$1')\n .replace(/__(.+?)__/g, '$1')\n .replace(/\\*(.+?)\\*/g, '$1')\n .replace(/_(.+?)_/g, '$1')\n .replace(/`(.+?)`/g, '$1')\n .replace(/~~(.+?)~~/g, '$1');\n\n/**\n * @description AI 응답에서 <poll> 태그 파싱\n * @Todo vibecode - 지원 형식:\n *\n * 단순 형식:\n * <poll question=\"질문 내용\" multiSelect=\"true\">\n * - 옵션1\n * - 옵션2\n * </poll>\n *\n * 복잡 형식:\n * <poll>\n * <question multiSelect=\"true\">질문 내용</question>\n * <option>옵션1</option>\n * <option>옵션2</option>\n * </poll>\n */\nexport const parsePollFromContent = (\n content: string\n): { pollBlock: PollBlock | null; cleanContent: string } => {\n // <poll> 태그 매칭\n const pollRegex = /<poll([^>]*)>([\\s\\S]*?)<\\/poll>/gi;\n const polls: PollQuestion[] = [];\n let cleanContent = content;\n\n let match;\n while ((match = pollRegex.exec(content)) !== null) {\n const attributes = match[1];\n const innerContent = match[2].trim();\n\n // 속성에서 question 추출 (단순 형식)\n const questionAttrMatch = attributes.match(/question=[\"']([^\"']+)[\"']/i);\n const multiSelectAttrMatch = attributes.match(/multiSelect=[\"']?(true|false)[\"']?/i);\n const allowOtherAttrMatch = attributes.match(/allowOther=[\"']?(true|false)[\"']?/i);\n\n let questionText = questionAttrMatch?.[1] || '';\n let multiSelect = multiSelectAttrMatch?.[1]?.toLowerCase() === 'true';\n let allowOther = allowOtherAttrMatch?.[1]?.toLowerCase() !== 'false'; // 기본 true\n\n // <question> 태그 확인 (복잡 형식)\n const questionTagMatch = innerContent.match(\n /<question([^>]*)>([^<]+)<\\/question>/i\n );\n if (questionTagMatch) {\n const qAttrs = questionTagMatch[1];\n questionText = questionTagMatch[2].trim();\n\n const qMultiSelect = qAttrs.match(/multiSelect=[\"']?(true|false)[\"']?/i);\n const qAllowOther = qAttrs.match(/allowOther=[\"']?(true|false)[\"']?/i);\n\n if (qMultiSelect) {\n multiSelect = qMultiSelect[1].toLowerCase() === 'true';\n }\n if (qAllowOther) {\n allowOther = qAllowOther[1].toLowerCase() !== 'false';\n }\n }\n\n // 옵션 파싱\n const options: PollOption[] = [];\n\n // <option> 태그 형식\n const optionTagRegex = /<option([^>]*)>([^<]+)<\\/option>/gi;\n let optionMatch;\n while ((optionMatch = optionTagRegex.exec(innerContent)) !== null) {\n const optionAttrs = optionMatch[1];\n /** @Todo vibecode - 마크다운 보존: PollCard renderInlineMarkdown이 렌더 시 처리 */\n const optionLabel = optionMatch[2].trim();\n const descMatch = optionAttrs.match(/description=[\"']([^\"']+)[\"']/i);\n\n options.push({\n id: generateId(),\n label: optionLabel,\n description: descMatch?.[1] || undefined,\n });\n }\n\n // - 또는 * 리스트 형식 (옵션 태그가 없을 때)\n // 지원 형식: \"- 옵션\" 또는 \"- 옵션: 설명\"\n if (options.length === 0) {\n const listRegex = /^[-*]\\s+(.+)$/gm;\n let listMatch;\n while ((listMatch = listRegex.exec(innerContent)) !== null) {\n const fullText = listMatch[1].trim();\n /** @Todo vibecode - \"옵션: 설명\" 형식 파싱 (마크다운 보존) */\n const colonIndex = fullText.indexOf(':');\n if (colonIndex > 0) {\n const label = fullText.substring(0, colonIndex).trim();\n const description = fullText.substring(colonIndex + 1).trim();\n options.push({\n id: generateId(),\n label,\n description: description || undefined,\n });\n } else {\n options.push({\n id: generateId(),\n label: fullText,\n });\n }\n }\n }\n\n // 숫자 리스트 형식 (1. 2. 3.)\n if (options.length === 0) {\n const numberedRegex = /^\\d+[.)]\\s+(.+)$/gm;\n let numMatch;\n while ((numMatch = numberedRegex.exec(innerContent)) !== null) {\n options.push({\n id: generateId(),\n label: numMatch[1].trim(),\n });\n }\n }\n\n // 최소 2개 옵션이 있어야 유효한 poll\n if (questionText && options.length >= 2) {\n const pollQuestion = {\n id: generateId(),\n question: questionText,\n options,\n multiSelect,\n allowOther,\n required: false,\n };\n console.log('[pollParser] Parsed poll:', {\n question: pollQuestion.question,\n optionsCount: pollQuestion.options.length,\n options: pollQuestion.options.map(o => o.label),\n });\n polls.push(pollQuestion);\n }\n\n /**\n * @description 원본 콘텐츠에서 poll 태그 제거 + 빈 줄 정리\n * @Todo vibecode - 태그 제거 후 연속 빈 줄이 남아 공백 영역이 생기는 문제 수정\n */\n cleanContent = cleanContent.replace(match[0], '');\n }\n\n if (polls.length === 0) {\n return { pollBlock: null, cleanContent: content };\n }\n\n console.log('[pollParser] Total polls parsed:', polls.length, polls.map(p => p.question));\n\n /** @Todo vibecode - 3줄 이상 연속 개행을 2줄로 축소하여 빈 공백 제거 */\n cleanContent = cleanContent.replace(/\\n{3,}/g, '\\n\\n');\n\n return {\n pollBlock: {\n id: generateId(),\n questions: polls,\n currentIndex: 0,\n },\n cleanContent: cleanContent.trim(),\n };\n};\n\n/**\n * @description Poll 응답을 사용자 메시지 형식으로 변환\n * @Todo vibecode - AI에게 전달할 선택 결과 포맷팅 (명확한 답변 형태)\n */\nexport const formatPollResponse = (\n question: PollQuestion,\n selectedOptions: string[],\n otherText?: string\n): string => {\n /** @Todo vibecode - AI에 전달할 텍스트는 마크다운 제거 (plain text) */\n const selectedLabels = question.options\n .filter((opt) => selectedOptions.includes(opt.id))\n .map((opt) => stripInlineMarkdown(opt.label));\n\n if (otherText) {\n selectedLabels.push(otherText);\n }\n\n if (selectedLabels.length === 0) {\n return `건너뛰기를 선택했습니다. 다른 질문이 있으면 알려주세요.`;\n }\n\n // 더 자연스러운 답변 형태로 변환\n return `${selectedLabels.join(', ')}을(를) 선택했습니다. 이 선택을 바탕으로 진행해주세요.`;\n};\n\nexport default parsePollFromContent;\n","/**\n * @description Tool → Skill 변환 어댑터\n * @Todo vibecode - ChatToolDefinition을 SkillConfig로 변환하여 기존 Skills 인프라 재사용\n */\n\nimport type {\n ChatToolDefinition,\n ToolCallResult,\n SkillConfig,\n SkillExecutionResult,\n} from '../types';\n\n/**\n * @description 도구 정의 배열을 스킬 레코드로 변환\n * @Todo vibecode - 각 tool을 trigger: 'both' SkillConfig로 변환\n *\n * 변환 규칙:\n * - skill name = tool.name (접두사 없음)\n * - trigger: 'both' (AI 자동 호출 + '+' 메뉴에서 수동 선택)\n * - execute: onToolCall 호출 → SkillExecutionResult 반환\n * - metadata.__toolResult__: true (도구 결과 식별용)\n */\nexport const convertToolsToSkills = (\n tools: ChatToolDefinition[],\n onToolCall: (name: string, params: Record<string, unknown>) => Promise<ToolCallResult>,\n): Record<string, SkillConfig> => {\n const skillMap: Record<string, SkillConfig> = {};\n\n for (const tool of tools) {\n skillMap[tool.name] = {\n description: tool.description,\n /** @Todo vibecode - tool.trigger 지원 (기본 'both', 'attachment' 가능) */\n trigger: tool.trigger || 'both',\n label: tool.label || tool.name,\n icon: tool.icon,\n acceptedTypes: tool.acceptedTypes,\n autoConvertBase64: tool.autoConvertBase64,\n parameters: {\n type: 'object',\n properties: Object.fromEntries(\n Object.entries(tool.parameters).map(([key, param]) => [\n key,\n {\n type: param.type,\n description: param.description,\n enum: param.enum,\n },\n ]),\n ),\n required: Object.entries(tool.parameters)\n .filter(([, param]) => param.required)\n .map(([key]) => key),\n },\n execute: async (params: Record<string, unknown>): Promise<SkillExecutionResult> => {\n const result = await onToolCall(tool.name, params);\n return {\n content: result.content,\n /** @Todo vibecode - 도구 결과의 sources를 SkillExecutionResult로 전달 */\n sources: result.sources,\n metadata: {\n __toolResult__: true,\n resultType: result.type,\n toolName: tool.name,\n toolLabel: tool.label,\n toolIcon: tool.icon,\n ...result.metadata,\n },\n };\n },\n };\n }\n\n return skillMap;\n};\n\nexport default convertToolsToSkills;\n","/**\n * @description localStorage fallback cache for external storage mode\n * @Todo vibecode - useExternalStorage 모드에서 per-session 캐시 읽기/쓰기/삭제\n * onLoadSession 빈 응답/에러 시 fallback 복원용\n */\n\nimport type { ChatSession } from '../types';\n\n/**\n * @description 캐시 키 생성\n * @Todo vibecode - 세션별 개별 키로 5MB 제한 분산 + 개별 삭제 가능\n */\nconst buildCacheKey = (storageKey: string, sessionId: string): string =>\n `${storageKey}_cache_${sessionId}`;\n\n/**\n * @description 세션을 localStorage 캐시에 저장\n * @Todo vibecode - best-effort, 실패 시 무시 (quota exceeded 등)\n */\nexport const writeSessionCache = (\n storageKey: string,\n session: ChatSession\n): void => {\n if (typeof window === 'undefined') return;\n try {\n const key = buildCacheKey(storageKey, session.id);\n localStorage.setItem(key, JSON.stringify(session));\n } catch (error) {\n console.warn('[sessionCache] Failed to write cache:', error);\n }\n};\n\n/**\n * @description localStorage 캐시에서 세션 읽기\n * @Todo vibecode - 없거나 파싱 에러 시 null 반환\n */\nexport const readSessionCache = (\n storageKey: string,\n sessionId: string\n): ChatSession | null => {\n if (typeof window === 'undefined') return null;\n try {\n const key = buildCacheKey(storageKey, sessionId);\n const data = localStorage.getItem(key);\n if (!data) return null;\n return JSON.parse(data) as ChatSession;\n } catch {\n return null;\n }\n};\n\n/**\n * @description localStorage 캐시에서 세션 삭제\n * @Todo vibecode - 세션 삭제 시 캐시도 정리\n */\nexport const removeSessionCache = (\n storageKey: string,\n sessionId: string\n): void => {\n if (typeof window === 'undefined') return;\n try {\n const key = buildCacheKey(storageKey, sessionId);\n localStorage.removeItem(key);\n } catch {\n // Ignore errors on removal\n }\n};\n","/**\n * @description 채팅 사이드바 컴포넌트 - Modern Canvas 디자인\n * @Todo vibecode - v0.11.0 새 디자인 시스템 적용\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { IconSvg } from './Icon';\nimport { ProjectSelector } from './ProjectSelector';\nimport type { SidebarProps, ChatSession } from '../types';\n\nconst formatDate = (timestamp: number): string => {\n const date = new Date(timestamp);\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n const days = Math.floor(diff / (1000 * 60 * 60 * 24));\n\n if (days === 0) return '오늘';\n if (days === 1) return '어제';\n if (days < 7) return `${days}일 전`;\n return date.toLocaleDateString('ko-KR');\n};\n\nexport const ChatSidebar: React.FC<SidebarProps> = ({\n sessions,\n currentSessionId,\n onSelectSession,\n onNewSession,\n onDeleteSession,\n onRenameSession,\n isOpen,\n onToggle,\n width: widthProp,\n theme,\n projects,\n currentProjectId,\n onSelectProject,\n onNewProject,\n onProjectSettings,\n renderAfterHeader,\n renderFooter,\n isLoading = false,\n}) => {\n /** @Todo vibecode - 사이드바 너비 커스터마이징 (기본: 288px) */\n const sidebarWidth = typeof widthProp === 'number' ? `${widthProp}px` : (widthProp || '288px');\n\n const [editingId, setEditingId] = useState<string | null>(null);\n const [editingTitle, setEditingTitle] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (editingId && inputRef.current) {\n inputRef.current.focus();\n inputRef.current.select();\n }\n }, [editingId]);\n\n const handleStartEdit = (session: ChatSession, e: React.MouseEvent) => {\n e.stopPropagation();\n setEditingId(session.id);\n setEditingTitle(session.title);\n };\n\n const handleSaveEdit = () => {\n if (editingId && editingTitle.trim() && onRenameSession) {\n onRenameSession(editingId, editingTitle.trim());\n }\n setEditingId(null);\n setEditingTitle('');\n };\n\n const handleCancelEdit = () => {\n setEditingId(null);\n setEditingTitle('');\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleSaveEdit();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n handleCancelEdit();\n }\n };\n\n /** @Todo vibecode - theme prop으로 chatllm-root 밖에서도 CSS 변수 적용 */\n const themeClass = theme === 'dark' ? 'chatllm-dark' : '';\n\n return (\n <aside\n className={`chatllm-sidebar chatllm-sidebar-transition ${theme ? `chatllm-root ${themeClass}` : ''}`}\n style={{\n width: isOpen ? sidebarWidth : '0',\n height: '100%',\n flexShrink: 0,\n backgroundColor: 'var(--chatllm-sidebar-bg)',\n borderRight: isOpen ? '1px solid var(--chatllm-border)' : 'none',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n zIndex: 20,\n }}\n >\n <div\n style={{\n width: sidebarWidth,\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n padding: '24px',\n }}\n >\n {/* Header */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: '40px',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>\n <div\n style={{\n width: '28px',\n height: '28px',\n borderRadius: '6px',\n backgroundColor: 'var(--chatllm-primary)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 1px 2px rgba(0,0,0,0.05)',\n }}\n >\n <IconSvg name=\"chat-1-line\" size={16} color=\"#ffffff\" />\n </div>\n <span\n style={{\n fontSize: '14px',\n fontWeight: 700,\n letterSpacing: '-0.01em',\n color: 'var(--chatllm-text)',\n }}\n >\n AI 채팅\n </span>\n </div>\n </div>\n\n {/* Project Selector */}\n {projects && projects.length > 0 && onSelectProject && onNewProject && onProjectSettings && (\n <ProjectSelector\n projects={projects}\n currentProjectId={currentProjectId || null}\n onSelectProject={onSelectProject}\n onNewProject={onNewProject}\n onProjectSettings={onProjectSettings}\n />\n )}\n\n {/* New Chat Button */}\n <button\n onClick={onNewSession}\n className=\"chatllm-btn-primary\"\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '12px',\n padding: '12px 16px',\n marginBottom: '32px',\n borderRadius: '12px',\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n <IconSvg name=\"add-line\" size={20} color=\"#ffffff\" />\n <span>새 대화</span>\n </button>\n\n {/* Custom slot: after header */}\n {renderAfterHeader && renderAfterHeader()}\n\n {/* Sessions List */}\n <div\n className=\"chatllm-scrollbar\"\n style={{\n flex: 1,\n overflow: 'auto',\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n {isLoading ? (\n /* Skeleton Loading State */\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', padding: '0 4px' }}>\n {/** @Todo vibecode - 세션 목록 로딩 스켈레톤 (4개 바) */}\n {[1, 2, 3, 4].map((i) => (\n <div\n key={i}\n className=\"chatllm-skeleton-pulse\"\n style={{\n height: '48px',\n borderRadius: '8px',\n backgroundColor: 'var(--chatllm-bg-tertiary)',\n opacity: 1 - (i - 1) * 0.15,\n }}\n />\n ))}\n </div>\n ) : sessions.length === 0 ? (\n /* Empty State */\n <div\n style={{\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n textAlign: 'center',\n padding: '16px',\n }}\n >\n <div\n style={{\n width: '64px',\n height: '64px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-bg-tertiary)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginBottom: '16px',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n <IconSvg name=\"history-line\" size={32} />\n </div>\n <p\n style={{\n fontSize: '14px',\n fontWeight: 600,\n color: 'var(--chatllm-text-secondary)',\n marginBottom: '4px',\n }}\n >\n No history yet\n </p>\n <p\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n Your recent conversations will appear here.\n </p>\n </div>\n ) : (\n <>\n <div\n style={{\n fontSize: '11px',\n fontWeight: 700,\n color: 'var(--chatllm-text-muted)',\n textTransform: 'uppercase',\n letterSpacing: '0.1em',\n marginBottom: '12px',\n padding: '0 8px',\n }}\n >\n Recent activity\n </div>\n <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>\n {sessions.map((session) => {\n const isSelected = session.id === currentSessionId;\n return (\n <div\n key={session.id}\n onClick={() => onSelectSession(session.id)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '10px 12px',\n borderRadius: '8px',\n backgroundColor: isSelected\n ? 'var(--chatllm-bg-active)'\n : 'transparent',\n border: isSelected\n ? '1px solid var(--chatllm-border-light)'\n : '1px solid transparent',\n cursor: 'pointer',\n transition: 'all 0.2s',\n }}\n onMouseOver={(e) => {\n if (!isSelected) {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }\n }}\n onMouseOut={(e) => {\n if (!isSelected) {\n e.currentTarget.style.backgroundColor = 'transparent';\n }\n }}\n >\n <IconSvg\n name=\"chat-1-line\"\n size={18}\n color=\"var(--chatllm-text-muted)\"\n />\n <div style={{ flex: 1, minWidth: 0 }}>\n {editingId === session.id ? (\n <input\n ref={inputRef}\n type=\"text\"\n value={editingTitle}\n onChange={(e) => setEditingTitle(e.target.value)}\n onKeyDown={handleKeyDown}\n onBlur={handleSaveEdit}\n onClick={(e) => e.stopPropagation()}\n aria-label=\"세션 제목 편집\"\n style={{\n width: '100%',\n padding: '2px 6px',\n fontSize: '14px',\n fontWeight: 500,\n color: 'var(--chatllm-text)',\n backgroundColor: 'var(--chatllm-content-bg)',\n border: '1px solid var(--chatllm-primary)',\n borderRadius: '4px',\n outline: 'none',\n }}\n />\n ) : (\n <p\n style={{\n fontSize: '14px',\n fontWeight: 500,\n color: isSelected\n ? 'var(--chatllm-text)'\n : 'var(--chatllm-text-secondary)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n margin: 0,\n }}\n >\n {session.title}\n </p>\n )}\n </div>\n {/* Action Buttons - show on hover or when selected */}\n <div\n style={{\n display: 'flex',\n gap: '2px',\n opacity: isSelected ? 1 : 0,\n pointerEvents: isSelected ? 'auto' : 'none',\n transition: 'opacity 0.2s',\n }}\n className=\"session-actions\"\n >\n {onRenameSession && editingId !== session.id && (\n <button\n onClick={(e) => handleStartEdit(session, e)}\n aria-label=\"제목 편집\"\n style={{\n padding: '4px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n <IconSvg name=\"pencil-line\" size={14} />\n </button>\n )}\n <button\n onClick={(e) => {\n e.stopPropagation();\n onDeleteSession(session.id);\n }}\n aria-label=\"세션 삭제\"\n style={{\n padding: '4px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n <IconSvg name=\"delete-bin-line\" size={14} />\n </button>\n </div>\n </div>\n );\n })}\n </div>\n </>\n )}\n </div>\n\n {/* Custom slot: footer */}\n {renderFooter && renderFooter()}\n </div>\n </aside>\n );\n};\n\nexport default ChatSidebar;\n","/**\n * @description Remix Icons wrapper component\n * @see https://remixicon.com/\n * Using Remix Icons 4.6.0 via CDN or npm package\n */\n\nimport React from 'react';\n\nexport type IconName =\n // Navigation & UI\n | 'menu-line'\n | 'close-line'\n | 'arrow-left-line'\n | 'arrow-right-line'\n | 'arrow-down-s-line'\n | 'arrow-up-s-line'\n | 'more-line'\n | 'more-2-line'\n | 'settings-3-line'\n | 'settings-4-line'\n // Chat & Communication\n | 'chat-1-line'\n | 'chat-3-line'\n | 'chat-new-line'\n | 'message-2-line'\n | 'send-plane-line'\n | 'send-plane-fill'\n | 'question-answer-line'\n // Actions\n | 'add-line'\n | 'add-circle-line'\n | 'delete-bin-line'\n | 'delete-bin-6-line'\n | 'edit-line'\n | 'edit-2-line'\n | 'pencil-line'\n | 'check-line'\n | 'close-circle-line'\n | 'refresh-line'\n | 'loop-left-line'\n | 'stop-line'\n | 'stop-circle-line'\n | 'play-line'\n | 'pause-line'\n // Content\n | 'file-copy-line'\n | 'clipboard-line'\n | 'quote-text'\n | 'double-quotes-l'\n | 'double-quotes-r'\n // Search & Find\n | 'search-line'\n | 'search-2-line'\n | 'search-eye-line'\n | 'global-line'\n // Media\n | 'image-line'\n | 'image-add-line'\n | 'gallery-line'\n | 'video-line'\n | 'mic-line'\n // Code & Development\n | 'code-line'\n | 'code-s-slash-line'\n | 'terminal-box-line'\n | 'bug-line'\n | 'git-branch-line'\n // Document\n | 'file-text-line'\n | 'file-list-line'\n | 'article-line'\n | 'draft-line'\n | 'book-2-line'\n // AI & Magic\n | 'magic-line'\n | 'sparkling-line'\n | 'sparkling-2-line'\n | 'robot-line'\n | 'brain-line'\n // User\n | 'user-line'\n | 'user-3-line'\n | 'user-settings-line'\n | 'account-circle-line'\n // System\n | 'sun-line'\n | 'moon-line'\n | 'computer-line'\n | 'information-line'\n | 'error-warning-line'\n | 'checkbox-circle-line'\n | 'loader-4-line'\n // Misc\n | 'translate-2'\n | 'time-line'\n | 'history-line'\n | 'star-line'\n | 'star-fill'\n | 'heart-line'\n | 'thumb-up-line'\n | 'thumb-down-line'\n | 'attachment-line'\n | 'link'\n | 'links-line'\n | 'external-link-line'\n | 'download-line'\n | 'upload-line'\n | 'folder-line'\n | 'home-line'\n | 'dashboard-line'\n | 'list-check'\n | 'list-unordered'\n | 'key-line'\n | 'lock-line'\n | 'eye-line'\n | 'eye-off-line';\n\nexport interface IconProps {\n /** Icon name from Remix Icons */\n name: IconName;\n /** Size in pixels or CSS value */\n size?: number | string;\n /** CSS color value */\n color?: string;\n /** Additional CSS classes */\n className?: string;\n /** Additional inline styles */\n style?: React.CSSProperties;\n /** Click handler */\n onClick?: () => void;\n /** Accessibility label */\n 'aria-label'?: string;\n}\n\n/**\n * Remix Icons component\n * Uses CSS class-based icons (requires remixicon CSS)\n */\nexport const Icon: React.FC<IconProps> = ({\n name,\n size = 20,\n color,\n className = '',\n onClick,\n 'aria-label': ariaLabel,\n}) => {\n const sizeValue = typeof size === 'number' ? `${size}px` : size;\n\n return (\n <i\n className={`ri-${name} ${className}`}\n style={{\n fontSize: sizeValue,\n color,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n lineHeight: 1,\n }}\n onClick={onClick}\n aria-label={ariaLabel}\n role={onClick ? 'button' : undefined}\n tabIndex={onClick ? 0 : undefined}\n />\n );\n};\n\n/**\n * SVG-based Icon component (no external CSS required)\n * Icons are rendered inline as SVG\n */\nexport const IconSvg: React.FC<IconProps> = ({\n name,\n size = 20,\n color = 'currentColor',\n className = '',\n style,\n onClick,\n 'aria-label': ariaLabel,\n}) => {\n const sizeValue = typeof size === 'number' ? size : parseInt(size, 10) || 20;\n\n // Common SVG icons inline\n const icons: Partial<Record<IconName, React.ReactNode>> = {\n 'menu-line': (\n <path d=\"M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z\" />\n ),\n 'close-line': (\n <path d=\"M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z\" />\n ),\n 'add-line': (\n <path d=\"M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z\" />\n ),\n 'chat-1-line': (\n <path d=\"M10 3h4a8 8 0 1 1 0 16v3.5c-5-2-12-5-12-11.5a8 8 0 0 1 8-8zm2 14h2a6 6 0 0 0 0-12h-4a6 6 0 0 0-6 6c0 3.61 2.462 5.966 8 8.48V17z\" />\n ),\n 'send-plane-fill': (\n <path d=\"M1.946 9.315c-.522-.174-.527-.455.01-.634l19.087-6.362c.529-.176.832.12.684.638l-5.454 19.086c-.15.529-.455.547-.679.045L12 14l6-8-8 6-8.054-2.685z\" />\n ),\n 'send-plane-line': (\n <path d=\"M1.923 9.37c-.51-.205-.504-.51.034-.689l19.086-6.362c.529-.176.832.12.684.638l-5.454 19.086c-.15.529-.475.553-.717.07L12 14 3 10.5l8-4.25-9.077 3.12zM5.5 10.5l5.25 2.75 2.25 5.5 4-14-11.5 5.75z\" />\n ),\n 'search-line': (\n <path d=\"M18.031 16.617l4.283 4.282-1.415 1.415-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9 9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617zm-2.006-.742A6.977 6.977 0 0 0 18 11c0-3.868-3.133-7-7-7-3.868 0-7 3.132-7 7 0 3.867 3.132 7 7 7a6.977 6.977 0 0 0 4.875-1.975l.15-.15z\" />\n ),\n 'search-eye-line': (\n <path d=\"M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm0 2a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-12C5.373 4 0 12 0 12s5.373 8 12 8 12-8 12-8-5.373-8-12-8zm0 14c-4.418 0-8.268-3.582-9.538-6C3.732 9.582 7.582 6 12 6s8.268 3.582 9.538 6c-1.27 2.418-5.12 6-9.538 6z\" />\n ),\n 'image-line': (\n <path d=\"M4.828 21l-.02.02-.021-.02H2.992A.993.993 0 0 1 2 20.007V3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H4.828zM20 15V5H4v14L14 9l6 6zm0 2.828l-6-6L6.828 19H20v-1.172zM8 11a2 2 0 1 1 0-4 2 2 0 0 1 0 4z\" />\n ),\n 'code-s-slash-line': (\n <path d=\"M24 12l-5.657 5.657-1.414-1.414L21.172 12l-4.243-4.243 1.414-1.414L24 12zM2.828 12l4.243 4.243-1.414 1.414L0 12l5.657-5.657L7.07 7.757 2.828 12zm6.96 9H7.66l6.552-18h2.128L9.788 21z\" />\n ),\n 'file-text-line': (\n <path d=\"M21 8v12.993A1 1 0 0 1 20.007 22H3.993A.993.993 0 0 1 3 21.008V2.992C3 2.455 3.449 2 4.002 2h10.995L21 8zm-2 1h-5V4H5v16h14V9zM8 7h3v2H8V7zm0 4h8v2H8v-2zm0 4h8v2H8v-2z\" />\n ),\n 'delete-bin-line': (\n <path d=\"M17 6h5v2h-2v13a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V8H2V6h5V3a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v3zm1 2H6v12h12V8zm-9 3h2v6H9v-6zm4 0h2v6h-2v-6zM9 4v2h6V4H9z\" />\n ),\n 'edit-line': (\n <path d=\"M6.414 16L16.556 5.858l-1.414-1.414L5 14.586V16h1.414zm.829 2H3v-4.243L14.435 2.322a1 1 0 0 1 1.414 0l2.829 2.829a1 1 0 0 1 0 1.414L7.243 18zM3 20h18v2H3v-2z\" />\n ),\n 'check-line': (\n <path d=\"M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414z\" />\n ),\n 'file-copy-line': (\n <path d=\"M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1.001 1.001 0 0 1 3 20l.003-14c0-.552.45-1 1.007-1H7zM5.003 8L5 20h10V8H5.003zM9 6h8v10h2V4H9v2z\" />\n ),\n 'refresh-line': (\n <path d=\"M5.463 4.433A9.961 9.961 0 0 1 12 2c5.523 0 10 4.477 10 10 0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 0 0-2.46-5.772A7.96 7.96 0 0 0 12 4a7.96 7.96 0 0 0-5.54 2.228l1.414 1.414A5.972 5.972 0 0 1 12 6a5.99 5.99 0 0 1 3.88 1.42l-1.42 1.42A4 4 0 0 0 8.54 12H6V7l.002-.002 1.461 1.435zM18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12c0-2.136.67-4.116 1.81-5.74L7 12H4a8 8 0 0 0 2.46 5.772A7.96 7.96 0 0 0 12 20a7.96 7.96 0 0 0 5.54-2.228l-1.414-1.414A5.972 5.972 0 0 1 12 18a5.99 5.99 0 0 1-3.88-1.42l1.42-1.42A4 4 0 0 0 15.46 12H18v5l-.002.002-1.461-1.435z\" />\n ),\n 'stop-circle-line': (\n <path d=\"M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM9 9h6v6H9V9z\" />\n ),\n 'settings-3-line': (\n <path d=\"M3.34 17a10.018 10.018 0 0 1-.978-2.326 3 3 0 0 0 .002-5.347A9.99 9.99 0 0 1 4.865 4.99a3 3 0 0 0 4.631-2.674 9.99 9.99 0 0 1 5.007.002 3 3 0 0 0 4.632 2.672 10.018 10.018 0 0 1 2.525 4.337 3 3 0 0 0-.002 5.347 9.99 9.99 0 0 1-2.525 4.337 3 3 0 0 0-4.631 2.674 9.99 9.99 0 0 1-5.007-.002 3 3 0 0 0-4.632-2.672A10.018 10.018 0 0 1 3.34 17zm5.66.196a4.993 4.993 0 0 1 2.25 2.77c.499.047 1 .048 1.499.001A4.993 4.993 0 0 1 15 17.197a4.993 4.993 0 0 1 3.525-.565c.29-.408.54-.843.748-1.298A4.993 4.993 0 0 1 18 12c0-1.26.47-2.437 1.273-3.334a8.126 8.126 0 0 0-.75-1.298A4.993 4.993 0 0 1 15 6.804a4.993 4.993 0 0 1-2.25-2.77c-.499-.047-1-.048-1.499-.001A4.993 4.993 0 0 1 9 6.804a4.993 4.993 0 0 1-3.525.565 7.99 7.99 0 0 0-.748 1.298A4.993 4.993 0 0 1 6 12c0 1.26-.47 2.437-1.273 3.334a8.126 8.126 0 0 0 .75 1.298A4.993 4.993 0 0 1 9 17.196zM12 15a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z\" />\n ),\n 'loader-4-line': (\n <path d=\"M12 3a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7V3z\" />\n ),\n 'sparkling-line': (\n <path d=\"M14 4.438A2 2 0 0 1 15.438 3l4.62.764a2 2 0 0 1 1.112.529l.152.152a2 2 0 0 1 .529 1.112L22.5 10a2 2 0 0 1-.436 1.559l-.095.11L21 10.5l-3.3-3.3L14 4.438zm-3 1.124l5.5 5.5-9.086 9.086a2 2 0 0 1-2.828 0l-.172-.172a2 2 0 0 1 0-2.828L13.5 8.062 11 5.562zm-8.657 14.95a1 1 0 0 0 1.414 0l9.9-9.9-1.414-1.413-9.9 9.9a1 1 0 0 0 0 1.414z\" />\n ),\n 'arrow-down-s-line': (\n <path d=\"M12 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z\" />\n ),\n 'arrow-up-s-line': (\n <path d=\"M12 10.828l-4.95 4.95-1.414-1.414L12 8l6.364 6.364-1.414 1.414z\" />\n ),\n 'double-quotes-l': (\n <path d=\"M4.583 17.321C3.553 16.227 3 15 3 13.011c0-3.5 2.457-6.637 6.03-8.188l.893 1.378c-3.335 1.804-3.987 4.145-4.247 5.621.537-.278 1.24-.375 1.929-.311 1.804.167 3.226 1.648 3.226 3.489a3.5 3.5 0 0 1-3.5 3.5c-1.073 0-2.099-.49-2.748-1.179zm10 0C13.553 16.227 13 15 13 13.011c0-3.5 2.457-6.637 6.03-8.188l.893 1.378c-3.335 1.804-3.987 4.145-4.247 5.621.537-.278 1.24-.375 1.929-.311 1.804.167 3.226 1.648 3.226 3.489a3.5 3.5 0 0 1-3.5 3.5c-1.073 0-2.099-.49-2.748-1.179z\" />\n ),\n 'robot-line': (\n <path d=\"M13 4.055c4.5.497 8 4.312 8 8.945v9H3v-9c0-4.633 3.5-8.448 8-8.945V1h2v3.055zM5 20h14v-7a7 7 0 1 0-14 0v7zm2-7a5 5 0 0 1 10 0v4H7v-4zm2 0v2h2v-2H9zm4 0v2h2v-2h-2z\" />\n ),\n 'user-3-line': (\n <path d=\"M20 22h-2v-2a3 3 0 0 0-3-3H9a3 3 0 0 0-3 3v2H4v-2a5 5 0 0 1 5-5h6a5 5 0 0 1 5 5v2zm-8-9a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8z\" />\n ),\n 'sun-line': (\n <path d=\"M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z\" />\n ),\n 'moon-line': (\n <path d=\"M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z\" />\n ),\n 'key-line': (\n <path d=\"M12.917 13A6.002 6.002 0 0 1 1 12a6 6 0 0 1 11.917-1H23v6h-2v-4h-2v4h-2v-4h-4.083zM7 10a2 2 0 1 0 0 4 2 2 0 0 0 0-4z\" />\n ),\n 'links-line': (\n <path d=\"M17.657 14.828l-1.414-1.414L17.657 12A4 4 0 1 0 12 6.343l-1.414 1.414-1.414-1.414 1.414-1.414a6 6 0 0 1 8.485 8.485l-1.414 1.414zm-2.829 2.829l-1.414 1.414a6 6 0 1 1-8.485-8.485l1.414-1.414 1.414 1.414L6.343 12A4 4 0 1 0 12 17.657l1.414-1.414 1.414 1.414zm0-9.9l1.415 1.415-7.071 7.07-1.415-1.414 7.071-7.07z\" />\n ),\n 'external-link-line': (\n <path d=\"M10 6v2H5v11h11v-5h2v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h6zm11-3v8h-2V6.413l-7.793 7.794-1.414-1.414L17.585 5H13V3h8z\" />\n ),\n 'arrow-left-line': (\n <path d=\"M7.828 11H20v2H7.828l5.364 5.364-1.414 1.414L4 12l7.778-7.778 1.414 1.414z\" />\n ),\n 'arrow-right-line': (\n <path d=\"M16.172 11l-5.364-5.364 1.414-1.414L20 12l-7.778 7.778-1.414-1.414L16.172 13H4v-2z\" />\n ),\n 'magic-line': (\n <path d=\"M15.224 15.508l-2.213 4.65a.6.6 0 0 1-.542.342.6.6 0 0 1-.543-.342l-2.213-4.65-4.65-2.213a.6.6 0 0 1 0-1.086l4.65-2.213 2.213-4.65a.6.6 0 0 1 1.086 0l2.213 4.65 4.65 2.213a.6.6 0 0 1 0 1.086l-4.651 2.213zM6.5 19l1.18-2.478L10.158 17.5l-2.478-1.18L6.5 14l-1.18 2.32L2.842 17.5l2.478 1.022L6.5 19zM6.5 8l1.18-2.478L10.158 6.5l-2.478-1.18L6.5 3l-1.18 2.32L2.842 6.5l2.478 1.022L6.5 8z\" />\n ),\n 'attachment-line': (\n <path d=\"M14.828 7.757l-5.656 5.657a1 1 0 1 0 1.414 1.414l5.657-5.656A3 3 0 1 0 12 4.929l-5.657 5.657a5 5 0 1 0 7.071 7.07L19.071 12l1.414 1.414-5.657 5.657a7 7 0 1 1-9.9-9.9l5.658-5.656a5 5 0 0 1 7.07 7.07L12 16.244A3 3 0 1 1 7.757 12l5.657-5.657 1.414 1.414z\" />\n ),\n 'history-line': (\n <path d=\"M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12h2a8 8 0 1 0 .677-3.213l2.03.669A6 6 0 1 1 6 12H4a8 8 0 0 1 8-8zm1 5v4.585l3.243 3.243-1.414 1.414L11 12.415V7h2z\" />\n ),\n 'pencil-line': (\n <path d=\"M15.728 9.686l-1.414-1.414L5 17.586V19h1.414l9.314-9.314zm1.414-1.414l1.414-1.414-1.414-1.414-1.414 1.414 1.414 1.414zM7.242 21H3v-4.243L16.435 3.322a1 1 0 0 1 1.414 0l2.829 2.829a1 1 0 0 1 0 1.414L7.243 21z\" />\n ),\n };\n\n const iconPath = icons[name];\n\n return (\n <svg\n className={className}\n width={sizeValue}\n height={sizeValue}\n viewBox=\"0 0 24 24\"\n fill={color}\n onClick={onClick}\n aria-label={ariaLabel}\n role={onClick ? 'button' : 'img'}\n tabIndex={onClick ? 0 : undefined}\n style={{ display: 'inline-block', verticalAlign: 'middle', ...style }}\n >\n {iconPath || <path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z\" />}\n </svg>\n );\n};\n\nexport default Icon;\n","/**\n * @description 프로젝트 선택 드롭다운 - 사이드바 상단에 배치\n * @Todo vibecode - 프로젝트 전환, 생성, 설정 접근\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { IconSvg } from './Icon';\nimport type { ChatProject } from '../types';\n\nexport interface ProjectSelectorProps {\n projects: ChatProject[];\n currentProjectId: string | null;\n onSelectProject: (id: string) => void;\n onNewProject: () => void;\n onProjectSettings: (id: string) => void;\n}\n\nexport const ProjectSelector: React.FC<ProjectSelectorProps> = ({\n projects,\n currentProjectId,\n onSelectProject,\n onNewProject,\n onProjectSettings,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const currentProject = projects.find((p) => p.id === currentProjectId);\n\n /** @Todo vibecode - 외부 클릭 시 드롭다운 닫기 */\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) {\n setIsOpen(false);\n }\n };\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [isOpen]);\n\n return (\n <div ref={dropdownRef} style={{ position: 'relative', marginBottom: '12px' }}>\n {/* 드롭다운 트리거 버튼 */}\n <button\n onClick={() => setIsOpen(!isOpen)}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 12px',\n borderRadius: '8px',\n backgroundColor: 'var(--chatllm-bg-tertiary, #f5f5f5)',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n cursor: 'pointer',\n transition: 'background-color 0.15s',\n fontFamily: 'inherit',\n }}\n aria-expanded={isOpen}\n aria-haspopup='listbox'\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', overflow: 'hidden' }}>\n <div\n style={{\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: currentProject?.color || 'var(--chatllm-primary, #2563eb)',\n flexShrink: 0,\n }}\n />\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-text, #1a1a1a)',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {currentProject?.title || '기본 프로젝트'}\n </span>\n </div>\n <IconSvg\n name='arrow-down-s-line'\n size={16}\n color='var(--chatllm-text-muted, #999)'\n />\n </button>\n\n {/* 드롭다운 메뉴 */}\n {isOpen && (\n <div\n role='listbox'\n style={{\n position: 'absolute',\n top: 'calc(100% + 4px)',\n left: 0,\n right: 0,\n backgroundColor: 'var(--chatllm-content-bg, #fff)',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n borderRadius: '8px',\n boxShadow: '0 4px 12px rgba(0,0,0,0.1)',\n zIndex: 50,\n maxHeight: '280px',\n overflowY: 'auto',\n }}\n >\n {/* 프로젝트 목록 */}\n {projects.map((project) => (\n <div\n key={project.id}\n role='option'\n aria-selected={project.id === currentProjectId}\n onClick={() => {\n onSelectProject(project.id);\n setIsOpen(false);\n }}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 12px',\n cursor: 'pointer',\n backgroundColor: project.id === currentProjectId\n ? 'var(--chatllm-bg-hover, #f0f0f0)'\n : 'transparent',\n transition: 'background-color 0.1s',\n }}\n onMouseEnter={(e) => {\n if (project.id !== currentProjectId) {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--chatllm-bg-hover, #f0f0f0)';\n }\n }}\n onMouseLeave={(e) => {\n if (project.id !== currentProjectId) {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent';\n }\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', overflow: 'hidden' }}>\n <div\n style={{\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: project.color || 'var(--chatllm-primary, #2563eb)',\n flexShrink: 0,\n }}\n />\n <span\n style={{\n fontSize: '13px',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n >\n {project.title}\n </span>\n </div>\n {/* 설정 아이콘 */}\n <button\n onClick={(e) => {\n e.stopPropagation();\n onProjectSettings(project.id);\n setIsOpen(false);\n }}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '2px',\n opacity: 0.5,\n transition: 'opacity 0.1s',\n display: 'flex',\n alignItems: 'center',\n }}\n onMouseEnter={(e) => { (e.currentTarget as HTMLElement).style.opacity = '1'; }}\n onMouseLeave={(e) => { (e.currentTarget as HTMLElement).style.opacity = '0.5'; }}\n aria-label={`${project.title} 프로젝트 설정`}\n >\n <IconSvg name='settings-3-line' size={14} color='var(--chatllm-text-muted, #999)' />\n </button>\n </div>\n ))}\n\n {/* 구분선 */}\n <div style={{ height: '1px', backgroundColor: 'var(--chatllm-border, #e0e0e0)', margin: '4px 0' }} />\n\n {/* 새 프로젝트 버튼 */}\n <div\n onClick={() => {\n onNewProject();\n setIsOpen(false);\n }}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '10px 12px',\n cursor: 'pointer',\n transition: 'background-color 0.1s',\n }}\n onMouseEnter={(e) => { (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--chatllm-bg-hover, #f0f0f0)'; }}\n onMouseLeave={(e) => { (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent'; }}\n >\n <IconSvg name='add-line' size={16} color='var(--chatllm-primary, #2563eb)' />\n <span style={{ fontSize: '13px', fontWeight: 500, color: 'var(--chatllm-primary, #2563eb)' }}>\n 새 프로젝트\n </span>\n </div>\n </div>\n )}\n </div>\n );\n};\n","/**\n * @description 채팅 헤더 컴포넌트\n * 모델 선택, 설정 버튼\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\nimport type { HeaderProps } from '../types';\n\nexport const ChatHeader: React.FC<HeaderProps> = ({\n title,\n model,\n models,\n onModelChange,\n onSettingsOpen,\n onSidebarToggle,\n sidebarOpen,\n showModelSelector = true,\n showSettings = true,\n}) => {\n const [modelDropdownOpen, setModelDropdownOpen] = useState(false);\n\n const currentModel = models.find((m) => m.id === model);\n\n return (\n <header\n className=\"chatllm-header\"\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 24px',\n borderBottom: '1px solid var(--chatllm-border, #e5e7eb)',\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n }}\n >\n {/* Left: Sidebar Toggle & Title */}\n <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>\n <button\n onClick={onSidebarToggle}\n style={{\n width: '36px',\n height: '36px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover, #f3f4f6)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <IconSvg name=\"menu-line\" size={20} color=\"var(--chatllm-text, #1f2937)\" />\n </button>\n <h1\n style={{\n fontSize: '16px',\n fontWeight: 500,\n color: 'var(--chatllm-text, #1f2937)',\n margin: 0,\n }}\n >\n {title}\n </h1>\n </div>\n\n {/* Right: Model Selector & Settings */}\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n {/* Model Selector */}\n {showModelSelector && (\n <div style={{ position: 'relative' }}>\n <button\n onClick={() => setModelDropdownOpen(!modelDropdownOpen)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n cursor: 'pointer',\n transition: 'all 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.borderColor = 'var(--chatllm-primary, #3b82f6)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.borderColor = 'var(--chatllm-border, #e5e7eb)';\n }}\n >\n <IconSvg name=\"robot-line\" size={16} color=\"var(--chatllm-primary, #3b82f6)\" />\n <span style={{ fontSize: '14px', fontWeight: 500, color: 'var(--chatllm-text, #1f2937)' }}>\n {currentModel?.name || model}\n </span>\n <IconSvg\n name={modelDropdownOpen ? 'arrow-up-s-line' : 'arrow-down-s-line'}\n size={16}\n color=\"var(--chatllm-text-muted, #9ca3af)\"\n />\n </button>\n\n {/* Model Dropdown */}\n {modelDropdownOpen && (\n <>\n {/* Backdrop */}\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 99,\n }}\n onClick={() => setModelDropdownOpen(false)}\n />\n <div\n style={{\n position: 'absolute',\n top: '100%',\n right: 0,\n marginTop: '8px',\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n borderRadius: '12px',\n boxShadow: '0 4px 24px rgba(0, 0, 0, 0.12)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n padding: '8px',\n minWidth: '220px',\n zIndex: 100,\n }}\n >\n {/* Group by provider */}\n {Array.from(new Set(models.map((m) => m.provider))).map((provider) => (\n <div key={provider}>\n <div\n style={{\n padding: '8px 12px',\n fontSize: '11px',\n fontWeight: 600,\n color: 'var(--chatllm-text-muted, #9ca3af)',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n }}\n >\n {provider}\n </div>\n {models\n .filter((m) => m.provider === provider)\n .map((m) => (\n <button\n key={m.id}\n onClick={() => {\n onModelChange(m.id);\n setModelDropdownOpen(false);\n }}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 12px',\n backgroundColor: m.id === model ? 'var(--chatllm-bg-active, #eff6ff)' : 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n if (m.id !== model) {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover, #f9fafb)';\n }\n }}\n onMouseOut={(e) => {\n if (m.id !== model) {\n e.currentTarget.style.backgroundColor = 'transparent';\n }\n }}\n >\n <div\n style={{\n width: '28px',\n height: '28px',\n borderRadius: '6px',\n backgroundColor: m.id === model\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-bg-secondary, #f3f4f6)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg\n name=\"robot-line\"\n size={14}\n color={m.id === model ? '#ffffff' : 'var(--chatllm-text-muted, #9ca3af)'}\n />\n </div>\n <div>\n <div\n style={{\n fontSize: '14px',\n fontWeight: m.id === model ? 500 : 400,\n color: 'var(--chatllm-text, #1f2937)',\n }}\n >\n {m.name}\n </div>\n {m.description && (\n <div style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #9ca3af)' }}>\n {m.description}\n </div>\n )}\n </div>\n {m.id === model && (\n <IconSvg\n name=\"check-line\"\n size={16}\n color=\"var(--chatllm-primary, #3b82f6)\"\n className=\"ml-auto\"\n />\n )}\n </button>\n ))}\n </div>\n ))}\n </div>\n </>\n )}\n </div>\n )}\n\n {/* Settings Button */}\n {showSettings && (\n <button\n onClick={onSettingsOpen}\n style={{\n width: '36px',\n height: '36px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover, #f3f4f6)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <IconSvg name=\"settings-3-line\" size={20} color=\"var(--chatllm-text-muted, #6b7280)\" />\n </button>\n )}\n </div>\n </header>\n );\n};\n\nexport default ChatHeader;\n","/**\n * @description 채팅 입력창 컴포넌트 - Modern Canvas 디자인\n * @Todo vibecode - v0.11.0 새 디자인 시스템 적용 (플로팅 스타일)\n */\n\nimport React, { useRef, useEffect, useState } from 'react';\nimport { IconSvg } from './Icon';\nimport type { IconName } from './Icon';\nimport type { InputProps, ActionItem, ManualSkillItem, SkillExecution, ChatAttachment } from '../types';\n\nexport const ChatInput: React.FC<InputProps> = ({\n value,\n onChange,\n onSubmit,\n onStop,\n isLoading,\n placeholder = 'Message or ask a question...',\n quotedText,\n onClearQuote,\n selectedAction,\n onClearAction,\n onActionSelect,\n actions = [],\n onDeepResearch,\n isDeepResearchMode,\n deepResearchEnabled,\n manualSkills = [],\n onSkillSelect,\n activeSkillExecution,\n attachments = [],\n onFileAttach,\n onRemoveAttachment,\n acceptedFileTypes,\n onDisclaimerClick,\n}) => {\n const [mainMenuOpen, setMainMenuOpen] = React.useState(false);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [actionMenuOpen, setActionMenuOpen] = useState(false);\n const [isDragOver, setIsDragOver] = useState(false);\n const mainMenuRef = useRef<HTMLDivElement>(null);\n const actionMenuRef = useRef<HTMLDivElement>(null);\n\n // Auto-resize textarea\n useEffect(() => {\n if (textareaRef.current) {\n textareaRef.current.style.height = 'auto';\n textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 200)}px`;\n }\n }, [value]);\n\n // Close menus on outside click\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (mainMenuRef.current && !mainMenuRef.current.contains(event.target as Node)) {\n setMainMenuOpen(false);\n }\n if (actionMenuRef.current && !actionMenuRef.current.contains(event.target as Node)) {\n setActionMenuOpen(false);\n }\n };\n\n if (mainMenuOpen || actionMenuOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [mainMenuOpen, actionMenuOpen]);\n\n /**\n * @description 클립보드 붙여넣기로 파일 첨부\n * @Todo vibecode - Ctrl+V로 이미지 붙여넣기 지원\n */\n const handlePaste = (e: React.ClipboardEvent) => {\n const files = Array.from(e.clipboardData.files);\n if (files.length > 0 && onFileAttach) {\n e.preventDefault();\n onFileAttach(files);\n }\n };\n\n /**\n * @description 드래그앤드롭 파일 첨부\n * @Todo vibecode - 파일 드롭 시 첨부\n */\n const handleDrop = (e: React.DragEvent) => {\n e.preventDefault();\n setIsDragOver(false);\n const files = Array.from(e.dataTransfer.files);\n if (files.length > 0 && onFileAttach) {\n onFileAttach(files);\n }\n };\n\n const handleDragOver = (e: React.DragEvent) => {\n e.preventDefault();\n setIsDragOver(true);\n };\n\n const handleDragLeave = (e: React.DragEvent) => {\n e.preventDefault();\n setIsDragOver(false);\n };\n\n /**\n * @description 파일 선택 다이얼로그에서 파일 첨부\n * @Todo vibecode - \"+\" 메뉴 → \"파일 또는 사진 추가\" 클릭 시\n */\n const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(e.target.files || []);\n if (files.length > 0 && onFileAttach) {\n onFileAttach(files);\n }\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n };\n\n /** @Todo vibecode - 한글 IME 조합 중 Enter 방지 (isComposing 체크) */\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.nativeEvent.isComposing || e.keyCode === 229) return;\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n onSubmit();\n }\n };\n\n const handleActionSelect = (action: ActionItem) => {\n onActionSelect?.(action);\n setActionMenuOpen(false);\n };\n\n /**\n * @description 스킬 아이콘 매핑\n * @Todo vibecode - 스킬 icon 문자열 → IconSvg name 변환\n */\n const mapSkillIcon = (icon?: string): IconName => {\n const iconMap: Record<string, IconName> = {\n search: 'search-eye-line',\n image: 'image-line',\n code: 'code-s-slash-line',\n file: 'file-text-line',\n document: 'file-text-line',\n };\n return icon ? iconMap[icon] || 'sparkling-line' : 'sparkling-line';\n };\n\n return (\n <footer\n className=\"chatllm-input-footer\"\n style={{\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n paddingBottom: '16px',\n paddingTop: '64px',\n background: 'linear-gradient(to top, var(--chatllm-bg) 60%, transparent)',\n pointerEvents: 'none',\n }}\n >\n <div\n style={{\n width: '100%',\n maxWidth: '820px',\n padding: '0 24px',\n pointerEvents: 'auto',\n }}\n >\n {/* Skill Execution Chip */}\n {activeSkillExecution && activeSkillExecution.status === 'executing' && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 14px',\n marginBottom: '12px',\n backgroundColor: 'var(--chatllm-primary-light)',\n borderRadius: '9999px',\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-primary)',\n }}\n >\n <span\n className=\"chatllm-skeleton-pulse\"\n style={{\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-primary)',\n }}\n />\n {activeSkillExecution.skillName} 실행 중...\n </div>\n )}\n\n {/* Quote & Action Chips */}\n {(quotedText || selectedAction) && (\n <div style={{ display: 'flex', gap: '8px', marginBottom: '12px', flexWrap: 'wrap' }}>\n {/* Quote Chip */}\n {quotedText && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 12px',\n backgroundColor: 'var(--chatllm-content-bg)',\n borderRadius: '12px',\n border: '1px solid var(--chatllm-border)',\n maxWidth: '100%',\n }}\n >\n <IconSvg name=\"double-quotes-l\" size={14} color=\"var(--chatllm-primary)\" />\n <span\n style={{\n fontSize: '13px',\n color: 'var(--chatllm-text)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n maxWidth: '300px',\n }}\n >\n {quotedText}\n </span>\n <button\n onClick={onClearQuote}\n style={{\n padding: '2px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg name=\"close-line\" size={14} color=\"var(--chatllm-text-muted)\" />\n </button>\n </div>\n )}\n\n {/* Action Chip */}\n {selectedAction && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n padding: '8px 14px',\n backgroundColor: 'var(--chatllm-primary-light)',\n borderRadius: '9999px',\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-primary)',\n }}\n >\n <IconSvg name=\"sparkling-line\" size={14} color=\"var(--chatllm-primary)\" />\n {selectedAction.label}\n <button\n onClick={onClearAction}\n style={{\n padding: '2px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg name=\"close-line\" size={14} color=\"var(--chatllm-primary)\" />\n </button>\n </div>\n )}\n </div>\n )}\n\n {/* Hidden File Input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n accept={acceptedFileTypes?.join(',') || undefined}\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n />\n\n {/* Input Container */}\n <div\n className=\"chatllm-input-container\"\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n style={isDragOver ? { outline: '2px dashed var(--chatllm-primary)', outlineOffset: '-2px' } : undefined}\n >\n {/* Attachment Preview */}\n {attachments.length > 0 && (\n <div\n style={{\n display: 'flex',\n gap: '8px',\n padding: '12px 24px 0 24px',\n flexWrap: 'wrap',\n }}\n >\n {attachments.map((att) => (\n <div\n key={att.id}\n style={{\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: att.type === 'image' ? '0' : '8px 12px',\n backgroundColor: 'var(--chatllm-content-bg)',\n borderRadius: '12px',\n border: '1px solid var(--chatllm-border)',\n overflow: 'hidden',\n }}\n >\n {att.type === 'image' && att.previewUrl ? (\n <img\n src={att.previewUrl}\n alt={att.name}\n style={{\n width: '64px',\n height: '64px',\n objectFit: 'cover',\n borderRadius: '12px',\n }}\n />\n ) : (\n <>\n <IconSvg name=\"file-text-line\" size={16} color=\"var(--chatllm-text-muted)\" />\n <span style={{ fontSize: '13px', color: 'var(--chatllm-text)', maxWidth: '120px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {att.name}\n </span>\n </>\n )}\n {/* Remove Button */}\n <button\n onClick={() => onRemoveAttachment?.(att.id)}\n style={{\n position: 'absolute',\n top: '2px',\n right: '2px',\n width: '20px',\n height: '20px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'rgba(0,0,0,0.5)',\n border: 'none',\n borderRadius: '50%',\n cursor: 'pointer',\n padding: 0,\n }}\n >\n <IconSvg name=\"close-line\" size={12} color=\"#fff\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* Textarea */}\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n placeholder={placeholder}\n rows={1}\n style={{\n width: '100%',\n minHeight: '60px',\n maxHeight: '200px',\n padding: '24px 32px 8px 32px',\n backgroundColor: 'transparent',\n border: 'none',\n outline: 'none',\n fontSize: '16px',\n lineHeight: '1.5',\n resize: 'none',\n color: 'var(--chatllm-text)',\n }}\n />\n\n {/* Bottom Actions */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '0 24px 20px 24px',\n }}\n >\n {/* Left Actions */}\n <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>\n {/* Add Menu Button */}\n {actions.length > 0 && (\n <div ref={actionMenuRef} style={{ position: 'relative' }}>\n <button\n onClick={() => setActionMenuOpen(!actionMenuOpen)}\n style={iconButtonStyle}\n title=\"기능 추가\"\n >\n <IconSvg name=\"add-line\" size={22} color=\"var(--chatllm-text-muted)\" />\n </button>\n\n {/* Action Menu Dropdown */}\n {actionMenuOpen && (\n <div\n style={{\n position: 'absolute',\n bottom: '100%',\n left: 0,\n marginBottom: '8px',\n backgroundColor: 'var(--chatllm-content-bg)',\n borderRadius: '16px',\n boxShadow: 'var(--chatllm-shadow-sheet)',\n border: '1px solid var(--chatllm-border)',\n padding: '8px',\n minWidth: '220px',\n zIndex: 100,\n }}\n >\n {actions.map((action) => (\n <button\n key={action.id}\n onClick={() => handleActionSelect(action)}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '12px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <div\n style={{\n width: '36px',\n height: '36px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'var(--chatllm-primary-light)',\n borderRadius: '10px',\n }}\n >\n <IconSvg\n name={\n action.icon === 'search'\n ? 'search-line'\n : action.icon === 'image'\n ? 'image-line'\n : action.icon === 'code'\n ? 'code-s-slash-line'\n : 'file-text-line'\n }\n size={20}\n color=\"var(--chatllm-primary)\"\n />\n </div>\n <div>\n <div style={{ fontSize: '14px', fontWeight: 600, color: 'var(--chatllm-text)' }}>\n {action.label}\n </div>\n <div style={{ fontSize: '12px', color: 'var(--chatllm-text-muted)' }}>\n {action.description}\n </div>\n </div>\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n\n {/** @Todo vibecode - 파일 업로드 바로가기 버튼 (+ 메뉴 옆 배치) */}\n <button\n onClick={() => fileInputRef.current?.click()}\n style={iconButtonStyle}\n title=\"파일 첨부\"\n aria-label=\"파일 첨부\"\n >\n <IconSvg name=\"attachment-line\" size={22} color=\"var(--chatllm-text-muted)\" />\n </button>\n\n {/* Main Menu Button */}\n <div ref={mainMenuRef} style={{ position: 'relative' }}>\n <button\n onClick={() => setMainMenuOpen(!mainMenuOpen)}\n style={{\n ...iconButtonStyle,\n backgroundColor: mainMenuOpen ? 'var(--chatllm-bg-hover)' : 'transparent',\n }}\n title=\"메뉴\"\n >\n <IconSvg name=\"add-line\" size={22} color=\"var(--chatllm-text-muted)\" />\n </button>\n\n {/* Main Menu Dropdown */}\n {mainMenuOpen && (\n <div\n style={{\n position: 'absolute',\n bottom: '100%',\n left: 0,\n marginBottom: '8px',\n backgroundColor: 'var(--chatllm-content-bg)',\n borderRadius: '16px',\n boxShadow: 'var(--chatllm-shadow-sheet)',\n border: '1px solid var(--chatllm-border)',\n padding: '8px',\n minWidth: '240px',\n zIndex: 100,\n }}\n >\n {/* File Upload */}\n <button\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '12px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n onClick={() => {\n fileInputRef.current?.click();\n setMainMenuOpen(false);\n }}\n >\n <IconSvg name=\"attachment-line\" size={20} color=\"var(--chatllm-text-secondary)\" />\n <span style={{ fontSize: '14px', color: 'var(--chatllm-text)' }}>\n 파일 또는 사진 추가\n </span>\n </button>\n\n {/* Deep Research */}\n {/* Deep Research (하위 호환) */}\n {deepResearchEnabled && (\n <button\n onClick={() => {\n onDeepResearch?.();\n setMainMenuOpen(false);\n }}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '12px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <IconSvg\n name=\"search-eye-line\"\n size={20}\n color={isDeepResearchMode ? 'var(--chatllm-primary)' : 'var(--chatllm-text-secondary)'}\n />\n <span\n style={{\n flex: 1,\n fontSize: '14px',\n color: isDeepResearchMode ? 'var(--chatllm-primary)' : 'var(--chatllm-text)',\n }}\n >\n 연구\n </span>\n {isDeepResearchMode && (\n <IconSvg name=\"check-line\" size={16} color=\"var(--chatllm-primary)\" />\n )}\n </button>\n )}\n\n {/* Manual Skills */}\n {manualSkills.map((skill) => (\n <button\n key={skill.name}\n onClick={() => {\n onSkillSelect?.(skill.name);\n setMainMenuOpen(false);\n }}\n disabled={skill.disabled}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '12px',\n cursor: skill.disabled ? 'not-allowed' : 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s',\n opacity: skill.disabled ? 0.5 : 1,\n }}\n onMouseOver={(e) => {\n if (!skill.disabled) {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <div\n style={{\n width: '36px',\n height: '36px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'var(--chatllm-primary-light)',\n borderRadius: '10px',\n }}\n >\n <IconSvg\n name={mapSkillIcon(skill.icon)}\n size={20}\n color=\"var(--chatllm-primary)\"\n />\n </div>\n <div>\n <div style={{ fontSize: '14px', fontWeight: 600, color: 'var(--chatllm-text)' }}>\n {skill.label}\n </div>\n <div style={{ fontSize: '12px', color: 'var(--chatllm-text-muted)', maxWidth: '180px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {skill.description}\n </div>\n </div>\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* Send / Stop Button */}\n {isLoading ? (\n <button\n onClick={onStop}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '48px',\n padding: '0 32px',\n backgroundColor: 'var(--chatllm-bg-tertiary)',\n border: '1px solid var(--chatllm-border)',\n borderRadius: '12px',\n cursor: 'pointer',\n transition: 'all 0.2s',\n gap: '8px',\n }}\n >\n <span\n style={{\n fontSize: '14px',\n fontWeight: 700,\n color: 'var(--chatllm-text-secondary)',\n textTransform: 'uppercase',\n letterSpacing: '0.02em',\n }}\n >\n 중지\n </span>\n <IconSvg name=\"stop-circle-line\" size={18} color=\"var(--chatllm-text-secondary)\" />\n </button>\n ) : (\n <button\n onClick={onSubmit}\n disabled={!value.trim() && attachments.length === 0}\n className=\"chatllm-btn-primary\"\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '48px',\n padding: '0 32px',\n borderRadius: '12px',\n cursor: (value.trim() || attachments.length > 0) ? 'pointer' : 'not-allowed',\n opacity: (value.trim() || attachments.length > 0) ? 1 : 0.5,\n gap: '8px',\n }}\n >\n <span\n style={{\n fontSize: '14px',\n fontWeight: 700,\n letterSpacing: '0.02em',\n }}\n >\n 보내기\n </span>\n <IconSvg name=\"arrow-up-s-line\" size={20} color=\"#ffffff\" />\n </button>\n )}\n </div>\n </div>\n\n {/** @Todo vibecode - AI 면책조항 텍스트 (하단 중앙, 클릭 시 모달) */}\n <p\n onClick={onDisclaimerClick}\n role={onDisclaimerClick ? 'button' : undefined}\n tabIndex={onDisclaimerClick ? 0 : undefined}\n style={{\n textAlign: 'center',\n marginTop: '10px',\n marginBottom: 0,\n cursor: onDisclaimerClick ? 'pointer' : 'default',\n fontSize: '12px',\n color: '#94a3b8',\n lineHeight: 1.4,\n }}\n >\n AI인 저도 실수를 할 수 있어요 🥹\n </p>\n </div>\n </footer>\n );\n};\n\nconst iconButtonStyle: React.CSSProperties = {\n padding: '10px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '12px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'background-color 0.2s, color 0.2s',\n};\n\nexport default ChatInput;\n","/**\n * @description 메시지 목록 컴포넌트\n */\n\nimport React, { useRef, useEffect, useCallback, useState } from 'react';\nimport { MessageBubble } from './MessageBubble';\nimport { IconSvg } from './Icon';\nimport type { MessageListProps } from '../types';\n\nexport const MessageList: React.FC<MessageListProps> = ({\n messages,\n isLoading,\n onCopy,\n onEdit,\n onRegenerate,\n onQuote,\n onAskOtherModel,\n onSetActiveAlternative,\n activeAlternatives = {},\n models,\n copiedId,\n editingId,\n onChoiceClick,\n showThinking = true,\n thinkingDefaultOpen = false,\n loadingAlternativeFor,\n onPollSubmit,\n}) => {\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const [selectedText, setSelectedText] = useState('');\n const [selectionPosition, setSelectionPosition] = useState<{ x: number; y: number } | null>(null);\n\n /** @Todo vibecode - 스크롤 위치 기반 자동스크롤 잠금 */\n const [showScrollButton, setShowScrollButton] = useState(false);\n const isUserScrolledUpRef = useRef(false);\n const SCROLL_THRESHOLD = 100;\n\n /** @Todo vibecode - 스크롤 이벤트 핸들러: 하단 근접 여부 판단 */\n const handleScroll = useCallback(() => {\n if (!containerRef.current) return;\n const { scrollTop, scrollHeight, clientHeight } = containerRef.current;\n const distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n const isNearBottom = distanceFromBottom < SCROLL_THRESHOLD;\n\n isUserScrolledUpRef.current = !isNearBottom;\n setShowScrollButton(!isNearBottom);\n }, []);\n\n /** @Todo vibecode - 조건부 auto-scroll: 사용자가 위로 스크롤한 상태면 스킵 */\n useEffect(() => {\n if (isUserScrolledUpRef.current) return;\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages]);\n\n /** @Todo vibecode - 맨 아래로 스크롤 + 자동스크롤 재개 */\n const scrollToBottom = useCallback(() => {\n isUserScrolledUpRef.current = false;\n setShowScrollButton(false);\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, []);\n\n // Handle text selection\n const handleMouseUp = useCallback(() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n const selection = typeof window !== 'undefined' ? window.getSelection() : null;\n const text = selection?.toString().trim();\n\n if (text && text.length > 0) {\n const range = selection?.getRangeAt(0);\n const rect = range?.getBoundingClientRect();\n if (rect && containerRef.current) {\n const containerRect = containerRef.current.getBoundingClientRect();\n const scrollTop = containerRef.current.scrollTop;\n setSelectedText(text);\n setSelectionPosition({\n x: rect.left - containerRect.left + rect.width / 2,\n y: rect.top - containerRect.top + scrollTop - 10,\n });\n }\n } else {\n setTimeout(() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n const currentSelection = typeof window !== 'undefined' ? window.getSelection()?.toString().trim() : undefined;\n if (!currentSelection) {\n setSelectionPosition(null);\n }\n }, 100);\n }\n }, []);\n\n // Handle quote\n const handleQuote = () => {\n if (selectedText && onQuote) {\n onQuote(selectedText);\n setSelectionPosition(null);\n setSelectedText('');\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n if (typeof window !== 'undefined') {\n window.getSelection()?.removeAllRanges();\n }\n }\n };\n\n return (\n <div\n ref={containerRef}\n className=\"chatllm-message-list chatllm-scrollbar\"\n style={{\n flex: 1,\n overflow: 'auto',\n position: 'relative',\n }}\n onScroll={handleScroll}\n onMouseUp={handleMouseUp}\n >\n {/* Messages Container with max-width */}\n <div\n style={{\n maxWidth: '860px',\n margin: '0 auto',\n paddingTop: '32px',\n paddingBottom: '240px', // Space for floating input\n }}\n >\n {messages.map((message, index) => {\n // For user messages, find the next assistant message\n const nextAssistant =\n message.role === 'user' && index + 1 < messages.length\n ? messages[index + 1]\n : null;\n const assistantForAlts =\n nextAssistant?.role === 'assistant' ? nextAssistant : null;\n\n // Get active alternative index for the assistant message\n const activeAltIndex = assistantForAlts\n ? activeAlternatives[assistantForAlts.id] ?? 0\n : 0;\n\n return (\n <MessageBubble\n key={message.id}\n message={message}\n isLoading={isLoading && index === messages.length - 1 && message.role === 'assistant'}\n isCopied={copiedId === message.id}\n isEditing={editingId === message.id}\n onCopy={() => onCopy(message.content, message.id)}\n onEdit={() => onEdit(message)}\n onRegenerate={message.role === 'assistant' ? () => onRegenerate(message.id) : undefined}\n onQuote={onQuote}\n // User messages: pass next assistant message for controls\n nextAssistantMessage={assistantForAlts}\n activeAlternativeIndex={message.role === 'user' ? activeAltIndex : activeAlternatives[message.id] ?? 0}\n onAskOtherModel={\n message.role === 'user' && assistantForAlts && onAskOtherModel\n ? (targetModel) => onAskOtherModel(message.id, assistantForAlts.id, targetModel)\n : message.role === 'assistant' && onAskOtherModel\n ? (targetModel) => {\n // assistant 메시지의 경우 이전 user 메시지를 찾아서 전달\n const prevUserMsg = messages[index - 1];\n if (prevUserMsg?.role === 'user') {\n onAskOtherModel(prevUserMsg.id, message.id, targetModel);\n }\n }\n : undefined\n }\n onAlternativeChange={\n message.role === 'user' && assistantForAlts && onSetActiveAlternative\n ? (idx) => onSetActiveAlternative(assistantForAlts.id, idx)\n : message.role === 'assistant' && onSetActiveAlternative\n ? (idx) => onSetActiveAlternative(message.id, idx)\n : undefined\n }\n models={models}\n alternatives={message.role === 'assistant' ? message.alternatives : assistantForAlts?.alternatives}\n onChoiceClick={message.role === 'assistant' ? onChoiceClick : undefined}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n isLoadingAlternative={loadingAlternativeFor === message.id}\n onPollSubmit={\n message.role === 'assistant' && onPollSubmit\n ? (response) => onPollSubmit(message.id, response)\n : undefined\n }\n />\n );\n })}\n\n <div ref={messagesEndRef} />\n </div>\n\n {/** @Todo vibecode - 맨 아래로 스크롤 FAB 버튼 (position: sticky) */}\n {showScrollButton && (\n <button\n onClick={scrollToBottom}\n aria-label=\"맨 아래로 스크롤\"\n style={{\n position: 'sticky',\n bottom: '260px',\n left: '50%',\n transform: 'translateX(-50%)',\n width: '40px',\n height: '40px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-content-bg)',\n border: '1px solid var(--chatllm-border)',\n boxShadow: '0 2px 8px rgba(0,0,0,0.15)',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 10,\n transition: 'opacity 0.2s',\n }}\n >\n <IconSvg name=\"arrow-down-s-line\" size={24} color=\"var(--chatllm-text-secondary)\" />\n </button>\n )}\n\n {/* Selection Popup */}\n {selectionPosition && (\n <div\n style={{\n position: 'absolute',\n left: selectionPosition.x,\n top: selectionPosition.y,\n transform: 'translate(-50%, -100%)',\n zIndex: 9999,\n pointerEvents: 'auto',\n }}\n >\n <button\n onClick={handleQuote}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n padding: '10px 16px',\n backgroundColor: '#1f2937',\n color: '#ffffff',\n border: 'none',\n borderRadius: '10px',\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n boxShadow: '0 4px 16px rgba(0, 0, 0, 0.2)',\n whiteSpace: 'nowrap',\n }}\n >\n <IconSvg name=\"double-quotes-l\" size={16} color=\"#ffffff\" />\n 인용하기\n </button>\n {/* Arrow */}\n <div\n style={{\n position: 'absolute',\n left: '50%',\n bottom: '-6px',\n transform: 'translateX(-50%)',\n width: 0,\n height: 0,\n borderLeft: '6px solid transparent',\n borderRight: '6px solid transparent',\n borderTop: '6px solid #1f2937',\n }}\n />\n </div>\n )}\n </div>\n );\n};\n\nexport default MessageList;\n","/**\n * @description 메시지 버블 컴포넌트 - Modern Canvas 디자인\n * @Todo vibecode - v0.11.0 새 디자인 시스템 적용\n */\n\nimport React, { useState, useCallback } from 'react';\nimport { IconSvg } from './Icon';\nimport { MarkdownRenderer } from './MarkdownRenderer';\nimport { LinkChip } from './LinkChip';\nimport { DeepResearchProgressUI } from './DeepResearchProgressUI';\nimport { PollCard } from './PollCard';\nimport { SkillProgressUI } from './SkillProgressUI';\nimport { ContentPartRenderer } from './ContentPartRenderer';\nimport type { MessageBubbleProps, PollResponse, DeepResearchProgress } from '../types';\n\nexport const MessageBubble: React.FC<MessageBubbleProps> = ({\n message,\n isLoading,\n isCopied,\n isEditing,\n onCopy,\n onEdit,\n onRegenerate,\n onQuote,\n onAskOtherModel,\n models,\n alternatives,\n activeAlternativeIndex = 0,\n onAlternativeChange,\n nextAssistantMessage,\n onChoiceClick,\n showThinking = true,\n thinkingDefaultOpen = false,\n isLoadingAlternative = false,\n onPollSubmit,\n}) => {\n const [showActions, setShowActions] = useState(false);\n const [showModelMenu, setShowModelMenu] = useState(false);\n const isUser = message.role === 'user';\n const isAssistant = message.role === 'assistant';\n\n const relevantAlternatives = isUser ? alternatives : message.alternatives;\n const relevantActiveIndex = activeAlternativeIndex;\n\n const currentAssistantModel = isUser ? nextAssistantMessage?.model : message.model;\n const otherModels = models?.filter((m) => m.id !== currentAssistantModel) || [];\n\n const displayContent =\n isAssistant && relevantAlternatives && relevantAlternatives.length > 0 && relevantActiveIndex > 0\n ? relevantAlternatives[relevantActiveIndex - 1]?.content || message.content\n : message.content;\n\n const displayModel =\n isAssistant && relevantAlternatives && relevantAlternatives.length > 0 && relevantActiveIndex > 0\n ? relevantAlternatives[relevantActiveIndex - 1]?.model\n : message.model;\n\n const displaySources =\n isAssistant && relevantAlternatives && relevantAlternatives.length > 0 && relevantActiveIndex > 0\n ? relevantAlternatives[relevantActiveIndex - 1]?.sources\n : message.sources;\n\n const handleMouseUp = () => {\n if (!onQuote) return;\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n const selection = typeof window !== 'undefined' ? window.getSelection() : null;\n const text = selection?.toString().trim();\n if (text && text.length > 0) {\n // Will be handled by parent component\n }\n };\n\n // User Message - 오른쪽 정렬, 회색 버블\n if (isUser) {\n return (\n <div\n className=\"chatllm-message chatllm-message--user\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-end',\n padding: '4px 24px',\n }}\n onMouseEnter={() => setShowActions(true)}\n onMouseLeave={() => setShowActions(false)}\n onMouseUp={handleMouseUp}\n >\n {/* 버블 */}\n <div\n style={{\n maxWidth: '70%',\n backgroundColor: 'var(--chatllm-user-bubble)',\n padding: '10px 14px',\n borderRadius: '16px',\n borderTopRightRadius: '4px',\n }}\n >\n {/* @Todo vibecode - user 메시지 contentParts 렌더링 (이미지/파일 첨부) */}\n {message.contentParts?.length ? (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {message.contentParts.map((part, idx) => {\n if (part.type === 'text') {\n return (\n <div\n key={idx}\n style={{\n fontSize: '14px',\n lineHeight: '1.5',\n color: 'var(--chatllm-text)',\n whiteSpace: 'pre-wrap',\n }}\n >\n {part.content}\n </div>\n );\n }\n if (part.type === 'image') {\n return (\n <img\n key={idx}\n src={part.url}\n alt={part.alt || '첨부 이미지'}\n style={{\n maxWidth: '100%',\n maxHeight: '300px',\n borderRadius: '8px',\n objectFit: 'contain',\n }}\n />\n );\n }\n if (part.type === 'file') {\n return (\n <div\n key={idx}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 12px',\n backgroundColor: 'rgba(0,0,0,0.05)',\n borderRadius: '8px',\n fontSize: '13px',\n color: 'var(--chatllm-text)',\n }}\n >\n <IconSvg name=\"file-text-line\" size={16} color=\"var(--chatllm-text-muted)\" />\n <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {part.name}\n </span>\n </div>\n );\n }\n return null;\n })}\n </div>\n ) : (\n <div\n style={{\n fontSize: '14px',\n lineHeight: '1.5',\n color: 'var(--chatllm-text)',\n whiteSpace: 'pre-wrap',\n }}\n >\n {displayContent}\n </div>\n )}\n </div>\n\n {/* Action Buttons - 버블 아래에 표시 */}\n {!isLoading && (\n <div\n style={{\n display: 'flex',\n gap: '2px',\n marginTop: '4px',\n height: '24px',\n opacity: showActions ? 1 : 0,\n transition: 'opacity 0.15s ease',\n }}\n >\n <button onClick={onCopy} style={actionButtonSmallStyle} title=\"복사\">\n <IconSvg\n name={isCopied ? 'check-line' : 'file-copy-line'}\n size={12}\n color={isCopied ? 'var(--chatllm-success)' : 'var(--chatllm-text-muted)'}\n />\n </button>\n <button onClick={onEdit} style={actionButtonSmallStyle} title=\"수정\">\n <IconSvg name=\"edit-line\" size={12} color=\"var(--chatllm-text-muted)\" />\n </button>\n </div>\n )}\n </div>\n );\n }\n\n // Assistant Message - 왼쪽 정렬, 흰색 카드\n return (\n <div\n className=\"chatllm-message chatllm-message--assistant\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-start',\n padding: '4px 24px',\n }}\n onMouseEnter={() => setShowActions(true)}\n onMouseLeave={() => setShowActions(false)}\n onMouseUp={handleMouseUp}\n >\n <div\n className=\"chatllm-sheet\"\n style={{\n width: '100%',\n padding: '16px',\n display: 'flex',\n gap: '12px',\n }}\n >\n {/* AI Icon */}\n <div style={{ flexShrink: 0 }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '10px',\n backgroundColor: 'var(--chatllm-primary-light)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'var(--chatllm-primary)',\n }}\n >\n <IconSvg name=\"magic-line\" size={20} />\n </div>\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, minWidth: 0 }}>\n {/* Model Badge */}\n {displayModel && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginBottom: '8px',\n }}\n >\n <span\n style={{\n fontSize: '12px',\n fontWeight: 600,\n color: 'var(--chatllm-text-muted)',\n textTransform: 'uppercase',\n letterSpacing: '0.02em',\n }}\n >\n {displayModel}\n </span>\n </div>\n )}\n\n {/* Deep Research Progress */}\n {message.isDeepResearch && message.researchProgress && message.researchProgress.phase !== 'done' && (\n <DeepResearchProgressUI progress={message.researchProgress} />\n )}\n\n {/* Skill Execution Progress - 딥리서치면 상세 카드, 아니면 간단 UI */}\n {message.skillExecution && message.skillExecution.status !== 'done' && (\n message.skillExecution.progress?.subAgents\n ? <DeepResearchProgressUI progress={message.skillExecution.progress as DeepResearchProgress} />\n : <SkillProgressUI execution={message.skillExecution} />\n )}\n\n {/* Deep Research Result Header */}\n {message.isDeepResearch && displayContent && (\n <div\n className=\"chatllm-deep-research__header\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginBottom: '16px',\n paddingBottom: '12px',\n borderBottom: '1px solid var(--chatllm-border-light)',\n }}\n >\n <IconSvg name=\"search-eye-line\" size={18} color=\"var(--chatllm-primary)\" />\n <span\n style={{\n fontSize: '14px',\n fontWeight: 600,\n color: 'var(--chatllm-text)',\n }}\n >\n 심층연구\n </span>\n {displaySources && displaySources.length > 0 && (\n <span\n className=\"chatllm-deep-research__source-count\"\n style={{\n marginLeft: 'auto',\n fontSize: '12px',\n fontWeight: 500,\n color: 'var(--chatllm-text-muted)',\n padding: '4px 10px',\n backgroundColor: 'var(--chatllm-bg-secondary)',\n borderRadius: '12px',\n }}\n >\n {displaySources.length}개 출처\n </span>\n )}\n </div>\n )}\n\n {/** @Todo vibecode - contentParts 우선 렌더링 (tool result 카드가 로딩 위에 표시) */}\n {message.contentParts?.length && (\n <div style={{ wordBreak: 'break-word' }}>\n <ContentPartRenderer\n parts={message.contentParts}\n onChoiceClick={onChoiceClick}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n />\n </div>\n )}\n\n {/** @Todo vibecode - Loading State: contentParts 유무에 따라 스켈레톤/간소화 분기 */}\n {isLoading && !displayContent && !message.isDeepResearch && (\n message.contentParts?.length ? (\n /* contentParts 있을 때: 간소화된 AI 응답 대기 표시 */\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '4px' }}>\n <div style={{ display: 'flex', gap: '4px', alignItems: 'center' }}>\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n </div>\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n fontStyle: 'italic',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n 답변 생성 중...\n </span>\n </div>\n ) : (\n /* contentParts 없을 때: 풀 스켈레톤 */\n <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>\n <div style={{ display: 'flex', gap: '4px', alignItems: 'center' }}>\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n </div>\n <span\n style={{\n fontSize: '14px',\n fontWeight: 600,\n fontStyle: 'italic',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n 생각 중...\n </span>\n </div>\n <div className=\"chatllm-skeleton-pulse\" style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>\n <div style={{ height: '32px', width: '75%', backgroundColor: 'var(--chatllm-bg-tertiary)', borderRadius: '8px' }} />\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n <div style={{ height: '16px', width: '100%', backgroundColor: 'var(--chatllm-bg-secondary)', borderRadius: '4px' }} />\n <div style={{ height: '16px', width: '85%', backgroundColor: 'var(--chatllm-bg-secondary)', borderRadius: '4px' }} />\n <div style={{ height: '16px', width: '65%', backgroundColor: 'var(--chatllm-bg-secondary)', borderRadius: '4px' }} />\n </div>\n </div>\n </div>\n )\n )}\n\n {displayContent ? (\n <div style={{ wordBreak: 'break-word' }}>\n <MarkdownRenderer\n content={displayContent}\n onChoiceClick={onChoiceClick}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n />\n </div>\n ) : null}\n\n {/* Poll Card (AI-driven choices) - 탭 UI */}\n {message.pollBlock && message.pollBlock.questions.length > 0 && (\n <PollCard\n questions={message.pollBlock.questions}\n onSubmit={(responses: PollResponse[]) => {\n onPollSubmit?.(responses);\n }}\n onSkip={() => {\n onPollSubmit?.([]);\n }}\n />\n )}\n\n {/* Empty Response Error State */}\n {!isLoading && !displayContent && !message.pollBlock && !message.contentParts?.length && (\n <div\n style={{\n padding: '16px',\n backgroundColor: 'var(--chatllm-bg-secondary)',\n borderRadius: '8px',\n color: 'var(--chatllm-text-muted)',\n fontSize: '14px',\n }}\n >\n 응답을 생성하지 못했습니다. 다시 시도해 주세요.\n </div>\n )}\n\n {/* Sources */}\n {displaySources && displaySources.length > 0 && (\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '8px',\n marginTop: '16px',\n paddingTop: '16px',\n borderTop: '1px solid var(--chatllm-border-light)',\n }}\n >\n <span\n style={{\n fontSize: '12px',\n fontWeight: 500,\n color: 'var(--chatllm-text-muted)',\n marginRight: '4px',\n }}\n >\n 출처:\n </span>\n {displaySources.map((source, index) => (\n <LinkChip\n key={source.id}\n text={source.title}\n url={source.url}\n index={index + 1}\n showFavicon\n />\n ))}\n </div>\n )}\n\n {/* Alternatives Navigation - 다른 모델 답변 탐색 */}\n {relevantAlternatives && relevantAlternatives.length > 0 && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginTop: '12px',\n padding: '8px 12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '8px',\n fontSize: '12px',\n }}\n >\n <span style={{ color: 'var(--chatllm-text-muted)', marginRight: '4px' }}>\n {displayModel || '모델'}\n </span>\n <button\n onClick={() => onAlternativeChange?.(Math.max(0, relevantActiveIndex - 1))}\n disabled={relevantActiveIndex === 0}\n style={{\n ...navButtonStyle,\n opacity: relevantActiveIndex === 0 ? 0.5 : 1,\n cursor: relevantActiveIndex === 0 ? 'not-allowed' : 'pointer',\n }}\n >\n <IconSvg name=\"arrow-left-line\" size={12} />\n </button>\n <span style={{ color: 'var(--chatllm-text-secondary)' }}>\n {relevantActiveIndex + 1} / {relevantAlternatives.length + 1}\n </span>\n <button\n onClick={() =>\n onAlternativeChange?.(Math.min(relevantAlternatives.length, relevantActiveIndex + 1))\n }\n disabled={relevantActiveIndex === relevantAlternatives.length}\n style={{\n ...navButtonStyle,\n opacity: relevantActiveIndex === relevantAlternatives.length ? 0.5 : 1,\n cursor: relevantActiveIndex === relevantAlternatives.length ? 'not-allowed' : 'pointer',\n }}\n >\n <IconSvg name=\"arrow-right-line\" size={12} />\n </button>\n </div>\n )}\n\n {/* Loading Alternative Indicator - 다른 모델 응답 생성 중 */}\n {isLoadingAlternative && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginTop: '12px',\n padding: '10px 14px',\n backgroundColor: 'var(--chatllm-primary-light, #eff6ff)',\n borderRadius: '8px',\n fontSize: '13px',\n color: 'var(--chatllm-primary, #2563eb)',\n }}\n >\n <div style={{ display: 'flex', gap: '4px', alignItems: 'center' }}>\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n </div>\n <span style={{ fontWeight: 500 }}>다른 모델 응답 생성 중...</span>\n </div>\n )}\n </div>\n </div>\n\n {/* Action Buttons - 카드 아래에 표시 */}\n {!isLoading && (\n <div\n style={{\n display: 'flex',\n gap: '2px',\n marginTop: '4px',\n marginLeft: '44px',\n height: '24px',\n opacity: showActions ? 1 : 0,\n transition: 'opacity 0.15s ease',\n }}\n >\n <button onClick={onCopy} style={actionButtonSmallStyle} title=\"복사\">\n <IconSvg\n name={isCopied ? 'check-line' : 'file-copy-line'}\n size={12}\n color={isCopied ? 'var(--chatllm-success)' : 'var(--chatllm-text-muted)'}\n />\n </button>\n {onRegenerate && (\n <button onClick={onRegenerate} style={actionButtonSmallStyle} title=\"다시 생성\">\n <IconSvg name=\"refresh-line\" size={12} color=\"var(--chatllm-text-muted)\" />\n </button>\n )}\n {onAskOtherModel && otherModels.length > 0 && (\n <div style={{ position: 'relative' }}>\n <button\n onClick={() => setShowModelMenu(!showModelMenu)}\n style={actionButtonSmallStyle}\n title=\"다른 모델에게 질문\"\n >\n <IconSvg name=\"robot-line\" size={12} color=\"var(--chatllm-text-muted)\" />\n </button>\n {showModelMenu && (\n <ModelMenu\n models={otherModels}\n onSelect={(modelId) => {\n onAskOtherModel(modelId);\n setShowModelMenu(false);\n }}\n onClose={() => setShowModelMenu(false)}\n />\n )}\n </div>\n )}\n </div>\n )}\n </div>\n );\n};\n\n/**\n * @description 모델 선택 드롭다운 메뉴\n */\nconst ModelMenu: React.FC<{\n models: Array<{ id: string; name: string; provider?: string }>;\n onSelect: (modelId: string) => void;\n onClose: () => void;\n}> = ({ models, onSelect, onClose }) => (\n <div\n style={{\n position: 'absolute',\n bottom: '100%',\n right: 0,\n marginBottom: '4px',\n backgroundColor: 'var(--chatllm-content-bg)',\n border: '1px solid var(--chatllm-border)',\n borderRadius: '12px',\n boxShadow: 'var(--chatllm-shadow-sheet)',\n minWidth: '180px',\n zIndex: 100,\n overflow: 'hidden',\n }}\n onMouseLeave={onClose}\n >\n <div\n style={{\n padding: '10px 14px',\n fontSize: '11px',\n fontWeight: 700,\n color: 'var(--chatllm-text-muted)',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n borderBottom: '1px solid var(--chatllm-border-light)',\n }}\n >\n 다른 모델에게 질문\n </div>\n {models.map((model) => (\n <button\n key={model.id}\n onClick={() => onSelect(model.id)}\n style={{\n width: '100%',\n padding: '12px 14px',\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: 'pointer',\n fontSize: '13px',\n color: 'var(--chatllm-text)',\n textAlign: 'left',\n transition: 'background-color 0.15s',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <IconSvg name=\"robot-line\" size={16} color=\"var(--chatllm-primary)\" />\n <span style={{ flex: 1, fontWeight: 500 }}>{model.name}</span>\n {model.provider && (\n <span\n style={{\n fontSize: '10px',\n padding: '2px 8px',\n backgroundColor: 'var(--chatllm-bg-tertiary)',\n borderRadius: '4px',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n {model.provider}\n </span>\n )}\n </button>\n ))}\n </div>\n);\n\nconst dotStyle: React.CSSProperties = {\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-primary)',\n};\n\nconst actionButtonStyle: React.CSSProperties = {\n padding: '8px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'background-color 0.2s',\n};\n\nconst actionButtonSmallStyle: React.CSSProperties = {\n padding: '4px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'background-color 0.2s',\n};\n\nconst navButtonStyle: React.CSSProperties = {\n width: '24px',\n height: '24px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'var(--chatllm-content-bg)',\n border: '1px solid var(--chatllm-border)',\n borderRadius: '6px',\n};\n\nexport default MessageBubble;\n","/**\n * @description 마크다운 렌더러 컴포넌트\n * 외부 의존성 없이 기본 마크다운 파싱 지원\n */\n\nimport React, { useMemo } from 'react';\nimport { LinkChip } from './LinkChip';\nimport type { SourceItem } from '../types';\n\nexport interface ChoiceOption {\n number: number;\n text: string;\n fullText: string;\n}\n\n/** @description 선택지 블록 (제목 + 선택지 목록) */\nexport interface ChoiceBlock {\n title?: string;\n choices: ChoiceOption[];\n}\n\nexport interface MarkdownRendererProps {\n /** 마크다운 텍스트 */\n content: string;\n /** 커스텀 클래스 */\n className?: string;\n /** 선택지 클릭 핸들러 */\n onChoiceClick?: (choice: ChoiceOption) => void;\n /**\n * @description Thinking 블록 표시 여부\n * @Todo vibecode - AI 추론 과정 표시 (기본: true)\n */\n showThinking?: boolean;\n /**\n * @description Thinking 블록 기본 펼침 상태\n * @Todo vibecode - true면 펼쳐진 상태로 표시 (기본: false)\n */\n thinkingDefaultOpen?: boolean;\n /**\n * @description 인라인 소스 참조용 출처 목록\n * @Todo vibecode - [1], [2] 패턴을 소스 URL 링크로 변환\n */\n sources?: SourceItem[];\n}\n\n// 이미지 정규식 - ![alt](url) 패턴\nconst IMAGE_REGEX = /!\\[([^\\]]*)\\]\\(([^)]+)\\)/g;\n// 링크 정규식 - [text](url) 패턴 (이미지가 아닌 것만)\nconst LINK_REGEX = /(?<!!)\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\n// 출처 링크 패턴 - 연속된 링크들 (예: [`1. brave`](url) [`2. brave`](url))\n// 주의: 이미지 링크(![)가 아닌 것만 매칭\nconst SOURCE_LINKS_REGEX = /(\\*{0,2}출처:?\\*{0,2}\\s*)?((?:(?<!!)\\[`?[^\\]]+`?\\]\\([^)]+\\)\\s*)+)/gi;\n\n// 선택지 패턴 - 번호로 시작하는 선택지 (예: 1. 옵션A, 2. 옵션B)\nconst CHOICE_PATTERN = /^(\\d+)[.)]\\s*(.+)$/;\n// 인라인 선택지 패턴 - [1] 텍스트 형식 (예: [1] 뉴스 문장 [2] 일상대화)\nconst INLINE_CHOICE_PATTERN = /\\[(\\d+)\\]\\s*([^\\[\\n]+?)(?=\\s*\\[\\d+\\]|$)/g;\n// 인라인 선택지 블록 감지 패턴 (2개 이상의 [숫자] 패턴이 있는 줄)\nconst INLINE_CHOICE_LINE_PATTERN = /^(.+?)?\\s*(\\[\\d+\\][^\\[]+(?:\\[\\d+\\][^\\[]+)+)$/;\n// 코드 블록 패턴\nconst CODE_BLOCK_REGEX = /```(\\w*)\\n?([\\s\\S]*?)```/g;\n// Thinking 블록 패턴\n/** @Todo vibecode - <thinking> 태그 패턴 (닫는 태그 필수) */\nconst THINKING_TAG_REGEX = /<thinking>([\\s\\S]*?)<\\/thinking>/gi;\n/** @Todo vibecode - ```thinking 코드블록 패턴 */\nconst THINKING_CODEBLOCK_REGEX = /```thinking\\n?([\\s\\S]*?)```/gi;\n/** @Todo vibecode - \"Thinking:\" 텍스트 패턴 (빈 줄까지) */\nconst THINKING_TEXT_REGEX = /^Thinking:\\s*\\n([\\s\\S]*?)(?=\\n\\n|$)/gim;\n/** @Todo vibecode - 닫히지 않은 <thinking> 태그만 제거 (내용은 유지) */\nconst UNCLOSED_THINKING_TAG_REGEX = /<thinking>(?![\\s\\S]*?<\\/thinking>)/gi;\n/** @Todo vibecode - 닫히지 않은 <poll> 태그 전체 제거 (스트리밍 중) */\nconst UNCLOSED_POLL_TAG_REGEX = /<poll[^>]*>(?![\\s\\S]*?<\\/poll>)[\\s\\S]*$/gi;\n/** @Todo vibecode - 닫히지 않은 <skill_use> 태그 전체 제거 (스트리밍 중) */\nconst UNCLOSED_SKILL_TAG_REGEX = /<skill_use[^>]*>(?![\\s\\S]*?<\\/skill_use>)[\\s\\S]*$/gi;\n// 인라인 코드 패턴\nconst INLINE_CODE_REGEX = /`([^`]+)`/g;\n// 굵게 패턴\nconst BOLD_REGEX = /\\*\\*([^*]+)\\*\\*/g;\n// 기울임 패턴 (굵게가 아닌 경우만)\nconst ITALIC_REGEX = /(?<!\\*)\\*([^*]+)\\*(?!\\*)/g;\n// 헤딩 패턴\nconst HEADING_REGEX = /^(#{1,6})\\s+(.+)$/gm;\n// 리스트 아이템 패턴\nconst LIST_ITEM_REGEX = /^[\\-\\*]\\s+(.+)$/gm;\n// 번호 리스트 패턴\nconst NUMBERED_LIST_REGEX = /^(\\d+)\\.\\s+(.+)$/gm;\n// 인용 패턴\nconst BLOCKQUOTE_REGEX = /^>\\s+(.+)$/gm;\n// 수평선 패턴\nconst HR_REGEX = /^---+$/gm;\n// 테이블 행 패턴\nconst TABLE_ROW_REGEX = /^\\|(.+)\\|$/;\n// 테이블 구분선 패턴\nconst TABLE_SEPARATOR_REGEX = /^\\|[\\s\\-:|]+\\|$/;\n\n/**\n * @description 비표준 테이블(탭/공백 구분)을 마크다운 파이프 테이블로 변환\n * @Todo vibecode - AI가 ```markdown 내 탭/공백 구분 형식으로 표를 작성할 때 처리\n */\nconst convertNonStandardTable = (codeContent: string): string | null => {\n const lines = codeContent.trim().split('\\n');\n const nonEmptyLines = lines.filter((l) => l.trim());\n if (nonEmptyLines.length < 2) return null;\n\n /** @Todo vibecode - separator 행 감지 (--- 또는 === 패턴) */\n const isSeparatorLine = (line: string) =>\n /^[-=\\s\\t|:]+$/.test(line.trim()) && /[-=]{2,}/.test(line);\n\n // Case 1: 탭 구분 테이블\n if (nonEmptyLines[0].includes('\\t')) {\n const dataLines = nonEmptyLines.filter((l) => !isSeparatorLine(l));\n if (dataLines.length < 2) return null;\n if (!dataLines.every((l) => l.includes('\\t'))) return null;\n\n const colCount = dataLines[0].split('\\t').length;\n if (colCount < 2) return null;\n\n const result: string[] = [];\n const headerCells = dataLines[0].split('\\t').map((c) => c.trim());\n result.push('| ' + headerCells.join(' | ') + ' |');\n result.push('| ' + Array(colCount).fill('---').join(' | ') + ' |');\n for (let i = 1; i < dataLines.length; i++) {\n const cells = dataLines[i].split('\\t').map((c) => c.trim());\n while (cells.length < colCount) cells.push('');\n result.push('| ' + cells.join(' | ') + ' |');\n }\n return result.join('\\n');\n }\n\n // Case 2: 2개 이상 공백으로 구분된 테이블\n const dataLines = nonEmptyLines.filter((l) => !isSeparatorLine(l));\n if (dataLines.length < 2) return null;\n\n const spaceParsed = dataLines.map((l) =>\n l\n .split(/\\s{2,}/)\n .map((c) => c.trim())\n .filter(Boolean)\n );\n\n const colCount = spaceParsed[0].length;\n if (colCount < 3) return null; // 3컬럼 이상만 (2컬럼은 오탐 위험)\n\n const consistent = spaceParsed.every(\n (cols) => cols.length >= colCount - 1 && cols.length <= colCount + 1\n );\n if (!consistent) return null;\n\n const result: string[] = [];\n result.push('| ' + spaceParsed[0].join(' | ') + ' |');\n result.push('| ' + Array(colCount).fill('---').join(' | ') + ' |');\n for (let i = 1; i < spaceParsed.length; i++) {\n const cells = [...spaceParsed[i]];\n while (cells.length < colCount) cells.push('');\n result.push('| ' + cells.join(' | ') + ' |');\n }\n return result.join('\\n');\n};\n\ninterface ParsedLink {\n text: string;\n url: string;\n}\n\n/**\n * 출처 링크들을 파싱하여 배열로 반환\n */\nconst parseSourceLinks = (text: string): ParsedLink[] => {\n const links: ParsedLink[] = [];\n let match;\n const linkRegex = /\\[`?([^\\]`]+)`?\\]\\(([^)]+)\\)/g;\n\n while ((match = linkRegex.exec(text)) !== null) {\n links.push({\n text: match[1],\n url: match[2],\n });\n }\n\n return links;\n};\n\n/**\n * @description 인라인 선택지 파싱 ([1] 텍스트 [2] 텍스트 형식)\n * @param text 파싱할 텍스트\n * @returns 선택지 블록 또는 null\n */\nconst parseInlineChoices = (text: string): ChoiceBlock | null => {\n const lineMatch = text.match(INLINE_CHOICE_LINE_PATTERN);\n if (!lineMatch) return null;\n\n const title = lineMatch[1]?.trim();\n const choicesText = lineMatch[2];\n\n const choices: ChoiceOption[] = [];\n let match;\n const regex = new RegExp(INLINE_CHOICE_PATTERN.source, 'g');\n\n while ((match = regex.exec(choicesText)) !== null) {\n const number = parseInt(match[1]);\n const choiceText = match[2].trim();\n if (choiceText) {\n choices.push({\n number,\n text: choiceText,\n fullText: `[${number}] ${choiceText}`,\n });\n }\n }\n\n if (choices.length >= 2) {\n return { title, choices };\n }\n\n return null;\n};\n\n/**\n * @description 텍스트에서 인라인 요소 파싱 (굵게, 기울임, 코드, 링크, 소스 참조)\n * @Todo vibecode - sources 전달 시 [N] 패턴을 소스 URL 상위첨자 링크로 변환\n */\nconst parseInlineElements = (text: string, key: string, sources?: SourceItem[]): React.ReactNode[] => {\n const elements: React.ReactNode[] = [];\n let currentText = text;\n\n /**\n * @Todo vibecode - 인라인 소스 참조 [N] → 상위첨자 링크 변환\n * [N](url) 마크다운 링크와 충돌하지 않도록 (?!\\() 사용\n */\n if (sources && sources.length > 0) {\n currentText = currentText.replace(\n /(?<![!\\[])\\[(\\d+)\\](?!\\()/g,\n (match, numStr) => {\n const num = parseInt(numStr);\n if (num >= 1 && num <= sources.length) {\n return `§SRCREF§${num}§/SRCREF§`;\n }\n return match;\n }\n );\n }\n\n // 인라인 코드 처리\n currentText = currentText.replace(INLINE_CODE_REGEX, '§CODE§$1§/CODE§');\n // 굵게 처리\n currentText = currentText.replace(BOLD_REGEX, '§BOLD§$1§/BOLD§');\n // 기울임 처리\n currentText = currentText.replace(ITALIC_REGEX, '§ITALIC§$1§/ITALIC§');\n // 이미지 처리 (링크보다 먼저 처리해야 함)\n currentText = currentText.replace(IMAGE_REGEX, '§IMAGE§$1§URL§$2§/IMAGE§');\n // 일반 링크 처리 (출처 링크가 아닌 것)\n currentText = currentText.replace(LINK_REGEX, '§LINK§$1§URL§$2§/LINK§');\n\n // 파싱된 마커를 React 요소로 변환\n const parts = currentText.split(/(§CODE§.*?§\\/CODE§|§BOLD§.*?§\\/BOLD§|§ITALIC§.*?§\\/ITALIC§|§IMAGE§.*?§\\/IMAGE§|§LINK§.*?§\\/LINK§|§SRCREF§\\d+§\\/SRCREF§)/);\n\n parts.forEach((part, index) => {\n if (part.startsWith('§CODE§')) {\n const content = part.replace('§CODE§', '').replace('§/CODE§', '');\n elements.push(\n <code\n key={`${key}-code-${index}`}\n style={{\n backgroundColor: 'var(--chatllm-code-bg, #f3f4f6)',\n padding: '2px 6px',\n borderRadius: '4px',\n fontSize: '0.9em',\n fontFamily: 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace',\n color: 'var(--chatllm-code-text, #e11d48)',\n }}\n >\n {content}\n </code>\n );\n } else if (part.startsWith('§BOLD§')) {\n const content = part.replace('§BOLD§', '').replace('§/BOLD§', '');\n elements.push(<strong key={`${key}-bold-${index}`}>{content}</strong>);\n } else if (part.startsWith('§ITALIC§')) {\n const content = part.replace('§ITALIC§', '').replace('§/ITALIC§', '');\n elements.push(<em key={`${key}-italic-${index}`}>{content}</em>);\n } else if (part.startsWith('§IMAGE§')) {\n const match = part.match(/§IMAGE§(.*)§URL§(.+?)§\\/IMAGE§/);\n if (match) {\n elements.push(\n <ImageWithCopyButton\n key={`${key}-image-${index}`}\n src={match[2]}\n alt={match[1] || ''}\n imageKey={`${key}-image-${index}`}\n />\n );\n }\n } else if (part.startsWith('§LINK§')) {\n const match = part.match(/§LINK§(.+?)§URL§(.+?)§\\/LINK§/);\n if (match) {\n elements.push(\n <a\n key={`${key}-link-${index}`}\n href={match[2]}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{\n color: 'var(--chatllm-link, #3b82f6)',\n textDecoration: 'none',\n }}\n >\n {match[1]}\n </a>\n );\n }\n } else if (part.startsWith('§SRCREF§') && sources) {\n /** @Todo vibecode - 소스 참조 상위첨자 렌더링 */\n const num = parseInt(part.replace('§SRCREF§', '').replace('§/SRCREF§', ''));\n const source = sources[num - 1];\n if (source) {\n elements.push(\n <a\n key={`${key}-srcref-${index}`}\n href={source.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n title={source.title}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '18px',\n height: '18px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-primary-light, #dbeafe)',\n color: 'var(--chatllm-primary, #3b82f6)',\n fontSize: '11px',\n fontWeight: 600,\n textDecoration: 'none',\n verticalAlign: 'super',\n marginLeft: '1px',\n marginRight: '1px',\n lineHeight: 1,\n }}\n >\n {num}\n </a>\n );\n }\n } else if (part) {\n elements.push(part);\n }\n });\n\n return elements;\n};\n\n/**\n * 테이블 셀 정렬 파싱\n */\ntype CellAlignment = 'left' | 'center' | 'right';\n\nconst parseTableAlignment = (separatorRow: string): CellAlignment[] => {\n const cells = separatorRow.split('|').filter((cell) => cell.trim() !== '');\n return cells.map((cell) => {\n const trimmed = cell.trim();\n const hasLeftColon = trimmed.startsWith(':');\n const hasRightColon = trimmed.endsWith(':');\n if (hasLeftColon && hasRightColon) return 'center';\n if (hasRightColon) return 'right';\n return 'left';\n });\n};\n\n/**\n * 테이블 행 파싱\n */\nconst parseTableRow = (row: string): string[] => {\n return row\n .split('|')\n .slice(1, -1) // Remove first and last empty strings from split\n .map((cell) => cell.trim());\n};\n\ninterface TableData {\n headers: string[];\n alignments: CellAlignment[];\n rows: string[][];\n}\n\n/**\n * @description 테이블 렌더링 컴포넌트\n * @Todo vibecode - 호버 시 복사 버튼 표시, 탭 구분 텍스트로 복사 (스프레드시트 호환)\n */\nconst MarkdownTable: React.FC<{ data: TableData }> = ({ data }) => {\n const [copied, setCopied] = React.useState(false);\n const [isHovered, setIsHovered] = React.useState(false);\n\n /** @Todo vibecode - 테이블 데이터를 탭 구분 텍스트로 변환 (스프레드시트 붙여넣기 호환) */\n const handleCopy = async () => {\n const headerLine = data.headers.join('\\t');\n const bodyLines = data.rows.map((row) => row.join('\\t'));\n const text = [headerLine, ...bodyLines].join('\\n');\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n console.error('Failed to copy table');\n }\n };\n\n return (\n <div\n style={{ position: 'relative', margin: '12px 0' }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n <table\n className=\"chatllm-table\"\n style={{\n width: '100%',\n borderCollapse: 'collapse',\n fontSize: '14px',\n }}\n >\n <thead>\n <tr>\n {data.headers.map((header, i) => (\n <th\n key={i}\n style={{\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n padding: '10px 12px',\n textAlign: data.alignments[i] || 'left',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n fontWeight: 600,\n color: 'var(--chatllm-text, #374151)',\n }}\n >\n {parseInlineElements(header, `th-${i}`)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.rows.map((row, rowIndex) => (\n <tr key={rowIndex}>\n {row.map((cell, cellIndex) => (\n <td\n key={cellIndex}\n style={{\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n padding: '10px 12px',\n textAlign: data.alignments[cellIndex] || 'left',\n color: 'var(--chatllm-text, #374151)',\n }}\n >\n {parseInlineElements(cell, `td-${rowIndex}-${cellIndex}`)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n {/* 복사 버튼 */}\n <button\n onClick={handleCopy}\n style={{\n position: 'absolute',\n top: '4px',\n right: '4px',\n padding: '4px 8px',\n fontSize: '12px',\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '6px',\n cursor: 'pointer',\n color: copied ? 'var(--chatllm-success, #22c55e)' : 'var(--chatllm-text-muted, #9ca3af)',\n opacity: isHovered || copied ? 1 : 0,\n transition: 'opacity 0.15s',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n boxShadow: '0 1px 3px rgba(0,0,0,0.08)',\n }}\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n {copied ? (\n <polyline points=\"20 6 9 17 4 12\" />\n ) : (\n <>\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </>\n )}\n </svg>\n {copied ? '복사됨' : '복사'}\n </button>\n </div>\n );\n};\n\n/**\n * @description 스피너 컴포넌트\n * @Todo vibecode - Thinking 블록 스트리밍 중 표시\n */\nconst ThinkingSpinner: React.FC = () => (\n <span\n className=\"chatllm-thinking-spinner\"\n style={{\n display: 'inline-block',\n width: '12px',\n height: '12px',\n border: '2px solid var(--chatllm-border, #e5e7eb)',\n borderTopColor: 'var(--chatllm-primary, #3b82f6)',\n borderRadius: '50%',\n animation: 'chatllm-spin 0.8s linear infinite',\n }}\n />\n);\n\n/**\n * @description Thinking 블록 렌더링\n * @Todo vibecode - AI 추론 과정을 접기/펼치기 UI로 표시\n * @Todo vibecode - isStreaming: 스트리밍 중일 때 스피너 표시\n */\nconst ThinkingBlock: React.FC<{\n content: string;\n defaultOpen?: boolean;\n}> = ({ content, defaultOpen = false }) => {\n const [isOpen, setIsOpen] = React.useState(defaultOpen);\n\n /**\n * @description 스트리밍 중 여부 판단\n * @Todo vibecode - 내용이 '...'로 끝나면 스트리밍 중\n */\n const isStreaming = content.trim().endsWith('...');\n\n return (\n <details\n open={isOpen}\n className=\"chatllm-thinking\"\n style={{\n margin: '8px 0',\n borderRadius: '6px',\n border: '1px dashed var(--chatllm-border, #e5e7eb)',\n background: 'transparent',\n overflow: 'hidden',\n }}\n >\n <summary\n onClick={(e) => {\n e.preventDefault();\n setIsOpen(!isOpen);\n }}\n style={{\n padding: '6px 10px',\n cursor: 'pointer',\n fontSize: '11px',\n color: 'var(--chatllm-text-tertiary, #9ca3af)',\n userSelect: 'none',\n listStyle: 'none',\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n }}\n >\n {isStreaming ? (\n <ThinkingSpinner />\n ) : (\n <span style={{ fontSize: '11px', opacity: 0.7 }}>💭</span>\n )}\n <span>{isStreaming ? '추론 중...' : isOpen ? '추론 과정' : '추론 과정 보기'}</span>\n <span\n style={{\n marginLeft: 'auto',\n fontSize: '8px',\n opacity: 0.6,\n transition: 'transform 0.2s',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n }}\n >\n ▼\n </span>\n </summary>\n {isOpen && (\n <div\n className=\"chatllm-thinking-content\"\n style={{\n padding: '8px 10px',\n borderTop: '1px dashed var(--chatllm-border, #e5e7eb)',\n fontSize: '12px',\n color: 'var(--chatllm-text-secondary, #6b7280)',\n whiteSpace: 'pre-wrap',\n lineHeight: '1.6',\n background: 'var(--chatllm-bg-secondary, #f9fafb)',\n maxHeight: '400px',\n overflowY: 'auto',\n }}\n >\n {isStreaming ? content.trim().slice(0, -3) : content.trim()}\n </div>\n )}\n </details>\n );\n};\n\n/**\n * 코드 블록 렌더링\n */\nconst CodeBlock: React.FC<{ language?: string; code: string }> = ({ language, code }) => {\n const [copied, setCopied] = React.useState(false);\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch (e) {\n console.error('Failed to copy');\n }\n };\n\n return (\n <div\n style={{\n position: 'relative',\n margin: '12px 0',\n borderRadius: '8px',\n overflow: 'hidden',\n backgroundColor: 'var(--chatllm-code-block-bg, #1f2937)',\n }}\n >\n {/* Header */}\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: '8px 12px',\n backgroundColor: 'var(--chatllm-code-block-header, #374151)',\n borderBottom: '1px solid var(--chatllm-code-block-border, #4b5563)',\n }}\n >\n <span\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-code-block-lang, #9ca3af)',\n textTransform: 'lowercase',\n }}\n >\n {language || 'code'}\n </span>\n <button\n onClick={handleCopy}\n style={{\n padding: '4px 8px',\n fontSize: '12px',\n backgroundColor: 'transparent',\n border: '1px solid var(--chatllm-code-block-border, #4b5563)',\n borderRadius: '4px',\n color: 'var(--chatllm-code-block-text, #e5e7eb)',\n cursor: 'pointer',\n }}\n >\n {copied ? '복사됨!' : '복사'}\n </button>\n </div>\n {/* Code */}\n <pre\n style={{\n margin: 0,\n padding: '16px',\n overflow: 'auto',\n fontSize: '13px',\n lineHeight: '1.6',\n fontFamily: 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace',\n color: 'var(--chatllm-code-block-text, #e5e7eb)',\n }}\n >\n <code>{code.trim()}</code>\n </pre>\n </div>\n );\n};\n\n/**\n * 이미지 복사 버튼이 있는 이미지 컴포넌트\n */\nconst ImageWithCopyButton: React.FC<{\n src: string;\n alt: string;\n imageKey: string;\n}> = ({ src, alt, imageKey }) => {\n const [isHovered, setIsHovered] = React.useState(false);\n const [copyState, setCopyState] = React.useState<'idle' | 'copying' | 'copied' | 'error'>('idle');\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // 이미지를 Blob으로 가져오는 공통 함수\n const getImageBlob = async (): Promise<Blob | null> => {\n // Method 1: Canvas (same-origin or data URLs)\n const img = imgRef.current;\n if (img && img.complete && img.naturalWidth > 0) {\n try {\n const canvas = document.createElement('canvas');\n canvas.width = img.naturalWidth;\n canvas.height = img.naturalHeight;\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.drawImage(img, 0, 0);\n const blob = await new Promise<Blob | null>((resolve) => {\n canvas.toBlob(resolve, 'image/png');\n });\n if (blob) return blob;\n }\n } catch {\n console.log('Canvas method failed (CORS), trying fetch...');\n }\n }\n\n // Method 2: Fetch (CORS-enabled images)\n if (!src.startsWith('data:')) {\n try {\n const response = await fetch(src, { mode: 'cors' });\n if (response.ok) {\n const blob = await response.blob();\n if (blob.type === 'image/png') return blob;\n\n // Convert to PNG\n const tempImg = new Image();\n const blobUrl = URL.createObjectURL(blob);\n return new Promise<Blob | null>((resolve) => {\n tempImg.onload = () => {\n const canvas = document.createElement('canvas');\n canvas.width = tempImg.naturalWidth;\n canvas.height = tempImg.naturalHeight;\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.drawImage(tempImg, 0, 0);\n canvas.toBlob((pngBlob) => {\n URL.revokeObjectURL(blobUrl);\n resolve(pngBlob);\n }, 'image/png');\n } else {\n URL.revokeObjectURL(blobUrl);\n resolve(null);\n }\n };\n tempImg.onerror = () => {\n URL.revokeObjectURL(blobUrl);\n resolve(null);\n };\n tempImg.src = blobUrl;\n });\n }\n } catch {\n console.log('Fetch method failed');\n }\n }\n return null;\n };\n\n // 복사 핸들러\n const handleCopy = async () => {\n setCopyState('copying');\n try {\n if (!navigator.clipboard?.write) {\n await navigator.clipboard.writeText(src);\n setCopyState('copied');\n setTimeout(() => setCopyState('idle'), 2000);\n return;\n }\n\n const blob = await getImageBlob();\n if (blob) {\n await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })]);\n setCopyState('copied');\n } else {\n await navigator.clipboard.writeText(src);\n setCopyState('copied');\n }\n setTimeout(() => setCopyState('idle'), 2000);\n } catch (error) {\n console.error('Failed to copy image:', error);\n setCopyState('error');\n setTimeout(() => setCopyState('idle'), 2000);\n }\n };\n\n // 다운로드 핸들러\n const handleDownload = async () => {\n try {\n const blob = await getImageBlob();\n const url = blob ? URL.createObjectURL(blob) : src;\n const link = document.createElement('a');\n link.href = url;\n link.download = alt || `image-${Date.now()}.png`;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n if (blob) URL.revokeObjectURL(url);\n } catch (error) {\n console.error('Failed to download image:', error);\n // Fallback: open in new tab\n window.open(src, '_blank');\n }\n };\n\n return (\n <div\n key={imageKey}\n style={{\n position: 'relative',\n display: 'inline-block',\n margin: '8px 0',\n }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n <img\n ref={imgRef}\n src={src}\n alt={alt}\n className=\"chatllm-image\"\n crossOrigin={src.startsWith('data:') ? undefined : 'anonymous'}\n style={{\n maxWidth: '100%',\n borderRadius: '8px',\n display: 'block',\n }}\n loading=\"lazy\"\n />\n {/* Bottom toolbar overlay - dark transparent style */}\n <div\n style={{\n position: 'absolute',\n bottom: '12px',\n left: '12px',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 16px',\n backgroundColor: 'rgba(0, 0, 0, 0.6)',\n backdropFilter: 'blur(12px)',\n borderRadius: '24px',\n opacity: isHovered ? 1 : 0,\n transition: 'opacity 0.2s ease',\n pointerEvents: isHovered ? 'auto' : 'none',\n }}\n >\n {/* Copy button */}\n <button\n onClick={handleCopy}\n disabled={copyState === 'copying'}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '32px',\n height: '32px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '50%',\n cursor: 'pointer',\n color: copyState === 'copied' ? '#22c55e' : copyState === 'error' ? '#ef4444' : 'rgba(255, 255, 255, 0.9)',\n transition: 'background-color 0.2s, color 0.2s',\n }}\n title={copyState === 'copied' ? '복사됨!' : copyState === 'error' ? '복사 실패' : '복사하기'}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.15)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n {copyState === 'copied' ? (\n <polyline points=\"20 6 9 17 4 12\" />\n ) : (\n <>\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </>\n )}\n </svg>\n </button>\n\n {/* Download button */}\n <button\n onClick={handleDownload}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '32px',\n height: '32px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '50%',\n cursor: 'pointer',\n color: 'rgba(255, 255, 255, 0.9)',\n transition: 'background-color 0.2s, color 0.2s',\n }}\n title=\"저장하기\"\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.15)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n </div>\n </div>\n );\n};\n\n/**\n * 선택지 버튼 렌더링 컴포넌트\n */\nconst ChoiceButtons: React.FC<{\n choices: ChoiceOption[];\n title?: string;\n onChoiceClick?: (choice: ChoiceOption) => void;\n}> = ({ choices, title, onChoiceClick }) => {\n const [hoveredIndex, setHoveredIndex] = React.useState<number | null>(null);\n\n return (\n <div\n className=\"chatllm-choices\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n margin: '16px 0',\n padding: '12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '12px',\n border: '1px solid var(--chatllm-border-light, #e5e7eb)',\n }}\n >\n <div\n style={{\n fontSize: title ? '14px' : '12px',\n fontWeight: 600,\n color: title ? 'var(--chatllm-text, #374151)' : 'var(--chatllm-text-muted, #6b7280)',\n marginBottom: '4px',\n textTransform: title ? 'none' : 'uppercase',\n letterSpacing: title ? 'normal' : '0.5px',\n }}\n >\n {title || '선택하세요'}\n </div>\n {choices.map((choice, index) => (\n <button\n key={choice.number}\n onClick={() => onChoiceClick?.(choice)}\n onMouseEnter={() => setHoveredIndex(index)}\n onMouseLeave={() => setHoveredIndex(null)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px 16px',\n backgroundColor: hoveredIndex === index\n ? 'var(--chatllm-primary-light, #dbeafe)'\n : 'var(--chatllm-bg, #ffffff)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s ease',\n }}\n >\n <span\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '28px',\n height: '28px',\n borderRadius: '50%',\n backgroundColor: hoveredIndex === index\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-bg-tertiary, #f3f4f6)',\n color: hoveredIndex === index\n ? '#ffffff'\n : 'var(--chatllm-text, #374151)',\n fontSize: '14px',\n fontWeight: 600,\n flexShrink: 0,\n transition: 'all 0.2s ease',\n }}\n >\n {choice.number}\n </span>\n <span\n style={{\n fontSize: '14px',\n color: 'var(--chatllm-text, #374151)',\n lineHeight: '1.5',\n }}\n >\n {choice.text}\n </span>\n </button>\n ))}\n </div>\n );\n};\n\n/**\n * 출처 링크 섹션 렌더링\n */\nconst SourceLinksSection: React.FC<{ links: ParsedLink[]; label?: string }> = ({ links, label }) => {\n return (\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: '8px',\n margin: '12px 0',\n padding: '12px',\n backgroundColor: 'var(--chatllm-source-bg, #f8fafc)',\n borderRadius: '8px',\n border: '1px solid var(--chatllm-border-light, #e2e8f0)',\n }}\n >\n {label && (\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-text-muted, #64748b)',\n marginRight: '4px',\n }}\n >\n {label}\n </span>\n )}\n {links.map((link, index) => (\n <LinkChip key={index} text={link.text} url={link.url} />\n ))}\n </div>\n );\n};\n\nexport const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({\n content,\n className,\n onChoiceClick,\n showThinking = true,\n thinkingDefaultOpen = false,\n sources,\n}) => {\n const rendered = useMemo(() => {\n const elements: React.ReactNode[] = [];\n let processedContent = content;\n\n /**\n * @description Thinking 블록 추출 및 치환\n * @Todo vibecode - 코드 블록 추출 전에 Thinking 먼저 처리\n */\n const thinkingBlocks: string[] = [];\n if (showThinking) {\n // 패턴 1: <thinking>...</thinking> 태그\n processedContent = processedContent.replace(THINKING_TAG_REGEX, (_, thinkContent) => {\n thinkingBlocks.push(thinkContent);\n return `§THINKING§${thinkingBlocks.length - 1}§/THINKING§`;\n });\n // 패턴 2: ```thinking 코드블록\n processedContent = processedContent.replace(THINKING_CODEBLOCK_REGEX, (_, thinkContent) => {\n thinkingBlocks.push(thinkContent);\n return `§THINKING§${thinkingBlocks.length - 1}§/THINKING§`;\n });\n // 패턴 3: \"Thinking:\" 텍스트 패턴\n processedContent = processedContent.replace(THINKING_TEXT_REGEX, (_, thinkContent) => {\n thinkingBlocks.push(thinkContent);\n return `§THINKING§${thinkingBlocks.length - 1}§/THINKING§`;\n });\n } else {\n // showThinking=false일 때는 Thinking 블록 완전히 제거\n processedContent = processedContent.replace(THINKING_TAG_REGEX, '');\n processedContent = processedContent.replace(THINKING_CODEBLOCK_REGEX, '');\n processedContent = processedContent.replace(THINKING_TEXT_REGEX, '');\n }\n\n /**\n * @description 닫히지 않은 <thinking> 태그 처리 (스트리밍 중)\n * @Todo vibecode - 스트리밍 중인 thinking 내용도 ThinkingBlock으로 표시\n */\n if (showThinking) {\n // 스트리밍 중인 thinking 내용을 ThinkingBlock으로 표시\n const unclosedMatch = processedContent.match(/<thinking>([\\s\\S]*)$/i);\n if (unclosedMatch) {\n const streamingThinkContent = unclosedMatch[1];\n thinkingBlocks.push(streamingThinkContent + '...');\n processedContent = processedContent.replace(/<thinking>[\\s\\S]*$/i, `§THINKING§${thinkingBlocks.length - 1}§/THINKING§`);\n }\n } else {\n processedContent = processedContent.replace(UNCLOSED_THINKING_TAG_REGEX, '');\n }\n\n /**\n * @description 완성된 <poll> 태그 제거 (PollCard가 별도 렌더링)\n * @Todo vibecode - 완성/미완성 모두 MarkdownRenderer에서 숨김\n */\n processedContent = processedContent.replace(/<poll[^>]*>[\\s\\S]*?<\\/poll>/gi, '');\n /** @Todo vibecode - 미완성 poll 태그 감지 시 로딩 플레이스홀더 삽입 */\n const hasUnfinishedPoll = UNCLOSED_POLL_TAG_REGEX.test(processedContent);\n UNCLOSED_POLL_TAG_REGEX.lastIndex = 0;\n processedContent = processedContent.replace(UNCLOSED_POLL_TAG_REGEX, '');\n if (hasUnfinishedPoll) {\n processedContent += '\\n§POLL_LOADING§';\n }\n\n /**\n * @description 불완전한 <skill_use> 태그 제거 (스트리밍 중)\n * @Todo vibecode - </skill_use> 없이 끝나는 skill_use 태그 전체 제거\n */\n processedContent = processedContent.replace(UNCLOSED_SKILL_TAG_REGEX, '');\n\n // 1. 코드 블록 추출 및 치환\n const codeBlocks: { language: string; code: string }[] = [];\n processedContent = processedContent.replace(CODE_BLOCK_REGEX, (match, lang, code) => {\n /**\n * @description markdown/md 코드블록 내 테이블 감지 및 변환\n * @Todo vibecode - 파이프, 탭, 공백 구분 테이블 모두 표준 마크다운 테이블로 처리\n */\n if (lang === 'markdown' || lang === 'md') {\n const trimmedCode = code.trim();\n\n // Case 1: 표준 파이프 구분 테이블 → 원문 유지\n if (TABLE_ROW_REGEX.test(trimmedCode.split('\\n')[0])) {\n return '\\n' + trimmedCode + '\\n';\n }\n\n // Case 2: 비표준 테이블(탭/공백) → 파이프 테이블로 변환\n const converted = convertNonStandardTable(trimmedCode);\n if (converted) {\n return '\\n' + converted + '\\n';\n }\n }\n codeBlocks.push({ language: lang || '', code });\n return `§CODEBLOCK§${codeBlocks.length - 1}§/CODEBLOCK§`;\n });\n\n // 2. 출처 링크 섹션 추출 및 치환\n const sourceSections: { label: string; links: ParsedLink[] }[] = [];\n processedContent = processedContent.replace(SOURCE_LINKS_REGEX, (match, label, linksText) => {\n const links = parseSourceLinks(linksText);\n if (links.length > 0) {\n sourceSections.push({ label: label?.replace(/\\*+/g, '').trim() || '출처', links });\n return `§SOURCES§${sourceSections.length - 1}§/SOURCES§`;\n }\n return match;\n });\n\n // 3. 줄 단위로 파싱\n const lines = processedContent.split('\\n');\n let currentList: { type: 'ul' | 'ol'; items: React.ReactNode[] } | null = null;\n let blockquoteLines: string[] = [];\n let tableLines: string[] = [];\n // 선택지 수집용\n let choiceItems: ChoiceOption[] = [];\n\n const flushTable = () => {\n if (tableLines.length >= 2) {\n // Need at least header + separator\n const headerLine = tableLines[0];\n const separatorLine = tableLines[1];\n const dataLines = tableLines.slice(2);\n\n if (TABLE_SEPARATOR_REGEX.test(separatorLine)) {\n const headers = parseTableRow(headerLine);\n const alignments = parseTableAlignment(separatorLine);\n const rows = dataLines.map((line) => parseTableRow(line));\n\n elements.push(\n <MarkdownTable\n key={`table-${elements.length}`}\n data={{ headers, alignments, rows }}\n />\n );\n } else {\n // Not a valid table, render as regular lines\n tableLines.forEach((line, i) => {\n elements.push(\n <p key={`p-table-fallback-${elements.length}-${i}`} style={{ margin: '4px 0' }}>\n {parseInlineElements(line, `p-table-fallback-${i}`, sources)}\n </p>\n );\n });\n }\n }\n tableLines = [];\n };\n\n const flushChoices = () => {\n if (choiceItems.length >= 2 && onChoiceClick) {\n // 선택지가 2개 이상이고 콜백이 있으면 버튼으로 렌더링\n elements.push(\n <ChoiceButtons\n key={`choices-${elements.length}`}\n choices={choiceItems}\n onChoiceClick={onChoiceClick}\n />\n );\n choiceItems = [];\n return true;\n }\n choiceItems = [];\n return false;\n };\n\n const flushList = () => {\n if (currentList) {\n if (currentList.type === 'ul') {\n elements.push(\n <ul key={`ul-${elements.length}`} style={{ margin: '8px 0', paddingLeft: '24px' }}>\n {currentList.items}\n </ul>\n );\n } else {\n // 순서 리스트: 선택지로 변환 시도\n if (!flushChoices()) {\n // 선택지로 변환되지 않으면 일반 리스트로 렌더링\n elements.push(\n <ol key={`ol-${elements.length}`} style={{ margin: '8px 0', paddingLeft: '24px' }}>\n {currentList.items}\n </ol>\n );\n }\n }\n currentList = null;\n }\n };\n\n const flushBlockquote = () => {\n if (blockquoteLines.length > 0) {\n elements.push(\n <blockquote\n key={`bq-${elements.length}`}\n style={{\n margin: '12px 0',\n padding: '12px 16px',\n borderLeft: '4px solid var(--chatllm-primary, #3b82f6)',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '0 8px 8px 0',\n color: 'var(--chatllm-text, #374151)',\n }}\n >\n {blockquoteLines.map((line, i) => (\n <React.Fragment key={i}>\n {parseInlineElements(line, `bq-line-${i}`, sources)}\n {i < blockquoteLines.length - 1 && <br />}\n </React.Fragment>\n ))}\n </blockquote>\n );\n blockquoteLines = [];\n }\n };\n\n lines.forEach((line, lineIndex) => {\n /**\n * @description Thinking 블록 마커 처리\n * @Todo vibecode - ThinkingBlock 컴포넌트로 렌더링\n */\n const thinkingMatch = line.match(/§THINKING§(\\d+)§\\/THINKING§/);\n if (thinkingMatch) {\n flushList();\n flushBlockquote();\n const index = parseInt(thinkingMatch[1]);\n elements.push(\n <ThinkingBlock\n key={`thinking-${lineIndex}`}\n content={thinkingBlocks[index]}\n defaultOpen={thinkingDefaultOpen}\n />\n );\n return;\n }\n\n /** @Todo vibecode - Poll 로딩 플레이스홀더 처리 (스트리밍 중 선택지 준비 표시) */\n if (line.trim() === '§POLL_LOADING§') {\n flushList();\n flushBlockquote();\n elements.push(\n <div\n key={`poll-loading-${lineIndex}`}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '14px 16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '10px',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n marginTop: '12px',\n animation: 'chatllm-pulse 1.5s ease-in-out infinite',\n }}\n >\n <div\n style={{\n width: '18px',\n height: '18px',\n borderRadius: '50%',\n border: '2px solid var(--chatllm-primary, #4A90E2)',\n borderTopColor: 'transparent',\n animation: 'chatllm-spin 0.8s linear infinite',\n }}\n />\n <span style={{ fontSize: '13px', color: 'var(--chatllm-text-muted, #64748b)' }}>\n 선택지를 준비하고 있어요...\n </span>\n </div>\n );\n return;\n }\n\n // 코드 블록 마커 처리\n const codeBlockMatch = line.match(/§CODEBLOCK§(\\d+)§\\/CODEBLOCK§/);\n if (codeBlockMatch) {\n flushList();\n flushBlockquote();\n const index = parseInt(codeBlockMatch[1]);\n elements.push(\n <CodeBlock key={`codeblock-${lineIndex}`} {...codeBlocks[index]} />\n );\n return;\n }\n\n // 출처 링크 마커 처리\n const sourcesMatch = line.match(/§SOURCES§(\\d+)§\\/SOURCES§/);\n if (sourcesMatch) {\n flushList();\n flushBlockquote();\n const index = parseInt(sourcesMatch[1]);\n elements.push(\n <SourceLinksSection key={`sources-${lineIndex}`} {...sourceSections[index]} />\n );\n return;\n }\n\n // 테이블 행 감지\n if (TABLE_ROW_REGEX.test(line)) {\n flushList();\n flushBlockquote();\n tableLines.push(line);\n return;\n } else if (tableLines.length > 0) {\n // 테이블이 끝났음\n flushTable();\n }\n\n // 수평선\n if (HR_REGEX.test(line)) {\n flushList();\n flushBlockquote();\n elements.push(\n <hr\n key={`hr-${lineIndex}`}\n style={{\n margin: '16px 0',\n border: 'none',\n borderTop: '1px solid var(--chatllm-border, #e5e7eb)',\n }}\n />\n );\n return;\n }\n\n // 헤딩\n const headingMatch = line.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n flushList();\n flushBlockquote();\n const level = headingMatch[1].length;\n const text = headingMatch[2];\n const HeadingTag = `h${level}` as keyof JSX.IntrinsicElements;\n const sizes: Record<number, string> = {\n 1: '1.5em',\n 2: '1.3em',\n 3: '1.15em',\n 4: '1.05em',\n 5: '1em',\n 6: '0.95em',\n };\n elements.push(\n <HeadingTag\n key={`heading-${lineIndex}`}\n style={{\n fontSize: sizes[level],\n fontWeight: level <= 2 ? 600 : 500,\n margin: '16px 0 8px',\n color: 'var(--chatllm-text, #1f2937)',\n }}\n >\n {parseInlineElements(text, `heading-${lineIndex}`, sources)}\n </HeadingTag>\n );\n return;\n }\n\n // 인용문\n const blockquoteMatch = line.match(/^>\\s*(.*)$/);\n if (blockquoteMatch) {\n flushList();\n blockquoteLines.push(blockquoteMatch[1]);\n return;\n } else {\n flushBlockquote();\n }\n\n // 비순서 리스트\n const ulMatch = line.match(/^[\\-\\*]\\s+(.+)$/);\n if (ulMatch) {\n flushBlockquote();\n if (!currentList || currentList.type !== 'ul') {\n flushList();\n currentList = { type: 'ul', items: [] };\n }\n currentList.items.push(\n <li key={`li-${lineIndex}`} style={{ margin: '4px 0' }}>\n {parseInlineElements(ulMatch[1], `li-${lineIndex}`, sources)}\n </li>\n );\n return;\n }\n\n // 순서 리스트 (선택지 후보 수집 포함)\n const olMatch = line.match(/^(\\d+)[.)]\\s+(.+)$/);\n if (olMatch) {\n flushBlockquote();\n if (!currentList || currentList.type !== 'ol') {\n flushList();\n currentList = { type: 'ol', items: [] };\n }\n\n const itemNumber = parseInt(olMatch[1]);\n const itemText = olMatch[2];\n\n // 선택지 후보로도 수집 (짧은 텍스트만, 100자 이하)\n if (itemText.length <= 100) {\n choiceItems.push({\n number: itemNumber,\n text: itemText,\n fullText: line,\n });\n }\n\n currentList.items.push(\n <li key={`li-${lineIndex}`} style={{ margin: '4px 0' }}>\n {parseInlineElements(itemText, `li-${lineIndex}`, sources)}\n </li>\n );\n return;\n }\n\n // 리스트 종료\n flushList();\n\n // 빈 줄\n if (!line.trim()) {\n elements.push(<br key={`br-${lineIndex}`} />);\n return;\n }\n\n // 인라인 선택지 체크 ([1] 텍스트 [2] 텍스트 형식)\n if (onChoiceClick) {\n const choiceBlock = parseInlineChoices(line);\n if (choiceBlock) {\n elements.push(\n <ChoiceButtons\n key={`inline-choices-${lineIndex}`}\n choices={choiceBlock.choices}\n title={choiceBlock.title}\n onChoiceClick={onChoiceClick}\n />\n );\n return;\n }\n }\n\n /**\n * @description 일반 텍스트 렌더링\n * @Todo vibecode - 이미지 포함 시 <div> 사용 (HTML 규칙: <p> 안에 <div> 불가)\n */\n const hasImage = IMAGE_REGEX.test(line);\n // 이미지가 있으면 div 사용, 없으면 p 사용\n if (hasImage) {\n elements.push(\n <div key={`p-${lineIndex}`} style={{ margin: '4px 0' }}>\n {parseInlineElements(line, `p-${lineIndex}`, sources)}\n </div>\n );\n } else {\n elements.push(\n <p key={`p-${lineIndex}`} style={{ margin: '4px 0' }}>\n {parseInlineElements(line, `p-${lineIndex}`, sources)}\n </p>\n );\n }\n });\n\n // 남은 리스트/인용문/테이블 처리\n flushList();\n flushBlockquote();\n flushTable();\n\n return elements;\n }, [content, onChoiceClick, sources]);\n\n return (\n <div\n className={`chatllm-markdown ${className || ''}`}\n style={{\n fontSize: '15px',\n lineHeight: '1.7',\n color: 'var(--chatllm-text, #374151)',\n }}\n >\n {rendered}\n </div>\n );\n};\n\nexport default MarkdownRenderer;\n","/**\n * @description 링크 칩 컴포넌트\n * 출처 링크를 칩 형태로 표시\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\n\nexport interface LinkChipProps {\n /** 링크 텍스트 */\n text: string;\n /** 링크 URL */\n url: string;\n /** 파비콘 표시 여부 */\n showFavicon?: boolean;\n /** 번호 표시 */\n index?: number;\n /** 커스텀 스타일 */\n style?: React.CSSProperties;\n}\n\n/**\n * URL에서 도메인 추출\n */\nconst getDomain = (url: string): string => {\n try {\n const urlObj = new URL(url);\n return urlObj.hostname.replace('www.', '');\n } catch {\n return url;\n }\n};\n\n/**\n * 도메인에서 짧은 이름 추출\n */\nconst getShortName = (domain: string): string => {\n const parts = domain.split('.');\n if (parts.length >= 2) {\n return parts[parts.length - 2];\n }\n return domain;\n};\n\n/**\n * 도메인별 색상 매핑\n */\nconst getDomainColor = (domain: string): string => {\n const lowerDomain = domain.toLowerCase();\n\n // 주요 사이트 색상\n const colorMap: Record<string, string> = {\n 'google': '#4285f4',\n 'wikipedia': '#000000',\n 'github': '#24292e',\n 'stackoverflow': '#f48024',\n 'medium': '#00ab6c',\n 'youtube': '#ff0000',\n 'twitter': '#1da1f2',\n 'naver': '#03c75a',\n 'namu': '#00a495',\n 'tistory': '#eb531f',\n 'velog': '#20c997',\n 'brave': '#fb542b',\n 'mk': '#0066cc',\n 'ko': '#3366cc',\n };\n\n for (const [key, color] of Object.entries(colorMap)) {\n if (lowerDomain.includes(key)) {\n return color;\n }\n }\n\n // 기본 색상 (해시 기반)\n let hash = 0;\n for (let i = 0; i < domain.length; i++) {\n hash = domain.charCodeAt(i) + ((hash << 5) - hash);\n }\n const hue = hash % 360;\n return `hsl(${hue}, 60%, 45%)`;\n};\n\nexport const LinkChip: React.FC<LinkChipProps> = ({\n text,\n url,\n showFavicon = true,\n index,\n style,\n}) => {\n const [isHovered, setIsHovered] = useState(false);\n const domain = getDomain(url);\n const shortName = getShortName(domain);\n const domainColor = getDomainColor(domain);\n\n // 텍스트에서 번호 추출 (예: \"1. brave\" -> { number: 1, label: \"brave\" })\n const parseText = (t: string): { number?: string; label: string } => {\n const match = t.match(/^(\\d+)\\.\\s*(.+)$/);\n if (match) {\n return { number: match[1], label: match[2] };\n }\n return { label: t };\n };\n\n const parsed = parseText(text);\n const displayNumber = index !== undefined ? String(index + 1) : parsed.number;\n const displayLabel = parsed.label;\n\n return (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '6px',\n padding: '4px 10px',\n backgroundColor: isHovered\n ? 'var(--chatllm-chip-bg-hover, #e2e8f0)'\n : 'var(--chatllm-chip-bg, #f1f5f9)',\n border: '1px solid var(--chatllm-chip-border, #e2e8f0)',\n borderRadius: '16px',\n textDecoration: 'none',\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-chip-text, #475569)',\n transition: 'all 0.15s ease',\n cursor: 'pointer',\n maxWidth: '180px',\n ...style,\n }}\n title={`${displayLabel} - ${domain}`}\n >\n {/* 번호 배지 */}\n {displayNumber && (\n <span\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '18px',\n height: '18px',\n borderRadius: '50%',\n backgroundColor: domainColor,\n color: '#ffffff',\n fontSize: '11px',\n fontWeight: 600,\n flexShrink: 0,\n }}\n >\n {displayNumber}\n </span>\n )}\n\n {/* 파비콘 또는 링크 아이콘 */}\n {showFavicon && !displayNumber && (\n <span\n style={{\n width: '16px',\n height: '16px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n >\n <IconSvg\n name=\"links-line\"\n size={14}\n color={domainColor}\n />\n </span>\n )}\n\n {/* 텍스트 */}\n <span\n style={{\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {displayLabel}\n </span>\n\n {/* 외부 링크 아이콘 */}\n <IconSvg\n name=\"external-link-line\"\n size={12}\n color=\"var(--chatllm-text-muted, #94a3b8)\"\n style={{\n opacity: isHovered ? 1 : 0.6,\n flexShrink: 0,\n }}\n />\n </a>\n );\n};\n\nexport default LinkChip;\n","/**\n * @description 심층연구 진행 상태 UI 컴포넌트\n * @Todo vibecode - 심층연구 4단계 진행 상태 표시\n */\n\nimport React from 'react';\nimport { IconSvg } from './Icon';\nimport type { DeepResearchProgress, SubAgentProgress } from '../types';\n\nexport interface DeepResearchProgressUIProps {\n progress: DeepResearchProgress;\n}\n\n/**\n * @description 상태별 아이콘 컴포넌트\n */\nconst StatusIcon: React.FC<{ status: SubAgentProgress['status'] }> = ({ status }) => {\n switch (status) {\n case 'pending':\n return (\n <div\n style={{\n width: 16,\n height: 16,\n borderRadius: '50%',\n border: '2px solid var(--chatllm-border)',\n backgroundColor: 'transparent',\n }}\n />\n );\n case 'searching':\n case 'extracting':\n return (\n <div\n style={{\n width: 16,\n height: 16,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <div\n style={{\n width: 12,\n height: 12,\n borderRadius: '50%',\n border: '2px solid var(--chatllm-primary)',\n borderTopColor: 'transparent',\n animation: 'chatllm-spin 1s linear infinite',\n }}\n />\n </div>\n );\n case 'done':\n return <IconSvg name=\"check-line\" size={16} color=\"var(--chatllm-success, #10b981)\" />;\n case 'error':\n return <IconSvg name=\"close-line\" size={16} color=\"var(--chatllm-error, #ef4444)\" />;\n default:\n return null;\n }\n};\n\n/**\n * @description 단계별 진행 표시 바\n */\nconst PhaseProgress: React.FC<{ phase: DeepResearchProgress['phase'] }> = ({ phase }) => {\n const phases = ['analyzing', 'researching', 'evaluating', 'generating', 'done'] as const;\n const currentIndex = phases.indexOf(phase);\n\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginBottom: '16px',\n }}\n >\n {phases.slice(0, 4).map((p, index) => (\n <React.Fragment key={p}>\n <div\n style={{\n width: 24,\n height: 24,\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '12px',\n fontWeight: 600,\n backgroundColor:\n index < currentIndex\n ? 'var(--chatllm-primary)'\n : index === currentIndex\n ? 'var(--chatllm-primary-light)'\n : 'var(--chatllm-bg-secondary)',\n color:\n index < currentIndex\n ? '#fff'\n : index === currentIndex\n ? 'var(--chatllm-primary)'\n : 'var(--chatllm-text-muted)',\n border:\n index === currentIndex\n ? '2px solid var(--chatllm-primary)'\n : '2px solid transparent',\n }}\n >\n {index < currentIndex ? (\n <IconSvg name=\"check-line\" size={14} color=\"#fff\" />\n ) : (\n index + 1\n )}\n </div>\n {index < 3 && (\n <div\n style={{\n flex: 1,\n height: 2,\n backgroundColor:\n index < currentIndex\n ? 'var(--chatllm-primary)'\n : 'var(--chatllm-border)',\n }}\n />\n )}\n </React.Fragment>\n ))}\n </div>\n );\n};\n\n/**\n * @description 심층연구 진행 상태 UI\n */\nexport const DeepResearchProgressUI: React.FC<DeepResearchProgressUIProps> = ({ progress }) => {\n return (\n <div\n className=\"chatllm-research-progress\"\n style={{\n padding: '20px',\n backgroundColor: 'var(--chatllm-bg-secondary)',\n borderRadius: '16px',\n border: '1px solid var(--chatllm-border)',\n }}\n >\n {/* 헤더 */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n marginBottom: '16px',\n }}\n >\n <IconSvg name=\"search-eye-line\" size={20} color=\"var(--chatllm-primary)\" />\n <span\n style={{\n fontSize: '15px',\n fontWeight: 600,\n color: 'var(--chatllm-text)',\n }}\n >\n 심층연구\n </span>\n </div>\n\n {/* 단계 진행 표시 */}\n <PhaseProgress phase={progress.phase} />\n\n {/* 현재 단계 라벨 */}\n <div\n className=\"chatllm-research-progress__phase\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n marginBottom: '16px',\n }}\n >\n {progress.phase !== 'done' && (\n <div\n style={{\n width: 16,\n height: 16,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <div\n style={{\n width: 14,\n height: 14,\n borderRadius: '50%',\n border: '2px solid var(--chatllm-primary)',\n borderTopColor: 'transparent',\n animation: 'chatllm-spin 1s linear infinite',\n }}\n />\n </div>\n )}\n <span\n style={{\n fontSize: '14px',\n color: 'var(--chatllm-text-secondary)',\n }}\n >\n {progress.phaseLabel}\n </span>\n </div>\n\n {/* 서브에이전트 상태 (검색 단계일 때) */}\n {progress.phase === 'researching' && progress.subAgents.length > 0 && (\n <div\n className=\"chatllm-research-progress__agents\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: '10px',\n marginBottom: '16px',\n }}\n >\n {progress.subAgents.map((agent) => (\n <div\n key={agent.id}\n className=\"chatllm-research-progress__agent\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 14px',\n backgroundColor: 'var(--chatllm-bg)',\n borderRadius: '10px',\n border: '1px solid var(--chatllm-border)',\n }}\n >\n <StatusIcon status={agent.status} />\n <span\n style={{\n flex: 1,\n fontSize: '13px',\n color: 'var(--chatllm-text)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {agent.topic}\n </span>\n <span\n className=\"count\"\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted)',\n whiteSpace: 'nowrap',\n }}\n >\n {agent.resultsCount}개 수집\n </span>\n </div>\n ))}\n </div>\n )}\n\n {/* 전체 소스 카운트 */}\n <div\n className=\"chatllm-research-progress__total\"\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 14px',\n backgroundColor: 'var(--chatllm-primary-light)',\n borderRadius: '10px',\n }}\n >\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-primary)',\n }}\n >\n 총 {progress.totalSources}개 소스 수집\n </span>\n <IconSvg name=\"file-text-line\" size={16} color=\"var(--chatllm-primary)\" />\n </div>\n </div>\n );\n};\n\nexport default DeepResearchProgressUI;\n","/**\n * @description AI 주도 선택지 (Poll) 컴포넌트\n * @Todo vibecode - Claude Code 스타일 탭 UI (여러 질문 한 번에)\n */\n\nimport React, { useState, useCallback, useEffect } from 'react';\nimport { IconSvg } from './Icon';\nimport type { PollQuestion, PollResponse } from '../types';\n\n/**\n * @description 마크다운 인라인 서식을 React 엘리먼트로 렌더링\n * @Todo vibecode - **bold**, *italic*, `code`, ~~strikethrough~~ → styled span\n */\nconst renderInlineMarkdown = (text: string): React.ReactNode => {\n const parts: React.ReactNode[] = [];\n let remaining = text;\n let key = 0;\n\n while (remaining.length > 0) {\n /** @Todo vibecode - bold(**) → italic(*) → code(`) → strikethrough(~~) 순서 매칭 */\n const match = remaining.match(\n /(\\*\\*(.+?)\\*\\*|__(.+?)__|`(.+?)`|~~(.+?)~~|\\*(.+?)\\*|_(.+?)_)/\n );\n\n if (!match || match.index === undefined) {\n parts.push(remaining);\n break;\n }\n\n if (match.index > 0) {\n parts.push(remaining.slice(0, match.index));\n }\n\n const fullMatch = match[0];\n if (match[2] || match[3]) {\n parts.push(<strong key={key++}>{match[2] || match[3]}</strong>);\n } else if (match[4]) {\n parts.push(\n <code key={key++} style={{ backgroundColor: 'var(--chatllm-bg-tertiary, #f1f5f9)', padding: '1px 4px', borderRadius: '3px', fontSize: '0.9em' }}>\n {match[4]}\n </code>\n );\n } else if (match[5]) {\n parts.push(<s key={key++}>{match[5]}</s>);\n } else if (match[6] || match[7]) {\n parts.push(<em key={key++}>{match[6] || match[7]}</em>);\n }\n\n remaining = remaining.slice(match.index + fullMatch.length);\n }\n\n return parts.length === 1 && typeof parts[0] === 'string' ? parts[0] : <>{parts}</>;\n};\n\n/** @Todo vibecode - 탭 제목용 마크다운 제거 (plain text 필요) */\nconst stripMarkdown = (text: string): string =>\n text\n .replace(/\\*\\*(.+?)\\*\\*/g, '$1')\n .replace(/__(.+?)__/g, '$1')\n .replace(/\\*(.+?)\\*/g, '$1')\n .replace(/_(.+?)_/g, '$1')\n .replace(/`(.+?)`/g, '$1')\n .replace(/~~(.+?)~~/g, '$1');\n\nexport interface PollCardProps {\n /** 모든 질문 목록 */\n questions: PollQuestion[];\n /** 제출 콜백 (모든 질문의 응답) */\n onSubmit: (responses: PollResponse[]) => void;\n /** 건너뛰기 콜백 */\n onSkip?: () => void;\n}\n\n/**\n * @description 탭 형식 Poll 카드 컴포넌트\n * @Todo vibecode - 여러 질문을 탭으로 표시, 모두 답변 후 제출\n */\nexport const PollCard: React.FC<PollCardProps> = ({\n questions,\n onSubmit,\n onSkip,\n}) => {\n const [activeTab, setActiveTab] = useState(0);\n // 각 질문별 선택 상태: { questionId: Set<optionId> }\n const [selections, setSelections] = useState<Record<string, Set<string>>>({});\n // 각 질문별 기타 텍스트\n const [otherTexts, setOtherTexts] = useState<Record<string, string>>({});\n // 각 질문별 기타 선택 여부\n const [otherSelected, setOtherSelected] = useState<Record<string, boolean>>({});\n\n const currentQuestion = questions[activeTab];\n\n const handleOptionToggle = useCallback(\n (questionId: string, optionId: string, multiSelect: boolean) => {\n setSelections((prev) => {\n const current = prev[questionId] || new Set();\n const next = new Set(current);\n\n if (multiSelect) {\n if (next.has(optionId)) {\n next.delete(optionId);\n } else {\n next.add(optionId);\n }\n } else {\n next.clear();\n next.add(optionId);\n // 단일 선택 시 기타 해제\n setOtherSelected((os) => ({ ...os, [questionId]: false }));\n setOtherTexts((ot) => ({ ...ot, [questionId]: '' }));\n }\n\n return { ...prev, [questionId]: next };\n });\n },\n []\n );\n\n const handleOtherToggle = useCallback((questionId: string, multiSelect: boolean) => {\n if (multiSelect) {\n setOtherSelected((prev) => ({ ...prev, [questionId]: !prev[questionId] }));\n } else {\n setSelections((prev) => ({ ...prev, [questionId]: new Set() }));\n setOtherSelected((prev) => ({ ...prev, [questionId]: true }));\n }\n }, []);\n\n const handleSubmit = useCallback(() => {\n const responses: PollResponse[] = questions.map((q) => {\n const selected = selections[q.id] || new Set();\n const other = otherSelected[q.id] && otherTexts[q.id]?.trim();\n\n return {\n questionId: q.id,\n selectedOptions: Array.from(selected),\n otherText: other || undefined,\n skipped: false,\n };\n });\n onSubmit(responses);\n }, [questions, selections, otherSelected, otherTexts, onSubmit]);\n\n const handleSkip = useCallback(() => {\n const responses: PollResponse[] = questions.map((q) => ({\n questionId: q.id,\n selectedOptions: [],\n skipped: true,\n }));\n onSubmit(responses);\n onSkip?.();\n }, [questions, onSubmit, onSkip]);\n\n // ESC로 건너뛰기\n useEffect(() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n if (typeof window === 'undefined') return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') handleSkip();\n };\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [handleSkip]);\n\n // 각 질문별 선택 수\n const getSelectionCount = (questionId: string) => {\n const selected = selections[questionId]?.size || 0;\n const other = otherSelected[questionId] && otherTexts[questionId]?.trim() ? 1 : 0;\n return selected + other;\n };\n\n // 현재 탭 선택 여부\n const currentHasSelection = getSelectionCount(currentQuestion.id) > 0;\n const isLastTab = activeTab === questions.length - 1;\n const totalSelected = questions.reduce((sum, q) => sum + getSelectionCount(q.id), 0);\n\n /** @Todo vibecode - 마운트 시 옵션 stagger 애니메이션 (순차 등장) */\n const [visibleCount, setVisibleCount] = useState(0);\n const [cardVisible, setCardVisible] = useState(false);\n\n useEffect(() => {\n /** @Todo vibecode - 카드 페이드인 후 옵션 순차 등장 */\n const fadeTimer = setTimeout(() => setCardVisible(true), 50);\n const totalItems = currentQuestion.options.length + 1;\n const timers: ReturnType<typeof setTimeout>[] = [fadeTimer];\n\n for (let i = 1; i <= totalItems; i++) {\n timers.push(setTimeout(() => setVisibleCount(i), 150 + i * 80));\n }\n return () => timers.forEach(clearTimeout);\n }, [currentQuestion.options.length]);\n\n /** @Todo vibecode - 탭 전환 시 애니메이션 리셋 */\n useEffect(() => {\n setVisibleCount(0);\n const totalItems = currentQuestion.options.length + 1;\n const timers: ReturnType<typeof setTimeout>[] = [];\n for (let i = 1; i <= totalItems; i++) {\n timers.push(setTimeout(() => setVisibleCount(i), i * 80));\n }\n return () => timers.forEach(clearTimeout);\n }, [activeTab, currentQuestion.options.length]);\n\n /**\n * @description 확인 버튼: 다음 탭 이동 또는 마지막 탭에서 제출\n * @Todo vibecode - 탭 간 순차 이동 후 최종 제출\n */\n const handleNext = useCallback(() => {\n if (!isLastTab) {\n setActiveTab((prev) => prev + 1);\n } else {\n handleSubmit();\n }\n }, [isLastTab, handleSubmit]);\n\n return (\n <div\n className=\"chatllm-poll-card\"\n style={{\n backgroundColor: 'var(--chatllm-content-bg, #fff)',\n borderRadius: '12px',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n overflow: 'hidden',\n opacity: cardVisible ? 1 : 0,\n transform: cardVisible ? 'translateY(0)' : 'translateY(8px)',\n transition: 'opacity 0.3s ease, transform 0.3s ease',\n marginTop: '12px',\n }}\n >\n {/* Tabs */}\n {questions.length > 1 && (\n <div\n style={{\n display: 'flex',\n borderBottom: '1px solid var(--chatllm-border, #e5e7eb)',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n }}\n >\n {questions.map((q, idx) => {\n const isActive = idx === activeTab;\n const hasSelection = getSelectionCount(q.id) > 0;\n return (\n <button\n key={q.id}\n onClick={() => setActiveTab(idx)}\n style={{\n flex: 1,\n padding: '12px 16px',\n backgroundColor: isActive ? 'var(--chatllm-content-bg, #fff)' : 'transparent',\n border: 'none',\n borderBottom: isActive ? '2px solid var(--chatllm-primary, #4A90E2)' : '2px solid transparent',\n cursor: 'pointer',\n fontSize: '13px',\n fontWeight: isActive ? 600 : 500,\n color: isActive ? 'var(--chatllm-primary, #4A90E2)' : 'var(--chatllm-text-muted, #64748b)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '6px',\n transition: 'all 0.15s ease',\n }}\n >\n {hasSelection && (\n <IconSvg name=\"check-line\" size={14} color=\"var(--chatllm-success, #22c55e)\" />\n )}\n {(() => { const t = stripMarkdown(q.question); return t.length > 15 ? t.substring(0, 15) + '...' : t; })()}\n </button>\n );\n })}\n </div>\n )}\n\n {/* Question Header */}\n <div\n style={{\n padding: '16px',\n borderBottom: '1px solid var(--chatllm-border-light, #f1f5f9)',\n }}\n >\n <div\n style={{\n fontSize: '15px',\n fontWeight: 600,\n color: 'var(--chatllm-text, #1e293b)',\n }}\n >\n {renderInlineMarkdown(currentQuestion.question)}\n </div>\n {currentQuestion.multiSelect && (\n <div\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted, #94a3b8)',\n marginTop: '4px',\n }}\n >\n 복수 선택 가능\n </div>\n )}\n </div>\n\n {/* Options */}\n <div style={{ padding: '8px' }}>\n {currentQuestion.options.map((option, optIdx) => {\n const isSelected = selections[currentQuestion.id]?.has(option.id) || false;\n /** @Todo vibecode - stagger 애니메이션: visibleCount 기반 순차 등장 */\n const isVisible = optIdx < visibleCount;\n return (\n <button\n key={option.id}\n onClick={() => handleOptionToggle(currentQuestion.id, option.id, currentQuestion.multiSelect ?? false)}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'flex-start',\n gap: '12px',\n padding: '12px 14px',\n backgroundColor: isSelected\n ? 'var(--chatllm-primary-light, rgba(74, 144, 226, 0.08))'\n : 'transparent',\n border: isSelected\n ? '1px solid var(--chatllm-primary, #4A90E2)'\n : '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'all 0.2s ease',\n marginBottom: '6px',\n opacity: isVisible ? 1 : 0,\n transform: isVisible ? 'translateY(0)' : 'translateY(6px)',\n }}\n >\n {/* Checkbox */}\n <div\n style={{\n width: '20px',\n height: '20px',\n borderRadius: currentQuestion.multiSelect ? '4px' : '50%',\n border: `2px solid ${isSelected ? 'var(--chatllm-primary, #4A90E2)' : 'var(--chatllm-border, #d1d5db)'}`,\n backgroundColor: isSelected ? 'var(--chatllm-primary, #4A90E2)' : 'transparent',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n marginTop: '2px',\n transition: 'all 0.15s ease',\n }}\n >\n {isSelected && <IconSvg name=\"check-line\" size={14} color=\"#fff\" />}\n </div>\n <div style={{ flex: 1 }}>\n <span\n style={{\n fontSize: '14px',\n fontWeight: 500,\n color: 'var(--chatllm-text, #1e293b)',\n lineHeight: '1.4',\n }}\n >\n {renderInlineMarkdown(option.label)}\n </span>\n {option.description && (\n <div\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted, #64748b)',\n marginTop: '2px',\n lineHeight: '1.3',\n }}\n >\n {renderInlineMarkdown(option.description)}\n </div>\n )}\n </div>\n </button>\n );\n })}\n\n {/* Other Option */}\n {currentQuestion.allowOther !== false && (() => {\n /** @Todo vibecode - 기타 옵션도 stagger 애니메이션 적용 */\n const otherVisible = currentQuestion.options.length < visibleCount;\n return (\n <>\n <button\n onClick={() => handleOtherToggle(currentQuestion.id, currentQuestion.multiSelect ?? false)}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px 14px',\n backgroundColor: otherSelected[currentQuestion.id]\n ? 'var(--chatllm-primary-light, rgba(74, 144, 226, 0.08))'\n : 'transparent',\n border: otherSelected[currentQuestion.id]\n ? '1px solid var(--chatllm-primary, #4A90E2)'\n : '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'all 0.2s ease',\n opacity: otherVisible ? 1 : 0,\n transform: otherVisible ? 'translateY(0)' : 'translateY(6px)',\n }}\n >\n <div\n style={{\n width: '20px',\n height: '20px',\n borderRadius: currentQuestion.multiSelect ? '4px' : '50%',\n border: `2px solid ${otherSelected[currentQuestion.id] ? 'var(--chatllm-primary, #4A90E2)' : 'var(--chatllm-border, #d1d5db)'}`,\n backgroundColor: otherSelected[currentQuestion.id] ? 'var(--chatllm-primary, #4A90E2)' : 'transparent',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n transition: 'all 0.15s ease',\n }}\n >\n {otherSelected[currentQuestion.id] && <IconSvg name=\"check-line\" size={14} color=\"#fff\" />}\n </div>\n <span style={{ fontSize: '14px', color: 'var(--chatllm-text-muted, #64748b)' }}>\n 기타\n </span>\n </button>\n {otherSelected[currentQuestion.id] && (\n <div style={{ padding: '8px 0 4px 32px' }}>\n <input\n type=\"text\"\n value={otherTexts[currentQuestion.id] || ''}\n onChange={(e) => setOtherTexts((prev) => ({ ...prev, [currentQuestion.id]: e.target.value }))}\n placeholder=\"직접 입력...\"\n style={{\n width: '100%',\n padding: '10px 12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '6px',\n color: 'var(--chatllm-text, #1e293b)',\n fontSize: '13px',\n outline: 'none',\n }}\n autoFocus\n />\n </div>\n )}\n </>\n );\n })()}\n </div>\n\n {/* Footer */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderTop: '1px solid var(--chatllm-border, #e5e7eb)',\n }}\n >\n <span style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #94a3b8)' }}>\n {questions.length > 1\n ? `${activeTab + 1} / ${questions.length}`\n : `${totalSelected}개 선택됨`}\n </span>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <button\n onClick={handleSkip}\n style={{\n padding: '8px 16px',\n backgroundColor: 'transparent',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '6px',\n color: 'var(--chatllm-text-secondary, #64748b)',\n fontSize: '13px',\n fontWeight: 500,\n cursor: 'pointer',\n }}\n >\n 자동생성\n </button>\n <button\n onClick={handleNext}\n disabled={!currentHasSelection}\n style={{\n padding: '8px 20px',\n backgroundColor: currentHasSelection\n ? 'var(--chatllm-primary, #4A90E2)'\n : 'var(--chatllm-bg-disabled, #e5e7eb)',\n border: 'none',\n borderRadius: '6px',\n color: currentHasSelection ? '#fff' : 'var(--chatllm-text-muted, #94a3b8)',\n fontSize: '13px',\n fontWeight: 600,\n cursor: currentHasSelection ? 'pointer' : 'not-allowed',\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n }}\n >\n {isLastTab ? '제출' : '다음'}\n <IconSvg\n name=\"arrow-right-line\"\n size={16}\n color={currentHasSelection ? '#fff' : 'var(--chatllm-text-muted)'}\n />\n </button>\n </div>\n </div>\n </div>\n );\n};\n\nexport default PollCard;\n","/**\n * @description 스킬 실행 진행 상태 UI 컴포넌트\n * @Todo vibecode - 범용 스킬 실행 상태 표시\n */\n\nimport React from 'react';\nimport { IconSvg } from './Icon';\nimport type { IconName } from './Icon';\nimport type { SkillExecution } from '../types';\n\nexport interface SkillProgressUIProps {\n /** 스킬 실행 상태 */\n execution: SkillExecution;\n /** UI 표시용 레이블 */\n skillLabel?: string;\n /** 아이콘 이름 */\n skillIcon?: string;\n}\n\n/**\n * @description 스킬 아이콘 매핑\n */\nconst mapIcon = (icon?: string): IconName => {\n const iconMap: Record<string, IconName> = {\n search: 'search-eye-line',\n image: 'image-line',\n code: 'code-s-slash-line',\n file: 'file-text-line',\n document: 'file-text-line',\n };\n return icon ? iconMap[icon] || 'sparkling-line' : 'sparkling-line';\n};\n\nexport const SkillProgressUI: React.FC<SkillProgressUIProps> = ({\n execution,\n skillLabel,\n skillIcon,\n}) => {\n const label = skillLabel || execution.skillName;\n const isExecuting = execution.status === 'executing';\n const isDone = execution.status === 'done';\n const isError = execution.status === 'error';\n\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '12px 16px',\n marginTop: '8px',\n backgroundColor: isError\n ? 'rgba(239, 68, 68, 0.08)'\n : 'var(--chatllm-primary-light)',\n borderRadius: '12px',\n border: `1px solid ${isError ? 'rgba(239, 68, 68, 0.2)' : 'rgba(74, 144, 226, 0.15)'}`,\n }}\n >\n {/* 상태 아이콘 */}\n {isExecuting && (\n <div\n style={{\n width: 16,\n height: 16,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <div\n style={{\n width: 12,\n height: 12,\n borderRadius: '50%',\n border: '2px solid var(--chatllm-primary)',\n borderTopColor: 'transparent',\n animation: 'chatllm-spin 1s linear infinite',\n }}\n />\n </div>\n )}\n {isDone && <IconSvg name=\"check-line\" size={16} color=\"var(--chatllm-success)\" />}\n {isError && <IconSvg name=\"close-line\" size={16} color=\"var(--chatllm-error)\" />}\n\n {/* 스킬 아이콘 */}\n <IconSvg\n name={mapIcon(skillIcon)}\n size={16}\n color={isError ? 'var(--chatllm-error)' : 'var(--chatllm-primary)'}\n />\n\n {/* 상태 텍스트 */}\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: isError ? 'var(--chatllm-error)' : 'var(--chatllm-text-secondary)',\n }}\n >\n {isExecuting && `${label} 실행 중...`}\n {isDone && `${label} 완료`}\n {isError && `${label} 오류: ${execution.error || '알 수 없는 오류'}`}\n </span>\n\n {/* 진행 상태 (있는 경우) */}\n {execution.progress && isExecuting && (\n <span\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted)',\n marginLeft: 'auto',\n }}\n >\n {execution.progress.phaseLabel}\n {execution.progress.percentage != null && ` (${execution.progress.percentage}%)`}\n </span>\n )}\n </div>\n );\n};\n\nexport default SkillProgressUI;\n","/**\n * @description 이미지 콘텐츠 카드 컴포넌트\n * @Todo vibecode - 멀티 콘텐츠 메시지에서 이미지 인라인 표시\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\nimport type { ImageContentPart } from '../types';\n\nexport interface ImageContentCardProps {\n /** 이미지 콘텐츠 파트 */\n part: ImageContentPart;\n}\n\n/**\n * @description 이미지 카드 렌더러 (확대 모달 + 다운로드)\n * @Todo vibecode - 인라인 이미지 표시, 클릭 시 확대\n */\nexport const ImageContentCard: React.FC<ImageContentCardProps> = ({ part }) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const [isLoaded, setIsLoaded] = useState(false);\n const [hasError, setHasError] = useState(false);\n\n if (hasError) {\n return (\n <div\n style={{\n padding: '16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '8px',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n color: 'var(--chatllm-text-muted, #64748b)',\n fontSize: '13px',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n }}\n >\n <IconSvg name=\"error-warning-line\" size={16} color=\"var(--chatllm-error, #ef4444)\" />\n 이미지를 불러올 수 없습니다\n </div>\n );\n }\n\n return (\n <>\n <div\n style={{\n position: 'relative',\n borderRadius: '8px',\n overflow: 'hidden',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n cursor: 'pointer',\n maxWidth: part.width ? `${Math.min(part.width, 480)}px` : '480px',\n }}\n onClick={() => setIsExpanded(true)}\n >\n {!isLoaded && (\n <div\n style={{\n padding: '40px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'var(--chatllm-bg-secondary, #f1f5f9)',\n }}\n >\n <IconSvg name=\"loader-4-line\" size={24} color=\"var(--chatllm-text-muted, #94a3b8)\" />\n </div>\n )}\n <img\n src={part.url}\n alt={part.alt || ''}\n onLoad={() => setIsLoaded(true)}\n onError={() => setHasError(true)}\n style={{\n display: isLoaded ? 'block' : 'none',\n width: '100%',\n height: 'auto',\n maxHeight: '400px',\n objectFit: 'contain',\n }}\n />\n {part.alt && isLoaded && (\n <div\n style={{\n padding: '6px 10px',\n fontSize: '12px',\n color: 'var(--chatllm-text-muted, #64748b)',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderTop: '1px solid var(--chatllm-border, #e5e7eb)',\n }}\n >\n {part.alt}\n </div>\n )}\n </div>\n\n {/* @Todo vibecode - 이미지 확대 모달 */}\n {isExpanded && (\n <div\n onClick={() => setIsExpanded(false)}\n style={{\n position: 'fixed',\n inset: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.8)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 9999,\n cursor: 'zoom-out',\n }}\n >\n <img\n src={part.url}\n alt={part.alt || ''}\n style={{\n maxWidth: '90vw',\n maxHeight: '90vh',\n objectFit: 'contain',\n borderRadius: '4px',\n }}\n />\n </div>\n )}\n </>\n );\n};\n\nexport default ImageContentCard;\n","/**\n * @description 파일 콘텐츠 카드 컴포넌트\n * @Todo vibecode - 멀티 콘텐츠 메시지에서 파일 첨부 표시\n */\n\nimport React from 'react';\nimport { IconSvg } from './Icon';\nimport type { IconName } from './Icon';\nimport type { FileContentPart } from '../types';\n\nexport interface FileContentCardProps {\n /** 파일 콘텐츠 파트 */\n part: FileContentPart;\n}\n\n/**\n * @description 파일 사이즈 포맷팅\n * @Todo vibecode - bytes → KB/MB 변환\n */\nconst formatFileSize = (bytes?: number): string => {\n if (!bytes) return '';\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n};\n\n/**\n * @description MIME 타입에 따른 아이콘 선택\n * @Todo vibecode - 파일 유형별 아이콘 분기\n */\nconst getFileIcon = (mimeType?: string): IconName => {\n if (!mimeType) return 'file-text-line';\n if (mimeType.startsWith('image/')) return 'image-line';\n if (mimeType.startsWith('video/')) return 'video-line';\n if (mimeType.startsWith('audio/')) return 'mic-line';\n if (mimeType.includes('pdf')) return 'file-text-line';\n if (mimeType.includes('zip') || mimeType.includes('compressed')) return 'folder-line';\n return 'file-text-line';\n};\n\n/**\n * @description 파일 카드 렌더러 (파일명 + 아이콘 + 다운로드)\n * @Todo vibecode - 파일 첨부 인라인 표시\n */\nexport const FileContentCard: React.FC<FileContentCardProps> = ({ part }) => {\n return (\n <a\n href={part.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n download={part.name}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px 16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '8px',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n textDecoration: 'none',\n color: 'inherit',\n transition: 'background-color 0.15s ease',\n maxWidth: '320px',\n }}\n >\n <div\n style={{\n width: '36px',\n height: '36px',\n borderRadius: '8px',\n backgroundColor: 'var(--chatllm-primary-light, rgba(74, 144, 226, 0.1))',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n >\n <IconSvg name={getFileIcon(part.mimeType)} size={18} color=\"var(--chatllm-primary, #4A90E2)\" />\n </div>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-text, #1e293b)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {part.name}\n </div>\n {(part.size || part.mimeType) && (\n <div\n style={{\n fontSize: '11px',\n color: 'var(--chatllm-text-muted, #94a3b8)',\n marginTop: '2px',\n }}\n >\n {[formatFileSize(part.size), part.mimeType].filter(Boolean).join(' · ')}\n </div>\n )}\n </div>\n <IconSvg name=\"download-line\" size={16} color=\"var(--chatllm-text-muted, #94a3b8)\" />\n </a>\n );\n};\n\nexport default FileContentCard;\n","/**\n * @description 도구 실행 상태 카드 컴포넌트\n * @Todo vibecode - 로딩/완료/에러 상태 표시 + 접이식 소스 목록\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\nimport { LinkChip } from './LinkChip';\nimport type { IconName } from './Icon';\nimport type { SourceItem } from '../types';\n\nexport interface ToolStatusCardProps {\n /** 도구 이름 (fallback 레이블용) */\n toolName: string;\n /** UI 표시용 레이블 (예: '웹 검색', '이미지 생성') */\n label?: string;\n /** 아이콘 키 (예: 'search', 'image') */\n icon?: string;\n /** 현재 상태 */\n status: 'loading' | 'done' | 'error';\n /** 출처 목록 (done 상태에서 접이식 표시) */\n sources?: SourceItem[];\n /** 에러 메시지 (error 상태) */\n errorMessage?: string;\n}\n\n/** @Todo vibecode - 도구 아이콘 매핑 */\nconst mapIcon = (icon?: string): IconName => {\n const iconMap: Record<string, IconName> = {\n search: 'search-eye-line',\n image: 'image-line',\n code: 'code-s-slash-line',\n file: 'file-text-line',\n document: 'file-text-line',\n };\n return icon ? iconMap[icon] || 'sparkling-line' : 'sparkling-line';\n};\n\n/** @Todo vibecode - 도구 이름 → 한국어 레이블 매핑 */\nconst getDefaultLabel = (toolName: string): string => {\n const labelMap: Record<string, string> = {\n web_search: '웹 검색',\n generate_image: '이미지 생성',\n search: '검색',\n };\n return labelMap[toolName] || toolName;\n};\n\n/** @Todo vibecode - 상태별 동사 접미사 */\nconst getStatusSuffix = (label: string, status: 'loading' | 'done' | 'error'): string => {\n if (status === 'loading') return `${label} 중...`;\n if (status === 'done') return `${label}됨`;\n return `${label} 오류`;\n};\n\nexport const ToolStatusCard: React.FC<ToolStatusCardProps> = ({\n toolName,\n label,\n icon,\n status,\n sources,\n errorMessage,\n}) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const displayLabel = label || getDefaultLabel(toolName);\n const statusText = getStatusSuffix(displayLabel, status);\n const hasSources = sources && sources.length > 0;\n const isClickable = status === 'done' && hasSources;\n const isError = status === 'error';\n const isLoading = status === 'loading';\n\n return (\n <div style={{ marginBottom: '4px' }}>\n {/* 상태 헤더 */}\n <div\n onClick={isClickable ? () => setIsExpanded(!isExpanded) : undefined}\n role={isClickable ? 'button' : undefined}\n tabIndex={isClickable ? 0 : undefined}\n onKeyDown={isClickable ? (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setIsExpanded(!isExpanded);\n }\n } : undefined}\n aria-expanded={isClickable ? isExpanded : undefined}\n aria-label={isClickable ? `${statusText} - ${sources!.length}개 소스` : statusText}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '8px',\n padding: '6px 12px',\n backgroundColor: isError\n ? 'var(--chatllm-error-bg, #fef2f2)'\n : 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '20px',\n border: `1px solid ${isError ? 'var(--chatllm-error-border, #fecaca)' : 'var(--chatllm-border-light, #e2e8f0)'}`,\n cursor: isClickable ? 'pointer' : 'default',\n transition: 'background-color 0.15s',\n userSelect: 'none',\n }}\n >\n {/* 상태 아이콘 */}\n {isLoading && (\n <div\n style={{\n width: 14,\n height: 14,\n borderRadius: '50%',\n border: '2px solid var(--chatllm-primary, #4A90E2)',\n borderTopColor: 'transparent',\n animation: 'chatllm-spin 1s linear infinite',\n flexShrink: 0,\n }}\n />\n )}\n {status === 'done' && (\n <IconSvg name=\"check-line\" size={14} color=\"var(--chatllm-success, #22c55e)\" />\n )}\n {isError && (\n <IconSvg name=\"error-warning-line\" size={14} color=\"var(--chatllm-error, #ef4444)\" />\n )}\n\n {/* 도구 아이콘 */}\n <IconSvg\n name={mapIcon(icon)}\n size={14}\n color={isError ? 'var(--chatllm-error, #ef4444)' : 'var(--chatllm-text-muted, #64748b)'}\n />\n\n {/* 상태 텍스트 */}\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: isError\n ? 'var(--chatllm-error, #ef4444)'\n : 'var(--chatllm-text-secondary, #475569)',\n }}\n >\n {isError && errorMessage ? `${statusText}: ${errorMessage}` : statusText}\n </span>\n\n {/* 소스 개수 + 펼침 화살표 */}\n {isClickable && (\n <>\n <span\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted, #94a3b8)',\n fontWeight: 400,\n }}\n >\n · {sources!.length}개 소스\n </span>\n <span\n style={{\n fontSize: '10px',\n color: 'var(--chatllm-text-muted, #94a3b8)',\n transition: 'transform 0.2s',\n transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',\n }}\n >\n ▼\n </span>\n </>\n )}\n </div>\n\n {/* 접이식 소스 목록 */}\n {isExpanded && hasSources && (\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '6px',\n marginTop: '8px',\n padding: '10px 12px',\n backgroundColor: 'var(--chatllm-source-bg, #f8fafc)',\n borderRadius: '8px',\n border: '1px solid var(--chatllm-border-light, #e2e8f0)',\n }}\n >\n {sources!.map((source, si) => (\n <LinkChip\n key={si}\n text={source.title}\n url={source.url}\n index={si}\n showFavicon\n />\n ))}\n </div>\n )}\n </div>\n );\n};\n\nexport default ToolStatusCard;\n","/**\n * @description 멀티 콘텐츠 파트 렌더러\n * @Todo vibecode - contentParts 배열을 순서대로 렌더링\n */\n\nimport React from 'react';\nimport { MarkdownRenderer } from './MarkdownRenderer';\nimport type { ChoiceOption } from './MarkdownRenderer';\nimport { ImageContentCard } from './ImageContentCard';\nimport { FileContentCard } from './FileContentCard';\nimport { LinkChip } from './LinkChip';\nimport { ToolStatusCard } from './ToolStatusCard';\nimport { IconSvg } from './Icon';\nimport type { MessageContentPart, SourceItem } from '../types';\n\nexport interface ContentPartRendererProps {\n /** 콘텐츠 파트 배열 */\n parts: MessageContentPart[];\n /** 선택지 클릭 핸들러 */\n onChoiceClick?: (choice: ChoiceOption) => void;\n /** Thinking 블록 표시 여부 */\n showThinking?: boolean;\n /** Thinking 블록 기본 펼침 상태 */\n thinkingDefaultOpen?: boolean;\n}\n\n/**\n * @description contentParts 배열을 타입별로 렌더링\n * @Todo vibecode - text, image, file, search_result, tool_loading, tool_result, error 지원\n * tool_result → ToolStatusCard 기반 구조화 렌더링\n */\nexport const ContentPartRenderer: React.FC<ContentPartRendererProps> = ({\n parts,\n onChoiceClick,\n showThinking,\n thinkingDefaultOpen,\n}) => {\n /**\n * @Todo vibecode - tool_result/search_result에서 sources 수집\n * 후속 text 파트에 인라인 소스 참조용으로 전달\n */\n const collectedSources: SourceItem[] = [];\n for (const part of parts) {\n if (part.type === 'tool_result' && part.result.sources) {\n collectedSources.push(...part.result.sources);\n } else if (part.type === 'search_result') {\n collectedSources.push(...part.results);\n }\n }\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {parts.map((part, idx) => {\n switch (part.type) {\n case 'text':\n return (\n <MarkdownRenderer\n key={idx}\n content={part.content}\n onChoiceClick={onChoiceClick}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n sources={collectedSources.length > 0 ? collectedSources : undefined}\n />\n );\n\n case 'image':\n return <ImageContentCard key={idx} part={part} />;\n\n case 'file':\n return <FileContentCard key={idx} part={part} />;\n\n case 'search_result':\n return (\n <div key={idx} style={{ display: 'flex', flexWrap: 'wrap', gap: '6px' }}>\n {part.results.map((source, si) => (\n <LinkChip\n key={si}\n text={source.title}\n url={source.url}\n index={si + 1}\n showFavicon\n />\n ))}\n </div>\n );\n\n case 'tool_loading':\n return (\n <ToolStatusCard\n key={idx}\n toolName={part.toolName}\n label={part.label}\n status=\"loading\"\n />\n );\n\n case 'tool_result': {\n const { result } = part;\n return (\n <div key={idx} style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\n {/* 도구 상태 카드 (완료/에러 + 접이식 소스) */}\n <ToolStatusCard\n toolName={part.toolName}\n label={part.label}\n icon={part.icon}\n status={result.type === 'error' ? 'error' : 'done'}\n sources={result.sources}\n errorMessage={result.type === 'error' ? result.content : undefined}\n />\n {/* 실제 결과 콘텐츠 */}\n {result.type === 'image' && (\n <ImageContentCard\n part={{ type: 'image', url: result.content, alt: result.metadata?.alt }}\n />\n )}\n {result.type === 'file' && (\n <FileContentCard\n part={{\n type: 'file',\n name: result.metadata?.fileName || 'file',\n url: result.content,\n mimeType: result.metadata?.mimeType,\n }}\n />\n )}\n </div>\n );\n }\n\n case 'error':\n return (\n <div\n key={idx}\n style={{\n padding: '10px 14px',\n backgroundColor: 'var(--chatllm-error-bg, #fef2f2)',\n borderRadius: '8px',\n border: '1px solid var(--chatllm-error-border, #fecaca)',\n fontSize: '13px',\n color: 'var(--chatllm-error, #ef4444)',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n }}\n >\n <IconSvg name=\"error-warning-line\" size={16} color=\"var(--chatllm-error, #ef4444)\" />\n {part.message}\n </div>\n );\n\n default:\n return null;\n }\n })}\n </div>\n );\n};\n\nexport default ContentPartRenderer;\n","/**\n * @description 빈 상태 컴포넌트 - Modern Canvas 디자인\n * @Todo vibecode - v0.11.0 새 디자인 시스템 적용 (Landing 화면)\n */\n\nimport React from 'react';\nimport { IconSvg, IconName } from './Icon';\nimport type { EmptyStateProps, ActionItem } from '../types';\n\nexport const EmptyState: React.FC<EmptyStateProps> = ({\n greeting,\n templates = [],\n onTemplateClick,\n actions = [],\n onActionSelect,\n}) => {\n const getActionIcon = (icon: string): IconName => {\n const iconMap: Record<string, IconName> = {\n search: 'search-line',\n image: 'image-line',\n code: 'code-s-slash-line',\n document: 'file-text-line',\n };\n return iconMap[icon] || 'sparkling-line';\n };\n\n const hasContent = actions.length > 0 || templates.length > 0;\n\n return (\n <div\n className=\"chatllm-empty-state\"\n style={{\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: hasContent ? 'center' : 'flex-end',\n padding: '48px 24px',\n paddingBottom: hasContent ? '200px' : '32px',\n textAlign: 'center',\n }}\n >\n {/* Logo */}\n <div\n className=\"chatllm-sheet\"\n style={{\n width: '64px',\n height: '64px',\n borderRadius: '16px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginBottom: '32px',\n color: 'var(--chatllm-primary)',\n }}\n >\n <IconSvg name=\"chat-1-line\" size={40} />\n </div>\n\n {/* Greeting */}\n <h1\n style={{\n fontSize: '30px',\n fontWeight: 700,\n color: 'var(--chatllm-text)',\n marginBottom: hasContent ? '40px' : '0',\n lineHeight: 1.3,\n }}\n >\n How can I help you today?\n </h1>\n\n {/* Quick Action Buttons (Pills) */}\n {(actions.length > 0 || templates.length > 0) && (\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n justifyContent: 'center',\n gap: '12px',\n maxWidth: '800px',\n marginBottom: '48px',\n }}\n >\n {/* Actions as pills */}\n {actions.map((action) => (\n <button\n key={action.id}\n onClick={() => onActionSelect?.(action)}\n className=\"chatllm-btn-secondary\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '12px 20px',\n fontSize: '14px',\n fontWeight: 500,\n }}\n >\n <IconSvg\n name={getActionIcon(action.icon)}\n size={18}\n color=\"var(--chatllm-primary)\"\n />\n {action.label}\n </button>\n ))}\n\n {/* Templates as pills */}\n {templates.slice(0, 4).map((template) => (\n <button\n key={template.id}\n onClick={() => onTemplateClick(template)}\n className=\"chatllm-btn-secondary\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '12px 20px',\n fontSize: '14px',\n fontWeight: 500,\n }}\n >\n <IconSvg\n name=\"sparkling-line\"\n size={18}\n color=\"var(--chatllm-primary)\"\n />\n {template.title}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n};\n\nexport default EmptyState;\n","/**\n * @description 설정 모달 컴포넌트\n * 일반/개인화/데이터 설정 탭 포함\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\nimport type { PersonalizationConfig, SettingsTab } from '../types';\nimport type { MemoryItem } from './MemoryPanel';\n\nexport interface SettingsModalProps {\n /** 모달 열림 상태 */\n isOpen: boolean;\n /** 모달 닫기 핸들러 */\n onClose: () => void;\n /** 개인화 설정 */\n personalization: PersonalizationConfig;\n /** 개인화 설정 변경 핸들러 */\n onPersonalizationChange: (config: PersonalizationConfig) => void;\n /** API 키 */\n apiKey?: string;\n /** API 키 변경 핸들러 */\n onApiKeyChange?: (key: string) => void;\n /** 전체 데이터 삭제 핸들러 */\n onClearAllData?: () => void;\n /** API 키 레이블 */\n apiKeyLabel?: string;\n /** API 키 설명 */\n apiKeyDescription?: string;\n /** @description 메모리 아이템 목록 @Todo vibecode */\n memoryItems?: MemoryItem[];\n /** @description 컨텍스트 요약 (압축된 대화) @Todo vibecode */\n contextSummary?: string;\n /** @description 메모리 항목 삭제 핸들러 @Todo vibecode */\n onDeleteMemory?: (key: string) => void;\n /** @description 메모리 전체 삭제 핸들러 @Todo vibecode */\n onClearMemory?: () => void;\n /** @Todo vibecode - 개인화 설정 저장 핸들러 (저장 버튼 클릭 시) */\n onSave?: () => void;\n /** @description 프로젝트 메모리 아이템 목록 @Todo vibecode */\n projectMemoryItems?: MemoryItem[];\n /** @description 프로젝트 메모리 항목 삭제 핸들러 @Todo vibecode */\n onDeleteProjectMemory?: (key: string) => void;\n /** @description 프로젝트 메모리 전체 삭제 핸들러 @Todo vibecode */\n onClearProjectMemory?: () => void;\n /** @description 프로젝트 기능 활성화 여부 @Todo vibecode */\n enableProjects?: boolean;\n /** @description 현재 프로젝트 이름 @Todo vibecode */\n currentProjectTitle?: string;\n /** @description 메모리 탭 표시 여부 (기본: true) @Todo vibecode */\n showMemoryTab?: boolean;\n}\n\nconst DEFAULT_PERSONALIZATION: PersonalizationConfig = {\n responseStyle: {\n warmth: 'medium',\n enthusiasm: 'medium',\n emojiUsage: 'low',\n formatting: 'default',\n verbosity: 'balanced',\n },\n userProfile: {},\n useMemory: true,\n language: 'auto',\n};\n\nexport const SettingsModal: React.FC<SettingsModalProps> = ({\n isOpen,\n onClose,\n personalization,\n onPersonalizationChange,\n apiKey = '',\n onApiKeyChange,\n onClearAllData,\n apiKeyLabel = 'API Key',\n apiKeyDescription = 'Cloud 모델 사용에 필요합니다',\n memoryItems = [],\n contextSummary,\n onDeleteMemory,\n onClearMemory,\n onSave,\n projectMemoryItems = [],\n onDeleteProjectMemory,\n onClearProjectMemory,\n enableProjects = false,\n currentProjectTitle,\n showMemoryTab = true,\n}) => {\n const [activeTab, setActiveTab] = useState<SettingsTab>('general');\n const [localApiKey, setLocalApiKey] = useState(apiKey);\n\n if (!isOpen) return null;\n\n const updateResponseStyle = (key: string, value: string) => {\n onPersonalizationChange({\n ...personalization,\n responseStyle: {\n ...personalization.responseStyle,\n [key]: value,\n },\n });\n };\n\n const updateUserProfile = (key: string, value: string) => {\n onPersonalizationChange({\n ...personalization,\n userProfile: {\n ...personalization.userProfile,\n [key]: value,\n },\n });\n };\n\n const handleApiKeyChange = (value: string) => {\n setLocalApiKey(value);\n onApiKeyChange?.(value);\n };\n\n return (\n <div\n className=\"chatllm-settings-overlay\"\n style={{\n position: 'fixed',\n inset: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.3)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 1000,\n }}\n onClick={onClose}\n >\n <div\n className=\"chatllm-settings-modal\"\n style={{\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n borderRadius: '16px',\n width: '100%',\n maxWidth: '800px',\n height: '80vh',\n maxHeight: '600px',\n margin: '16px',\n boxShadow: '0 20px 60px rgba(0, 0, 0, 0.15)',\n display: 'flex',\n overflow: 'hidden',\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Sidebar */}\n <div\n style={{\n width: '200px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRight: '1px solid var(--chatllm-border, #e5e7eb)',\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n {/* Close Button */}\n <div style={{ padding: '16px', borderBottom: '1px solid var(--chatllm-border, #e5e7eb)' }}>\n <button\n onClick={onClose}\n style={{\n padding: '8px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg name=\"close-line\" size={20} color=\"var(--chatllm-text-muted, #6b7280)\" />\n </button>\n </div>\n\n {/* Tabs */}\n <nav style={{ flex: 1, padding: '8px' }}>\n <TabButton\n active={activeTab === 'general'}\n onClick={() => setActiveTab('general')}\n icon=\"settings-3-line\"\n label=\"일반\"\n />\n <TabButton\n active={activeTab === 'personalization'}\n onClick={() => setActiveTab('personalization')}\n icon=\"user-3-line\"\n label=\"개인 맞춤 설정\"\n />\n {/** @Todo vibecode - showMemoryTab으로 메모리 탭 노출 제어 */}\n {showMemoryTab && (\n <TabButton\n active={activeTab === 'memory'}\n onClick={() => setActiveTab('memory')}\n icon=\"robot-line\"\n label=\"AI 메모리\"\n />\n )}\n {showMemoryTab && enableProjects && (\n <TabButton\n active={activeTab === 'project-memory'}\n onClick={() => setActiveTab('project-memory')}\n icon=\"folder-line\"\n label=\"프로젝트 메모리\"\n />\n )}\n <TabButton\n active={activeTab === 'data'}\n onClick={() => setActiveTab('data')}\n icon=\"delete-bin-line\"\n label=\"데이터 제어\"\n />\n </nav>\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, overflow: 'auto', padding: '24px' }}>\n {activeTab === 'general' && (\n <div>\n <h2 style={{ fontSize: '20px', fontWeight: 600, marginBottom: '24px', color: 'var(--chatllm-text, #1f2937)' }}>\n 일반\n </h2>\n\n {/* Language */}\n <SettingRow label=\"언어\">\n <select\n value={personalization.language}\n onChange={(e) => onPersonalizationChange({ ...personalization, language: e.target.value })}\n style={selectStyle}\n >\n <option value=\"auto\">자동 탐지</option>\n <option value=\"ko\">한국어</option>\n <option value=\"en\">English</option>\n <option value=\"ja\">日本語</option>\n </select>\n </SettingRow>\n\n {/* Reset */}\n <SettingRow label=\"기본값으로 초기화\" description=\"모든 설정을 초기 상태로 되돌립니다\">\n <button\n onClick={() => onPersonalizationChange(DEFAULT_PERSONALIZATION)}\n style={buttonSecondaryStyle}\n >\n 초기화\n </button>\n </SettingRow>\n\n {/* API Key */}\n {onApiKeyChange && (\n <div style={{ marginTop: '32px', paddingTop: '24px', borderTop: '1px solid var(--chatllm-border, #e5e7eb)' }}>\n <h3 style={{ fontSize: '16px', fontWeight: 500, marginBottom: '16px', color: 'var(--chatllm-text, #1f2937)' }}>\n API 설정\n </h3>\n <div>\n <label style={{ display: 'block', fontSize: '14px', marginBottom: '8px', color: 'var(--chatllm-text, #374151)' }}>\n {apiKeyLabel}\n </label>\n <input\n type=\"password\"\n value={localApiKey}\n onChange={(e) => handleApiKeyChange(e.target.value)}\n placeholder=\"API 키를 입력하세요\"\n style={inputStyle}\n />\n <p style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #9ca3af)', marginTop: '4px' }}>\n {apiKeyDescription}\n </p>\n </div>\n </div>\n )}\n </div>\n )}\n\n {activeTab === 'personalization' && (\n <div>\n <h2 style={{ fontSize: '20px', fontWeight: 600, marginBottom: '24px', color: 'var(--chatllm-text, #1f2937)' }}>\n 개인 맞춤 설정\n </h2>\n\n {/* User Profile */}\n <section style={{ marginBottom: '32px' }}>\n <h3 style={{ fontSize: '14px', fontWeight: 500, color: 'var(--chatllm-text-muted, #6b7280)', marginBottom: '16px' }}>\n 사용자 프로필\n </h3>\n <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>\n <div>\n <label style={labelStyle}>닉네임</label>\n <input\n type=\"text\"\n value={personalization.userProfile.nickname || ''}\n onChange={(e) => updateUserProfile('nickname', e.target.value)}\n placeholder=\"어떻게 불러드릴까요?\"\n style={inputStyle}\n />\n </div>\n <div>\n <label style={labelStyle}>직업</label>\n <input\n type=\"text\"\n value={personalization.userProfile.occupation || ''}\n onChange={(e) => updateUserProfile('occupation', e.target.value)}\n placeholder=\"예: 소프트웨어 개발자\"\n style={inputStyle}\n />\n </div>\n <div>\n <label style={labelStyle}>추가 정보</label>\n <textarea\n value={personalization.userProfile.additionalInfo || ''}\n onChange={(e) => updateUserProfile('additionalInfo', e.target.value)}\n placeholder=\"관심사, 선호 사항 등\"\n rows={3}\n style={{ ...inputStyle, resize: 'none' }}\n />\n </div>\n </div>\n </section>\n\n {/* Response Style */}\n <section>\n <h3 style={{ fontSize: '14px', fontWeight: 500, color: 'var(--chatllm-text-muted, #6b7280)', marginBottom: '16px' }}>\n 응답 스타일\n </h3>\n\n <SettingRow label=\"따뜻함\">\n <select\n value={personalization.responseStyle.warmth}\n onChange={(e) => updateResponseStyle('warmth', e.target.value)}\n style={selectStyle}\n >\n <option value=\"high\">높음 - 친근하고 따뜻하게</option>\n <option value=\"medium\">기본값</option>\n <option value=\"low\">낮음 - 간결하고 사무적으로</option>\n </select>\n </SettingRow>\n\n <SettingRow label=\"열정적\">\n <select\n value={personalization.responseStyle.enthusiasm}\n onChange={(e) => updateResponseStyle('enthusiasm', e.target.value)}\n style={selectStyle}\n >\n <option value=\"high\">높음 - 적극적이고 활발하게</option>\n <option value=\"medium\">기본값</option>\n <option value=\"low\">낮음 - 차분하고 절제있게</option>\n </select>\n </SettingRow>\n\n <SettingRow label=\"이모지 사용\">\n <select\n value={personalization.responseStyle.emojiUsage}\n onChange={(e) => updateResponseStyle('emojiUsage', e.target.value)}\n style={selectStyle}\n >\n <option value=\"high\">높음 - 자주 사용</option>\n <option value=\"medium\">기본값</option>\n <option value=\"low\">낮음 - 거의 사용 안 함</option>\n </select>\n </SettingRow>\n\n <SettingRow label=\"응답 길이\">\n <select\n value={personalization.responseStyle.verbosity}\n onChange={(e) => updateResponseStyle('verbosity', e.target.value)}\n style={selectStyle}\n >\n <option value=\"detailed\">상세 - 자세하게 설명</option>\n <option value=\"balanced\">기본값</option>\n <option value=\"concise\">간결 - 핵심만 요약</option>\n </select>\n </SettingRow>\n </section>\n\n {/* @Todo vibecode - 개인화 설정 저장 버튼 */}\n {onSave && (\n <div style={{ marginTop: '24px', display: 'flex', justifyContent: 'flex-end' }}>\n <button\n onClick={onSave}\n style={{\n padding: '10px 24px',\n backgroundColor: 'var(--chatllm-primary, #4A90E2)',\n color: '#fff',\n border: 'none',\n borderRadius: '8px',\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n transition: 'opacity 0.15s ease',\n }}\n onMouseEnter={(e) => (e.currentTarget.style.opacity = '0.85')}\n onMouseLeave={(e) => (e.currentTarget.style.opacity = '1')}\n >\n 저장\n </button>\n </div>\n )}\n </div>\n )}\n\n {activeTab === 'memory' && showMemoryTab && (\n <MemoryTabContent\n items={memoryItems}\n contextSummary={contextSummary}\n onDelete={onDeleteMemory}\n onClearAll={onClearMemory}\n />\n )}\n\n {activeTab === 'project-memory' && showMemoryTab && enableProjects && (\n <MemoryTabContent\n items={projectMemoryItems}\n onDelete={onDeleteProjectMemory}\n onClearAll={onClearProjectMemory}\n title={currentProjectTitle ? `${currentProjectTitle} 메모리` : '프로젝트 메모리'}\n emptyMessage=\"프로젝트에 저장된 메모리가 없습니다\"\n emptyDescription=\"대화가 진행되면 AI가 프로젝트 맥락을 자동으로 학습합니다\"\n />\n )}\n\n {activeTab === 'data' && (\n <div>\n <h2 style={{ fontSize: '20px', fontWeight: 600, marginBottom: '24px', color: 'var(--chatllm-text, #1f2937)' }}>\n 데이터 제어\n </h2>\n\n {/* Memory Toggle */}\n <SettingRow label=\"메모리 사용\" description=\"대화 컨텍스트를 기억합니다\">\n <button\n onClick={() => onPersonalizationChange({ ...personalization, useMemory: !personalization.useMemory })}\n style={{\n width: '48px',\n height: '28px',\n borderRadius: '14px',\n backgroundColor: personalization.useMemory\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-text-muted, #d1d5db)',\n border: 'none',\n cursor: 'pointer',\n position: 'relative',\n transition: 'background-color 0.2s',\n }}\n >\n <div\n style={{\n width: '22px',\n height: '22px',\n borderRadius: '50%',\n backgroundColor: '#ffffff',\n boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',\n position: 'absolute',\n top: '3px',\n left: personalization.useMemory ? '23px' : '3px',\n transition: 'left 0.2s',\n }}\n />\n </button>\n </SettingRow>\n\n {/* Clear All Data */}\n {onClearAllData && (\n <SettingRow label=\"대화 기록 삭제\" description=\"모든 대화 기록을 삭제합니다\">\n <button\n onClick={() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n if (typeof window !== 'undefined' && window.confirm('모든 대화 기록을 삭제하시겠습니까?')) {\n onClearAllData();\n }\n }}\n style={buttonDangerStyle}\n >\n 삭제\n </button>\n </SettingRow>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n\n// Tab Button Component\nconst TabButton: React.FC<{\n active: boolean;\n onClick: () => void;\n icon: string;\n label: string;\n}> = ({ active, onClick, icon, label }) => (\n <button\n onClick={onClick}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '10px 12px',\n borderRadius: '10px',\n border: 'none',\n backgroundColor: active ? 'var(--chatllm-bg, #ffffff)' : 'transparent',\n boxShadow: active ? '0 1px 3px rgba(0, 0, 0, 0.08)' : 'none',\n color: active ? 'var(--chatllm-primary, #3b82f6)' : 'var(--chatllm-text-muted, #6b7280)',\n fontSize: '14px',\n cursor: 'pointer',\n textAlign: 'left',\n marginBottom: '4px',\n }}\n >\n <IconSvg name={icon as any} size={20} />\n {label}\n </button>\n);\n\n// Setting Row Component\nconst SettingRow: React.FC<{\n label: string;\n description?: string;\n children: React.ReactNode;\n}> = ({ label, description, children }) => (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 0',\n borderBottom: '1px solid var(--chatllm-border-light, #f3f4f6)',\n }}\n >\n <div>\n <span style={{ fontSize: '14px', color: 'var(--chatllm-text, #374151)' }}>{label}</span>\n {description && (\n <p style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #9ca3af)', marginTop: '2px' }}>\n {description}\n </p>\n )}\n </div>\n {children}\n </div>\n);\n\n// Styles\nconst selectStyle: React.CSSProperties = {\n padding: '8px 12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n fontSize: '14px',\n color: 'var(--chatllm-text, #374151)',\n minWidth: '200px',\n cursor: 'pointer',\n};\n\nconst inputStyle: React.CSSProperties = {\n width: '100%',\n padding: '10px 12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n fontSize: '14px',\n color: 'var(--chatllm-text, #374151)',\n};\n\nconst labelStyle: React.CSSProperties = {\n display: 'block',\n fontSize: '12px',\n color: 'var(--chatllm-text-muted, #6b7280)',\n marginBottom: '6px',\n};\n\nconst buttonSecondaryStyle: React.CSSProperties = {\n padding: '8px 16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f3f4f6)',\n border: 'none',\n borderRadius: '8px',\n fontSize: '14px',\n color: 'var(--chatllm-text, #374151)',\n cursor: 'pointer',\n};\n\nconst buttonDangerStyle: React.CSSProperties = {\n padding: '8px 16px',\n backgroundColor: 'var(--chatllm-danger-bg, #fef2f2)',\n border: 'none',\n borderRadius: '8px',\n fontSize: '14px',\n color: 'var(--chatllm-danger, #dc2626)',\n cursor: 'pointer',\n};\n\n/**\n * @description 메모리 탭 내부 콘텐츠\n * @Todo vibecode - SettingsModal 내 AI 메모리 뷰\n */\nconst memoryCategoryLabels: Record<string, string> = {\n fact: '사용자 정보',\n skill: '전문 분야/기술',\n preference: '사용자 선호',\n};\n\nconst memoryCategoryColors: Record<string, string> = {\n fact: '#f59e0b',\n skill: '#10b981',\n preference: '#8b5cf6',\n};\n\nconst MemoryTabContent: React.FC<{\n items: MemoryItem[];\n contextSummary?: string;\n onDelete?: (key: string) => void;\n onClearAll?: () => void;\n /** @description 탭 제목 @Todo vibecode */\n title?: string;\n /** @description 빈 상태 메시지 @Todo vibecode */\n emptyMessage?: string;\n /** @description 빈 상태 설명 @Todo vibecode */\n emptyDescription?: string;\n}> = ({ items, contextSummary, onDelete, onClearAll, title = 'AI 메모리', emptyMessage = '저장된 메모리가 없습니다', emptyDescription = '대화가 진행되면 AI가 자동으로 정보를 학습합니다' }) => {\n const [activeFilter, setActiveFilter] = useState<'all' | 'fact' | 'skill' | 'preference'>('all');\n const [expandedId, setExpandedId] = useState<string | null>(null);\n\n const filteredItems = activeFilter === 'all'\n ? items\n : items.filter((item) => item.category === activeFilter);\n\n const formatDate = (timestamp: number): string => {\n const date = new Date(timestamp);\n return date.toLocaleDateString('ko-KR', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n };\n\n return (\n <div>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '24px' }}>\n <h2 style={{ fontSize: '20px', fontWeight: 600, color: 'var(--chatllm-text, #1f2937)', margin: 0 }}>\n {title}\n </h2>\n <span style={{ fontSize: '13px', color: 'var(--chatllm-text-muted, #9ca3af)' }}>\n {items.length}개 항목\n </span>\n </div>\n\n {/* 카테고리 필터 */}\n <div style={{ display: 'flex', gap: '6px', marginBottom: '20px', flexWrap: 'wrap' }}>\n {(['all', 'fact', 'skill', 'preference'] as const).map((tab) => (\n <button\n key={tab}\n onClick={() => setActiveFilter(tab)}\n style={{\n padding: '6px 14px',\n fontSize: '13px',\n fontWeight: activeFilter === tab ? 500 : 400,\n backgroundColor: activeFilter === tab\n ? 'var(--chatllm-primary-light, #dbeafe)'\n : 'var(--chatllm-bg-secondary, #f9fafb)',\n color: activeFilter === tab\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-text-muted, #6b7280)',\n border: '1px solid ' + (activeFilter === tab\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-border, #e5e7eb)'),\n borderRadius: '8px',\n cursor: 'pointer',\n }}\n >\n {tab === 'all' ? '전체' : memoryCategoryLabels[tab]}\n </button>\n ))}\n </div>\n\n {/* 컨텍스트 요약 */}\n {contextSummary && activeFilter === 'all' && (\n <div\n style={{\n padding: '14px',\n marginBottom: '16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '10px',\n borderLeft: '3px solid var(--chatllm-primary, #3b82f6)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '6px', marginBottom: '8px' }}>\n <IconSvg name=\"file-text-line\" size={14} color=\"var(--chatllm-primary, #3b82f6)\" />\n <span style={{ fontSize: '12px', fontWeight: 500, color: 'var(--chatllm-primary, #3b82f6)' }}>\n 대화 요약\n </span>\n </div>\n <p style={{ fontSize: '13px', lineHeight: '1.6', color: 'var(--chatllm-text, #374151)', margin: 0 }}>\n {contextSummary}\n </p>\n </div>\n )}\n\n {/* 메모리 아이템 목록 */}\n {filteredItems.length === 0 ? (\n <div style={{ padding: '40px 16px', textAlign: 'center' }}>\n <IconSvg name=\"robot-line\" size={40} color=\"var(--chatllm-text-muted, #d1d5db)\" />\n <p style={{ fontSize: '14px', color: 'var(--chatllm-text-muted, #9ca3af)', marginTop: '12px' }}>\n {emptyMessage}\n </p>\n <p style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #d1d5db)', marginTop: '4px' }}>\n {emptyDescription}\n </p>\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {filteredItems.map((item) => (\n <div\n key={item.id}\n style={{\n padding: '12px 14px',\n backgroundColor: 'var(--chatllm-content-bg, #ffffff)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '10px',\n cursor: 'pointer',\n transition: 'border-color 0.2s',\n }}\n onClick={() => setExpandedId(expandedId === item.id ? null : item.id)}\n >\n <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between' }}>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>\n {item.category && (\n <span\n style={{\n fontSize: '11px',\n fontWeight: 500,\n padding: '2px 8px',\n backgroundColor: `${memoryCategoryColors[item.category]}15`,\n color: memoryCategoryColors[item.category],\n borderRadius: '4px',\n }}\n >\n {memoryCategoryLabels[item.category]}\n </span>\n )}\n <span style={{ fontSize: '11px', color: 'var(--chatllm-text-muted, #9ca3af)' }}>\n {formatDate(item.timestamp)}\n </span>\n </div>\n <div style={{ fontSize: '13px', fontWeight: 500, color: 'var(--chatllm-text, #1f2937)' }}>\n {item.key}\n </div>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>\n {onDelete && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onDelete(item.key);\n }}\n style={{\n padding: '4px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n opacity: 0.5,\n }}\n aria-label=\"메모리 삭제\"\n >\n <IconSvg name=\"delete-bin-line\" size={14} color=\"var(--chatllm-text-muted, #9ca3af)\" />\n </button>\n )}\n <IconSvg\n name={expandedId === item.id ? 'arrow-up-s-line' : 'arrow-down-s-line'}\n size={16}\n color=\"var(--chatllm-text-muted, #9ca3af)\"\n />\n </div>\n </div>\n\n {expandedId === item.id && (\n <div\n style={{\n marginTop: '12px',\n paddingTop: '12px',\n borderTop: '1px solid var(--chatllm-border-light, #f3f4f6)',\n }}\n >\n <p\n style={{\n fontSize: '13px',\n lineHeight: '1.6',\n color: 'var(--chatllm-text, #374151)',\n margin: 0,\n whiteSpace: 'pre-wrap',\n }}\n >\n {item.value}\n </p>\n </div>\n )}\n </div>\n ))}\n </div>\n )}\n\n {/* 전체 삭제 버튼 */}\n {onClearAll && items.length > 0 && (\n <div style={{ marginTop: '24px', paddingTop: '16px', borderTop: '1px solid var(--chatllm-border, #e5e7eb)' }}>\n <button\n onClick={() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n if (typeof window !== 'undefined' && window.confirm('모든 AI 메모리를 삭제하시겠습니까?')) {\n onClearAll();\n }\n }}\n style={buttonDangerStyle}\n >\n 전체 메모리 삭제\n </button>\n </div>\n )}\n </div>\n );\n};\n\nexport default SettingsModal;\n","/**\n * @description 프로젝트 설정 모달 - 일반/지침/파일 3탭 구조\n * @Todo vibecode - 프로젝트 정보 편집, Instructions, 파일 메타데이터 관리\n */\n\nimport React, { useState, useEffect } from 'react';\nimport { IconSvg } from './Icon';\nimport type { ChatProject, ProjectFile } from '../types';\n\nexport interface ProjectSettingsModalProps {\n isOpen: boolean;\n project: ChatProject | null;\n onClose: () => void;\n onUpdateProject: (projectId: string, data: Partial<ChatProject>) => void;\n onAddFile: (projectId: string, file: File) => void;\n onDeleteFile: (projectId: string, fileId: string) => void;\n /** @Todo vibecode - 프로젝트 삭제 핸들러 (기본 프로젝트 삭제 불가) */\n onDeleteProject?: (projectId: string) => void;\n}\n\n/** @Todo vibecode - 프로젝트 설정 탭 타입 */\ntype ProjectTab = 'general' | 'instructions' | 'files';\n\n/** @Todo vibecode - 프로젝트 색상 프리셋 */\nconst COLOR_PRESETS = [\n '#2563eb', '#7c3aed', '#db2777', '#dc2626',\n '#ea580c', '#d97706', '#16a34a', '#0d9488',\n];\n\nexport const ProjectSettingsModal: React.FC<ProjectSettingsModalProps> = ({\n isOpen,\n project,\n onClose,\n onUpdateProject,\n onAddFile,\n onDeleteFile,\n onDeleteProject,\n}) => {\n const [activeTab, setActiveTab] = useState<ProjectTab>('general');\n const [title, setTitle] = useState('');\n const [description, setDescription] = useState('');\n const [instructions, setInstructions] = useState('');\n const [color, setColor] = useState('#2563eb');\n\n /** @Todo vibecode - 프로젝트 데이터로 폼 초기화 */\n useEffect(() => {\n if (project) {\n setTitle(project.title);\n setDescription(project.description || '');\n setInstructions(project.instructions || '');\n setColor(project.color || '#2563eb');\n }\n }, [project]);\n\n if (!isOpen || !project) return null;\n\n const isDefaultProject = project.id === 'default';\n\n /** @Todo vibecode - 일반 탭 저장 핸들러 */\n const handleSaveGeneral = () => {\n onUpdateProject(project.id, { title, description, color });\n };\n\n /** @Todo vibecode - 지침 탭 저장 핸들러 */\n const handleSaveInstructions = () => {\n onUpdateProject(project.id, { instructions });\n };\n\n /** @Todo vibecode - 파일 업로드 핸들러 */\n const handleFileUpload = () => {\n const input = document.createElement('input');\n input.type = 'file';\n input.multiple = true;\n input.onchange = (e) => {\n const files = (e.target as HTMLInputElement).files;\n if (files) {\n Array.from(files).forEach((file) => onAddFile(project.id, file));\n }\n };\n input.click();\n };\n\n /** @Todo vibecode - 파일 타입별 아이콘 매핑 */\n const getFileIcon = (type: ProjectFile['type']) => {\n const icons = {\n image: 'image-line' as const,\n pdf: 'file-text-line' as const,\n text: 'file-text-line' as const,\n code: 'code-line' as const,\n other: 'file-text-line' as const,\n };\n return icons[type] || ('file-text-line' as const);\n };\n\n /** @Todo vibecode - 파일 크기 포매팅 */\n const formatSize = (bytes?: number): string => {\n if (!bytes) return '';\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n };\n\n const tabStyle = (tab: ProjectTab) => ({\n padding: '8px 16px',\n fontSize: '13px',\n fontWeight: activeTab === tab ? 600 : 400,\n color: activeTab === tab ? 'var(--chatllm-primary, #2563eb)' : 'var(--chatllm-text-muted, #999)',\n borderBottom: activeTab === tab ? '2px solid var(--chatllm-primary, #2563eb)' : '2px solid transparent',\n background: 'none',\n border: 'none',\n borderBottomStyle: 'solid' as const,\n cursor: 'pointer',\n fontFamily: 'inherit',\n });\n\n return (\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 100,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'rgba(0,0,0,0.4)',\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget) onClose();\n }}\n >\n <div\n style={{\n backgroundColor: 'var(--chatllm-content-bg, #fff)',\n borderRadius: '12px',\n width: '520px',\n maxWidth: '90vw',\n maxHeight: '80vh',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n }}\n >\n {/* 헤더 */}\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: '20px 24px 0',\n }}\n >\n <h2 style={{ fontSize: '16px', fontWeight: 600, margin: 0, color: 'var(--chatllm-text, #1a1a1a)' }}>\n 프로젝트 설정\n </h2>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n display: 'flex',\n alignItems: 'center',\n }}\n aria-label='닫기'\n >\n <IconSvg name='close-line' size={20} color='var(--chatllm-text-muted, #999)' />\n </button>\n </div>\n\n {/* 탭 */}\n <div\n style={{\n display: 'flex',\n gap: '4px',\n padding: '16px 24px 0',\n borderBottom: '1px solid var(--chatllm-border, #e0e0e0)',\n }}\n >\n <button onClick={() => setActiveTab('general')} style={tabStyle('general')}>\n 일반\n </button>\n <button onClick={() => setActiveTab('instructions')} style={tabStyle('instructions')}>\n 지침\n </button>\n <button onClick={() => setActiveTab('files')} style={tabStyle('files')}>\n 파일 ({project.files.length})\n </button>\n </div>\n\n {/* 탭 콘텐츠 */}\n <div style={{ padding: '24px', overflowY: 'auto', flex: 1 }}>\n {/* 일반 탭 */}\n {activeTab === 'general' && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>\n <div>\n <label style={{ display: 'block', fontSize: '13px', fontWeight: 500, marginBottom: '6px', color: 'var(--chatllm-text, #1a1a1a)' }}>\n 프로젝트 이름\n </label>\n <input\n type='text'\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder='프로젝트 이름'\n disabled={isDefaultProject}\n style={{\n width: '100%',\n padding: '8px 12px',\n borderRadius: '6px',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n fontSize: '14px',\n fontFamily: 'inherit',\n backgroundColor: isDefaultProject ? 'var(--chatllm-bg-tertiary, #f5f5f5)' : 'transparent',\n boxSizing: 'border-box',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n />\n </div>\n <div>\n <label style={{ display: 'block', fontSize: '13px', fontWeight: 500, marginBottom: '6px', color: 'var(--chatllm-text, #1a1a1a)' }}>\n 설명\n </label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder='프로젝트에 대한 간단한 설명'\n rows={3}\n style={{\n width: '100%',\n padding: '8px 12px',\n borderRadius: '6px',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n fontSize: '14px',\n fontFamily: 'inherit',\n resize: 'vertical',\n boxSizing: 'border-box',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n />\n </div>\n <div>\n <label style={{ display: 'block', fontSize: '13px', fontWeight: 500, marginBottom: '6px', color: 'var(--chatllm-text, #1a1a1a)' }}>\n 색상\n </label>\n <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>\n {COLOR_PRESETS.map((c) => (\n <button\n key={c}\n onClick={() => setColor(c)}\n style={{\n width: '28px',\n height: '28px',\n borderRadius: '50%',\n backgroundColor: c,\n border: color === c ? '3px solid var(--chatllm-text, #1a1a1a)' : '2px solid transparent',\n cursor: 'pointer',\n padding: 0,\n }}\n aria-label={`색상 ${c}`}\n />\n ))}\n </div>\n </div>\n <div style={{ display: 'flex', gap: '8px', justifyContent: 'flex-end', marginTop: '8px' }}>\n {!isDefaultProject && onDeleteProject && (\n <button\n onClick={() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n if (typeof window !== 'undefined' && window.confirm(`\"${project.title}\" 프로젝트와 소속 대화가 모두 삭제됩니다. 계속하시겠습니까?`)) {\n onDeleteProject(project.id);\n onClose();\n }\n }}\n style={{\n padding: '8px 16px',\n borderRadius: '6px',\n border: '1px solid #dc2626',\n backgroundColor: 'transparent',\n color: '#dc2626',\n fontSize: '13px',\n cursor: 'pointer',\n fontFamily: 'inherit',\n marginRight: 'auto',\n }}\n >\n 프로젝트 삭제\n </button>\n )}\n <button\n onClick={handleSaveGeneral}\n style={{\n padding: '8px 20px',\n borderRadius: '6px',\n border: 'none',\n backgroundColor: 'var(--chatllm-primary, #2563eb)',\n color: '#fff',\n fontSize: '13px',\n fontWeight: 500,\n cursor: 'pointer',\n fontFamily: 'inherit',\n }}\n >\n 저장\n </button>\n </div>\n </div>\n )}\n\n {/* 지침 탭 */}\n {activeTab === 'instructions' && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>\n <p style={{ fontSize: '13px', color: 'var(--chatllm-text-muted, #999)', margin: 0 }}>\n 이 프로젝트의 모든 대화에서 AI가 따라야 할 지침을 입력하세요.\n </p>\n <textarea\n value={instructions}\n onChange={(e) => setInstructions(e.target.value)}\n placeholder={'예:\\n- 너는 프로덕트 매니저 역할이야\\n- 항상 실행 가능한 액션 아이템을 제시해\\n- 기술적인 설명은 최소화해'}\n rows={12}\n style={{\n width: '100%',\n padding: '12px',\n borderRadius: '6px',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n fontSize: '14px',\n fontFamily: 'inherit',\n resize: 'vertical',\n lineHeight: 1.6,\n boxSizing: 'border-box',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n />\n <div style={{ display: 'flex', justifyContent: 'flex-end' }}>\n <button\n onClick={handleSaveInstructions}\n style={{\n padding: '8px 20px',\n borderRadius: '6px',\n border: 'none',\n backgroundColor: 'var(--chatllm-primary, #2563eb)',\n color: '#fff',\n fontSize: '13px',\n fontWeight: 500,\n cursor: 'pointer',\n fontFamily: 'inherit',\n }}\n >\n 저장\n </button>\n </div>\n </div>\n )}\n\n {/* 파일 탭 */}\n {activeTab === 'files' && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>\n <p style={{ fontSize: '13px', color: 'var(--chatllm-text-muted, #999)', margin: 0 }}>\n 프로젝트 컨텍스트로 사용할 파일을 관리합니다.\n </p>\n <button\n onClick={handleFileUpload}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n padding: '6px 14px',\n borderRadius: '6px',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n backgroundColor: 'transparent',\n fontSize: '13px',\n cursor: 'pointer',\n fontFamily: 'inherit',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n >\n <IconSvg name='upload-line' size={14} />\n 업로드\n </button>\n </div>\n\n {project.files.length === 0 ? (\n <div\n style={{\n padding: '32px',\n textAlign: 'center',\n color: 'var(--chatllm-text-muted, #999)',\n fontSize: '13px',\n border: '1px dashed var(--chatllm-border, #e0e0e0)',\n borderRadius: '8px',\n }}\n >\n 아직 파일이 없습니다\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\n {project.files.map((file) => (\n <div\n key={file.id}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 12px',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n borderRadius: '6px',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '10px', overflow: 'hidden' }}>\n <IconSvg name={getFileIcon(file.type)} size={18} color='var(--chatllm-text-muted, #999)' />\n <div style={{ overflow: 'hidden' }}>\n <div\n style={{\n fontSize: '13px',\n fontWeight: 500,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n >\n {file.name}\n </div>\n <div style={{ fontSize: '11px', color: 'var(--chatllm-text-muted, #999)' }}>\n {file.type}{formatSize(file.size) ? ` · ${formatSize(file.size)}` : ''}\n </div>\n </div>\n </div>\n <button\n onClick={() => onDeleteFile(project.id, file.id)}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n opacity: 0.5,\n transition: 'opacity 0.1s',\n display: 'flex',\n alignItems: 'center',\n }}\n onMouseEnter={(e) => { (e.currentTarget as HTMLElement).style.opacity = '1'; }}\n onMouseLeave={(e) => { (e.currentTarget as HTMLElement).style.opacity = '0.5'; }}\n aria-label={`${file.name} 삭제`}\n >\n <IconSvg name='delete-bin-line' size={16} color='#dc2626' />\n </button>\n </div>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n","/**\n * @description AI 면책조항 모달 컴포넌트\n * @Todo vibecode - 하단 \"AI 채팅은 실수를 할 수 있습니다\" 클릭 시 노출\n */\n\nimport React from 'react';\nimport { IconSvg } from './Icon';\n\nexport interface DisclaimerModalProps {\n /** 모달 열림 상태 */\n isOpen: boolean;\n /** 모달 닫기 핸들러 */\n onClose: () => void;\n}\n\n/** @Todo vibecode - 강조 텍스트 인라인 스타일 */\nconst highlightStyle: React.CSSProperties = {\n color: 'var(--chatllm-text, #1e293b)',\n fontWeight: 600,\n};\n\n/** @Todo vibecode - AI 한계 안내 모달 (AI 1인칭 시점, 감성적 톤 + 핵심 강조) */\nexport const DisclaimerModal: React.FC<DisclaimerModalProps> = ({ isOpen, onClose }) => {\n if (!isOpen) return null;\n\n return (\n <div\n className=\"chatllm-disclaimer-overlay\"\n style={{\n position: 'fixed',\n inset: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.3)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 1000,\n }}\n onClick={onClose}\n >\n <div\n className=\"chatllm-disclaimer-modal\"\n style={{\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n borderRadius: '16px',\n width: '100%',\n maxWidth: '560px',\n maxHeight: '80vh',\n margin: '16px',\n boxShadow: '0 20px 60px rgba(0, 0, 0, 0.15)',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* 헤더 */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '20px 24px 16px',\n borderBottom: '1px solid var(--chatllm-border, #e5e7eb)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <IconSvg name=\"error-warning-line\" size={20} color=\"var(--chatllm-primary, #4A90E2)\" />\n <h2\n style={{\n margin: 0,\n fontSize: '16px',\n fontWeight: 600,\n color: 'var(--chatllm-text, #1e293b)',\n }}\n >\n 안녕하세요, 저는 AI입니다\n </h2>\n </div>\n <button\n onClick={onClose}\n aria-label=\"닫기\"\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n borderRadius: '6px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg name=\"close-line\" size={20} color=\"var(--chatllm-text-muted, #64748b)\" />\n </button>\n </div>\n\n {/* 본문 */}\n <div\n className=\"chatllm-scrollbar\"\n style={{\n padding: '20px 24px 24px',\n overflow: 'auto',\n fontSize: '14px',\n lineHeight: 1.8,\n color: 'var(--chatllm-text-secondary, #475569)',\n }}\n >\n <p style={{ margin: '0 0 16px' }}>\n 저는 여러분의 질문에 <span style={highlightStyle}>최선의 답변을 드리기 위해 항상 노력</span>하고\n 있어요. 하지만 솔직하게 말씀드리면, 저도 때때로 실수를 하거나 정확하지 않은 답변을 드릴 수 있습니다.\n </p>\n\n {/* 핵심 안내 박스 */}\n <div\n style={{\n padding: '14px 16px',\n backgroundColor: 'var(--chatllm-primary-light, #eff6ff)',\n borderRadius: '10px',\n borderLeft: '3px solid var(--chatllm-primary, #4A90E2)',\n marginBottom: '16px',\n fontSize: '13px',\n lineHeight: 1.7,\n }}\n >\n <p style={{ margin: '0 0 8px', fontWeight: 600, color: 'var(--chatllm-text, #1e293b)' }}>\n 제가 이런 실수를 할 수 있어요\n </p>\n <ul style={{ margin: 0, paddingLeft: '18px', display: 'flex', flexDirection: 'column', gap: '4px' }}>\n <li>최신 정보를 반영하지 못한 답변을 드리는 경우</li>\n <li>그럴듯하게 들리지만 실제로는 정확하지 않은 내용</li>\n <li>실제로 존재하지 않는 출처나 인용을 만들어내는 경우</li>\n </ul>\n </div>\n\n <p style={{ margin: '0 0 16px' }}>\n 이런 현상을 <span style={highlightStyle}>&apos;환각(Hallucination)&apos;</span>이라고 부르는데요,\n 아직은 저와 같은 AI가 가진 근본적인 한계예요.\n 제 답변이 아무리 자연스러워 보여도, <span style={highlightStyle}>한 번 더 확인</span>해 주시면 감사하겠습니다.\n </p>\n\n <p style={{ margin: '0 0 16px' }}>\n <span style={highlightStyle}>제 답변은 참고 자료</span>로 활용해 주시고,\n 중요한 판단을 내리실 때는 꼭 추가로 확인해 주세요.\n 저도 더 정확한 답변을 드리기 위해 계속 발전하고 있습니다.\n </p>\n\n <p style={{ margin: '0 0 16px' }}>\n 제가 웹 검색 결과를 알려드릴 때도,{' '}\n <span style={highlightStyle}>원본 출처를 직접 확인</span>해 보시는 걸 추천드려요.\n 요약 과정에서 놓칠 수 있는 중요한 맥락이 원본에 담겨 있을 수 있거든요.\n </p>\n\n {/* 피드백 안내 */}\n <div\n style={{\n padding: '14px 16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '10px',\n fontSize: '13px',\n lineHeight: 1.7,\n textAlign: 'center',\n }}\n >\n <p style={{ margin: 0 }}>\n 저에 대한 의견이나 개선 제안이 있으시다면{' '}\n <a\n href=\"mailto:info@gendive.ai\"\n style={{\n color: 'var(--chatllm-primary, #4A90E2)',\n textDecoration: 'none',\n fontWeight: 600,\n }}\n >\n info@gendive.ai\n </a>\n 로 알려주세요.\n <br />\n 여러분의 피드백 하나하나가 제가 성장하는 데 큰 힘이 됩니다.\n </p>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default DisclaimerModal;\n","/**\n * @description 심층연구 (Deep Research) 훅\n * @Todo vibecode - Perplexity 스타일 에이전트 기반 심층연구 기능\n *\n * 4단계 아키텍처:\n * 1. 쿼리 분석 - 질문 유형 판단, 서브토픽 분해\n * 2. 병렬 서브에이전트 실행 - 검색 API 호출, 결과 수집\n * 3. 충분성 판단 - 커버리지 평가, 필요시 추가 검색\n * 4. 보고서 생성 - 구조화된 보고서 + 인라인 인용\n */\n\nimport { useState, useCallback, useRef } from 'react';\nimport type {\n SearchResult,\n DeepResearchProgress,\n SubAgentProgress,\n SourceItem,\n} from '../types';\n\n/**\n * @description useDeepResearch 훅 옵션\n */\nexport interface UseDeepResearchOptions {\n /** 웹 검색 API 호출 (필수) */\n onWebSearch: (query: string) => Promise<SearchResult[]>;\n /** 페이지 본문 추출 (선택) */\n onExtractContent?: (url: string) => Promise<string>;\n /** API 엔드포인트 */\n apiEndpoint: string;\n /** API 키 */\n apiKey?: string;\n /** 사용할 모델 */\n model: string;\n /** 프로바이더 */\n provider: string;\n}\n\n/**\n * @description 리서치 플랜 타입\n */\ninterface ResearchPlan {\n questionType: 'factCheck' | 'comparison' | 'comprehensive';\n topics: string[];\n searchQueries: string[];\n}\n\n/**\n * @description 서브에이전트 결과 타입\n */\ninterface SubAgentResult {\n topic: string;\n sources: SearchResult[];\n summary: string;\n}\n\n/**\n * @description 보고서 생성 프롬프트\n */\nconst REPORT_GENERATION_PROMPT = `당신은 리서치 보고서 작성 전문가입니다.\n\n<collected_sources>\n{sources_json}\n</collected_sources>\n\n<user_question>\n{question}\n</user_question>\n\n<format_rules>\n1. 핵심 요약 2-3문장으로 시작 (헤더 없이)\n2. ## 헤더로 섹션 구분\n3. 문장 끝에 인라인 인용 [1][2] 형태로 출처 표시\n4. 종합 결론으로 마무리\n5. 이모지 사용 금지\n</format_rules>\n\n<structure>\n[요약 2-3문장]\n\n## 상세 분석\n깊이 있는 분석 [1][2]\n\n## 주요 발견\n- 핵심 포인트 1 [3]\n- 핵심 포인트 2 [4]\n\n## 결론\n종합적인 결론\n</structure>`;\n\n/**\n * @description 쿼리 분석 프롬프트\n */\nconst QUERY_ANALYSIS_PROMPT = `사용자 질문을 분석하여 심층연구를 위한 검색 계획을 수립하세요.\n\n<user_question>\n{question}\n</user_question>\n\n응답은 반드시 다음 JSON 형식으로만 작성하세요:\n{\n \"questionType\": \"factCheck\" | \"comparison\" | \"comprehensive\",\n \"topics\": [\"서브토픽1\", \"서브토픽2\", \"서브토픽3\"],\n \"searchQueries\": [\"검색어1\", \"검색어2\", \"검색어3\", \"검색어4\", \"검색어5\"]\n}\n\n규칙:\n- topics: 3-5개의 핵심 서브토픽\n- searchQueries: 5-8개의 다양한 검색 쿼리 (한국어/영어 혼합)\n- JSON 외 다른 텍스트 출력 금지`;\n\n/**\n * @description useDeepResearch 훅\n */\nexport const useDeepResearch = (options: UseDeepResearchOptions) => {\n const { onWebSearch, onExtractContent, apiEndpoint, apiKey, model, provider } = options;\n\n const [isResearching, setIsResearching] = useState(false);\n const [progress, setProgress] = useState<DeepResearchProgress | null>(null);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n /**\n * @description LLM API 호출 헬퍼\n */\n const callLLM = useCallback(\n async (prompt: string, stream = false): Promise<string | ReadableStream> => {\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(apiKey && { Authorization: `Bearer ${apiKey}` }),\n },\n body: JSON.stringify({\n model,\n provider,\n messages: [{ role: 'user', content: prompt }],\n stream,\n }),\n signal: abortControllerRef.current?.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API 오류: ${response.status}`);\n }\n\n if (stream) {\n return response.body as ReadableStream;\n }\n\n const data = await response.json();\n return data.choices?.[0]?.message?.content || data.content || '';\n },\n [apiEndpoint, apiKey, model, provider]\n );\n\n /**\n * @description 1단계: 쿼리 분석\n */\n const analyzeQuery = useCallback(\n async (query: string): Promise<ResearchPlan> => {\n const prompt = QUERY_ANALYSIS_PROMPT.replace('{question}', query);\n const response = (await callLLM(prompt)) as string;\n\n try {\n // JSON 파싱 시도\n const jsonMatch = response.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n return JSON.parse(jsonMatch[0]) as ResearchPlan;\n }\n } catch {\n // 파싱 실패 시 기본값\n }\n\n // 기본 플랜 반환\n return {\n questionType: 'comprehensive',\n topics: [query],\n searchQueries: [query, `${query} 최신`, `${query} 상세`],\n };\n },\n [callLLM]\n );\n\n /**\n * @description 2단계: 서브에이전트 실행\n */\n const runSubAgent = useCallback(\n async (\n topic: string,\n queries: string[],\n agentId: string,\n updateProgress: (update: Partial<SubAgentProgress>) => void\n ): Promise<SubAgentResult> => {\n updateProgress({ status: 'searching', searchCount: 0, resultsCount: 0 });\n\n const allResults: SearchResult[] = [];\n let searchCount = 0;\n\n // 관련 쿼리로 검색\n for (const query of queries.slice(0, 3)) {\n try {\n searchCount++;\n updateProgress({ searchCount });\n\n const results = await onWebSearch(query);\n allResults.push(...results);\n\n updateProgress({ resultsCount: allResults.length });\n\n // 충분한 결과가 있으면 중단\n if (allResults.length >= 10) break;\n } catch (error) {\n console.error(`검색 오류 (${query}):`, error);\n }\n }\n\n // 본문 추출 (옵션)\n if (onExtractContent && allResults.length > 0) {\n updateProgress({ status: 'extracting' });\n\n const topResults = allResults.slice(0, 5);\n await Promise.all(\n topResults.map(async (result) => {\n try {\n const content = await onExtractContent(result.url);\n result.content = content.slice(0, 2000); // 최대 2000자\n } catch {\n // 추출 실패 시 스니펫 사용\n }\n })\n );\n }\n\n updateProgress({ status: 'done' });\n\n return {\n topic,\n sources: allResults,\n summary: '',\n };\n },\n [onWebSearch, onExtractContent]\n );\n\n /**\n * @description 4단계: 보고서 생성 (스트리밍)\n */\n const generateReport = useCallback(\n async (\n query: string,\n results: SubAgentResult[],\n onStreamContent: (chunk: string) => void\n ): Promise<{ content: string; sources: SourceItem[] }> => {\n // 소스 목록 생성\n const allSources: SourceItem[] = [];\n const sourcesForPrompt: { index: number; title: string; url: string; snippet: string }[] = [];\n\n results.forEach((result) => {\n result.sources.forEach((source) => {\n const index = allSources.length + 1;\n allSources.push({\n id: `source-${index}`,\n title: source.title,\n url: source.url,\n snippet: source.snippet,\n });\n sourcesForPrompt.push({\n index,\n title: source.title,\n url: source.url,\n snippet: source.content || source.snippet,\n });\n });\n });\n\n const prompt = REPORT_GENERATION_PROMPT.replace(\n '{sources_json}',\n JSON.stringify(sourcesForPrompt, null, 2)\n ).replace('{question}', query);\n\n // 스트리밍 응답 처리\n const stream = (await callLLM(prompt, true)) as ReadableStream;\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let fullContent = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n\n // SSE 형식 파싱\n const lines = chunk.split('\\n');\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n\n try {\n const parsed = JSON.parse(data);\n const content =\n parsed.choices?.[0]?.delta?.content || parsed.delta?.content || '';\n if (content) {\n fullContent += content;\n onStreamContent(content);\n }\n } catch {\n // JSON 파싱 실패 시 원본 데이터 사용\n if (data && data !== '[DONE]') {\n fullContent += data;\n onStreamContent(data);\n }\n }\n }\n }\n }\n\n return { content: fullContent, sources: allSources };\n },\n [callLLM]\n );\n\n /**\n * @description 심층연구 실행\n */\n const runDeepResearch = useCallback(\n async (\n query: string,\n onStreamContent: (chunk: string) => void\n ): Promise<{ content: string; sources: SourceItem[] }> => {\n abortControllerRef.current = new AbortController();\n setIsResearching(true);\n\n const subAgentStates: Map<string, SubAgentProgress> = new Map();\n\n const updateSubAgentProgress = (id: string, update: Partial<SubAgentProgress>) => {\n const current = subAgentStates.get(id) || {\n id,\n topic: '',\n status: 'pending' as const,\n searchCount: 0,\n resultsCount: 0,\n };\n const updated = { ...current, ...update };\n subAgentStates.set(id, updated);\n\n setProgress((prev) => ({\n phase: prev?.phase || 'researching',\n phaseLabel: prev?.phaseLabel || '정보 수집 중...',\n subAgents: Array.from(subAgentStates.values()),\n totalSources: Array.from(subAgentStates.values()).reduce(\n (sum, agent) => sum + agent.resultsCount,\n 0\n ),\n }));\n };\n\n try {\n // 1단계: 쿼리 분석\n setProgress({\n phase: 'analyzing',\n phaseLabel: '질문 분석 중...',\n subAgents: [],\n totalSources: 0,\n });\n\n const plan = await analyzeQuery(query);\n\n // 2단계: 병렬 서브에이전트 실행\n plan.topics.forEach((topic, index) => {\n const agentId = `agent-${index}`;\n subAgentStates.set(agentId, {\n id: agentId,\n topic,\n status: 'pending',\n searchCount: 0,\n resultsCount: 0,\n });\n });\n\n setProgress({\n phase: 'researching',\n phaseLabel: '정보 수집 중...',\n subAgents: Array.from(subAgentStates.values()),\n totalSources: 0,\n });\n\n const results = await Promise.all(\n plan.topics.map((topic, index) => {\n const agentId = `agent-${index}`;\n // 각 토픽에 관련된 쿼리 필터링\n const relatedQueries = plan.searchQueries.filter(\n (q) =>\n q.toLowerCase().includes(topic.toLowerCase()) ||\n topic.toLowerCase().includes(q.toLowerCase().split(' ')[0])\n );\n const queries =\n relatedQueries.length > 0 ? relatedQueries : [topic, ...plan.searchQueries.slice(0, 2)];\n\n return runSubAgent(topic, queries, agentId, (update) =>\n updateSubAgentProgress(agentId, update)\n );\n })\n );\n\n // 3단계: 충분성 판단 (현재는 단순화)\n setProgress((prev) => ({\n ...prev!,\n phase: 'evaluating',\n phaseLabel: '결과 평가 중...',\n }));\n\n const totalSources = results.reduce((sum, r) => sum + r.sources.length, 0);\n\n // 결과가 부족하면 추가 검색\n if (totalSources < 5) {\n const additionalResult = await runSubAgent(\n query,\n [query, `${query} 정보`, `${query} 최신 뉴스`],\n 'agent-additional',\n (update) => updateSubAgentProgress('agent-additional', update)\n );\n results.push(additionalResult);\n }\n\n // 4단계: 보고서 생성\n setProgress((prev) => ({\n ...prev!,\n phase: 'generating',\n phaseLabel: '보고서 작성 중...',\n }));\n\n const report = await generateReport(query, results, onStreamContent);\n\n setProgress((prev) => ({\n ...prev!,\n phase: 'done',\n phaseLabel: '완료',\n }));\n\n return report;\n } catch (error) {\n if ((error as Error).name === 'AbortError') {\n throw new Error('심층연구가 취소되었습니다.');\n }\n throw error;\n } finally {\n setIsResearching(false);\n abortControllerRef.current = null;\n }\n },\n [analyzeQuery, runSubAgent, generateReport]\n );\n\n /**\n * @description 심층연구 중단\n */\n const stopResearch = useCallback(() => {\n abortControllerRef.current?.abort();\n setIsResearching(false);\n setProgress(null);\n }, []);\n\n return {\n runDeepResearch,\n stopResearch,\n isResearching,\n progress,\n };\n};\n\nexport default useDeepResearch;\n","/**\n * @description 메모리 패널 컴포넌트\n * 저장된 메모리, 컨텍스트 요약, 학습된 정보 조회\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\n\nexport interface MemoryItem {\n id: string;\n key: string;\n value: string;\n category?: 'context' | 'preference' | 'skill' | 'fact';\n timestamp: number;\n}\n\nexport interface MemoryPanelProps {\n /** 메모리 아이템 목록 */\n items: MemoryItem[];\n /** 컨텍스트 요약 (압축된 대화) */\n contextSummary?: string;\n /** 삭제 핸들러 */\n onDelete?: (id: string) => void;\n /** 전체 삭제 핸들러 */\n onClearAll?: () => void;\n /** 패널 열림 상태 */\n isOpen: boolean;\n /** 패널 토글 */\n onToggle: () => void;\n}\n\nconst categoryLabels: Record<string, string> = {\n fact: '사용자 정보',\n skill: '전문 분야/기술',\n preference: '사용자 선호',\n};\n\nconst categoryColors: Record<string, string> = {\n fact: '#f59e0b',\n skill: '#10b981',\n preference: '#8b5cf6',\n};\n\nexport const MemoryPanel: React.FC<MemoryPanelProps> = ({\n items,\n contextSummary,\n onDelete,\n onClearAll,\n isOpen,\n onToggle,\n}) => {\n const [expandedId, setExpandedId] = useState<string | null>(null);\n const [activeTab, setActiveTab] = useState<'all' | 'fact' | 'skill' | 'preference'>('all');\n\n const filteredItems = activeTab === 'all'\n ? items\n : items.filter(item => item.category === activeTab);\n\n const formatDate = (timestamp: number): string => {\n const date = new Date(timestamp);\n return date.toLocaleDateString('ko-KR', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n };\n\n if (!isOpen) {\n return (\n <button\n onClick={onToggle}\n style={{\n position: 'fixed',\n right: '16px',\n bottom: '100px',\n width: '48px',\n height: '48px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-primary, #3b82f6)',\n border: 'none',\n boxShadow: '0 4px 12px rgba(59, 130, 246, 0.3)',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 100,\n }}\n >\n <IconSvg name=\"robot-line\" size={24} color=\"#ffffff\" />\n </button>\n );\n }\n\n return (\n <div\n className=\"chatllm-memory-panel\"\n style={{\n position: 'fixed',\n right: '16px',\n bottom: '16px',\n width: '380px',\n maxHeight: '70vh',\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n borderRadius: '16px',\n boxShadow: '0 8px 32px rgba(0, 0, 0, 0.12)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n zIndex: 100,\n }}\n >\n {/* Header */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '16px',\n borderBottom: '1px solid var(--chatllm-border, #e5e7eb)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '8px',\n backgroundColor: 'var(--chatllm-primary-light, #dbeafe)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg name=\"robot-line\" size={18} color=\"var(--chatllm-primary, #3b82f6)\" />\n </div>\n <div>\n <div style={{ fontSize: '15px', fontWeight: 600, color: 'var(--chatllm-text, #1f2937)' }}>\n AI 메모리\n </div>\n <div style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #9ca3af)' }}>\n {items.length}개 항목\n </div>\n </div>\n </div>\n <div style={{ display: 'flex', gap: '4px' }}>\n {onClearAll && items.length > 0 && (\n <button\n onClick={onClearAll}\n style={{\n padding: '8px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n }}\n title=\"전체 삭제\"\n >\n <IconSvg name=\"delete-bin-line\" size={18} color=\"var(--chatllm-text-muted, #9ca3af)\" />\n </button>\n )}\n <button\n onClick={onToggle}\n style={{\n padding: '8px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n }}\n >\n <IconSvg name=\"close-line\" size={18} color=\"var(--chatllm-text-muted, #9ca3af)\" />\n </button>\n </div>\n </div>\n\n {/* Tabs */}\n <div\n style={{\n display: 'flex',\n gap: '4px',\n padding: '12px 16px',\n borderBottom: '1px solid var(--chatllm-border-light, #f3f4f6)',\n overflowX: 'auto',\n }}\n >\n {(['all', 'fact', 'skill', 'preference'] as const).map((tab) => (\n <button\n key={tab}\n onClick={() => setActiveTab(tab)}\n style={{\n padding: '6px 12px',\n fontSize: '13px',\n fontWeight: activeTab === tab ? 500 : 400,\n backgroundColor: activeTab === tab\n ? 'var(--chatllm-primary-light, #dbeafe)'\n : 'transparent',\n color: activeTab === tab\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-text-muted, #6b7280)',\n border: 'none',\n borderRadius: '6px',\n cursor: 'pointer',\n whiteSpace: 'nowrap',\n }}\n >\n {tab === 'all' ? '전체' : categoryLabels[tab]}\n </button>\n ))}\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, overflow: 'auto', padding: '12px' }}>\n {/* Context Summary */}\n {contextSummary && activeTab === 'all' && (\n <div\n style={{\n padding: '12px',\n marginBottom: '12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '10px',\n borderLeft: '3px solid var(--chatllm-primary, #3b82f6)',\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n marginBottom: '8px',\n }}\n >\n <IconSvg name=\"file-text-line\" size={14} color=\"var(--chatllm-primary, #3b82f6)\" />\n <span style={{ fontSize: '12px', fontWeight: 500, color: 'var(--chatllm-primary, #3b82f6)' }}>\n 대화 요약\n </span>\n </div>\n <p\n style={{\n fontSize: '13px',\n lineHeight: '1.6',\n color: 'var(--chatllm-text, #374151)',\n margin: 0,\n }}\n >\n {contextSummary}\n </p>\n </div>\n )}\n\n {/* Memory Items */}\n {filteredItems.length === 0 ? (\n <div\n style={{\n padding: '32px 16px',\n textAlign: 'center',\n color: 'var(--chatllm-text-muted, #9ca3af)',\n }}\n >\n <IconSvg name=\"robot-line\" size={32} color=\"var(--chatllm-text-muted, #d1d5db)\" />\n <p style={{ fontSize: '14px', marginTop: '12px' }}>저장된 메모리가 없습니다</p>\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {filteredItems.map((item) => (\n <div\n key={item.id}\n style={{\n padding: '12px',\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '10px',\n cursor: 'pointer',\n transition: 'all 0.2s',\n }}\n onClick={() => setExpandedId(expandedId === item.id ? null : item.id)}\n >\n {/* Item Header */}\n <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between' }}>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>\n {item.category && (\n <span\n style={{\n fontSize: '11px',\n fontWeight: 500,\n padding: '2px 8px',\n backgroundColor: `${categoryColors[item.category]}15`,\n color: categoryColors[item.category],\n borderRadius: '4px',\n }}\n >\n {categoryLabels[item.category]}\n </span>\n )}\n <span style={{ fontSize: '11px', color: 'var(--chatllm-text-muted, #9ca3af)' }}>\n {formatDate(item.timestamp)}\n </span>\n </div>\n <div\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-text, #1f2937)',\n }}\n >\n {item.key}\n </div>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>\n {onDelete && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onDelete(item.id);\n }}\n style={{\n padding: '4px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n opacity: 0.5,\n }}\n >\n <IconSvg name=\"delete-bin-line\" size={14} color=\"var(--chatllm-text-muted, #9ca3af)\" />\n </button>\n )}\n <IconSvg\n name={expandedId === item.id ? 'arrow-up-s-line' : 'arrow-down-s-line'}\n size={16}\n color=\"var(--chatllm-text-muted, #9ca3af)\"\n />\n </div>\n </div>\n\n {/* Expanded Content */}\n {expandedId === item.id && (\n <div\n style={{\n marginTop: '12px',\n paddingTop: '12px',\n borderTop: '1px solid var(--chatllm-border-light, #f3f4f6)',\n }}\n >\n <p\n style={{\n fontSize: '13px',\n lineHeight: '1.6',\n color: 'var(--chatllm-text, #374151)',\n margin: 0,\n whiteSpace: 'pre-wrap',\n }}\n >\n {item.value}\n </p>\n </div>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default MemoryPanel;\n"],"mappings":"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","names":["React","useState","useRef","useCallback","useEffect","useMemo","categoryLabels","useState","useCallback","useState","useCallback","useRef","useState","useRef","useCallback","useState","useCallback","useEffect","useRef","useState","useRef","useEffect","useCallback","newProject","fileMeta","generateId","generateId","useState","useRef","useEffect","useMemo","useCallback","savedPersonalization","messages","now","newSess","existingSession","options","currentSession","content","useState","useRef","useEffect","useState","useRef","useEffect","jsx","useState","useRef","useEffect","jsx","jsxs","useState","useRef","useEffect","jsx","jsxs","useState","Fragment","jsx","jsxs","useState","React","useRef","useEffect","useState","Fragment","jsx","jsxs","React","useRef","useState","useEffect","useRef","useEffect","useCallback","useState","useState","React","useMemo","useState","jsx","jsxs","useState","Fragment","jsx","jsxs","dataLines","colCount","result","jsx","React","jsxs","Fragment","useMemo","React","jsx","jsxs","React","useState","useCallback","useEffect","Fragment","jsx","jsxs","useState","useCallback","useEffect","jsx","jsxs","useState","Fragment","jsx","jsxs","useState","jsx","jsxs","useState","Fragment","jsx","jsxs","mapIcon","useState","jsx","jsxs","jsx","jsxs","useState","jsx","jsxs","useRef","useState","useCallback","useEffect","jsx","jsxs","useState","jsx","jsxs","DEFAULT_PERSONALIZATION","useState","useState","useEffect","jsx","jsxs","useState","useEffect","getFileIcon","jsx","jsxs","jsx","jsxs","React","generateTitle","useState","useCallback","useRef","REPORT_GENERATION_PROMPT","QUERY_ANALYSIS_PROMPT","callLLM","analyzeQuery","runSubAgent","generateReport","useState","jsx","jsxs","useState"]}
1
+ {"version":3,"sources":["../../src/react/ChatUI.tsx","../../src/react/hooks/useChatUI.ts","../../src/types.ts","../../src/react/hooks/useGlobalMemory.ts","../../src/react/adapters/LocalStorageAdapter.ts","../../src/react/adapters/PostgreSQLAdapter.ts","../../src/react/hooks/useInfoExtraction.ts","../../src/react/hooks/useSkills.ts","../../src/react/utils/skillParser.ts","../../src/react/utils/deepResearchAdapter.ts","../../src/react/hooks/useProject.ts","../../src/react/utils/projectMigration.ts","../../src/react/utils/pollParser.ts","../../src/react/utils/toolAdapter.ts","../../src/react/utils/sessionCache.ts","../../src/react/components/ChatSidebar.tsx","../../src/react/components/Icon.tsx","../../src/react/components/ProjectSelector.tsx","../../src/react/components/ChatHeader.tsx","../../src/react/components/ChatInput.tsx","../../src/react/components/MessageList.tsx","../../src/react/components/MessageBubble.tsx","../../src/react/components/MarkdownRenderer.tsx","../../src/react/components/LinkChip.tsx","../../src/react/components/DeepResearchProgressUI.tsx","../../src/react/components/PollCard.tsx","../../src/react/components/SkillProgressUI.tsx","../../src/react/components/ImageContentCard.tsx","../../src/react/components/FileContentCard.tsx","../../src/react/components/ToolStatusCard.tsx","../../src/react/components/ContentPartRenderer.tsx","../../src/react/components/SettingsModal.tsx","../../src/react/components/ProjectSettingsModal.tsx","../../src/react/components/DisclaimerModal.tsx","../../src/react/hooks/useDeepResearch.ts","../../src/react/components/EmptyState.tsx","../../src/react/components/MemoryPanel.tsx"],"sourcesContent":["/**\n * @description ChatUI 메인 컴포넌트\n * 풀 기능 채팅 UI\n */\n\nimport React from 'react';\nimport { useChatUI, UseChatUIOptions } from './hooks/useChatUI';\nimport { ChatSidebar } from './components/ChatSidebar';\nimport { ChatHeader } from './components/ChatHeader';\nimport { ChatInput } from './components/ChatInput';\nimport { MessageList } from './components/MessageList';\nimport { EmptyState } from './components/EmptyState';\nimport { SettingsModal } from './components/SettingsModal';\nimport { ProjectSettingsModal } from './components/ProjectSettingsModal';\nimport { DisclaimerModal } from './components/DisclaimerModal';\nimport type { ChatUIProps, ActionItem, PromptTemplate, ModelConfig, UseChatUIReturn, SuggestedPrompt } from './types';\nimport { IconSvg } from './components/Icon';\nimport type { MemoryItem } from './components/MemoryPanel';\n\n// ============================================================================\n// Default Actions\n// ============================================================================\n\nconst DEFAULT_ACTIONS: ActionItem[] = [];\n\n// ============================================================================\n// Default Templates\n// ============================================================================\n\nconst DEFAULT_TEMPLATES: PromptTemplate[] = [];\n\n// ============================================================================\n// Default Models\n// ============================================================================\n\n/**\n * @description 기본 모델 목록\n * @Todo vibecode\n */\nconst DEFAULT_MODELS: ModelConfig[] = [\n { id: 'gpt-4o', name: 'GPT-4o', provider: 'openai' },\n { id: 'gpt-4o-mini', name: 'GPT-4o Mini', provider: 'openai' },\n { id: 'claude-3-5-sonnet', name: 'Claude 3.5 Sonnet', provider: 'anthropic' },\n];\n\n// ============================================================================\n// CSS Styles (injected)\n// ============================================================================\n\n/**\n * @description Modern Canvas 디자인 시스템 스타일 주입\n * @Todo vibecode - 새로운 디자인 시스템 적용 (v0.11.0)\n */\nconst injectStyles = () => {\n if (typeof document === 'undefined') return;\n\n const styleId = 'chatllm-styles';\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = `\n @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');\n\n @keyframes chatllm-typing {\n 0%, 80%, 100% {\n transform: scale(0);\n opacity: 0.5;\n }\n 40% {\n transform: scale(1);\n opacity: 1;\n }\n }\n\n @keyframes chatllm-bounce {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-4px); }\n }\n\n @keyframes chatllm-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n\n @keyframes chatllm-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n\n @keyframes chatllm-welcome-exit {\n from { opacity: 1; transform: translateY(0); }\n to { opacity: 0; transform: translateY(-16px); }\n }\n\n @keyframes chatllm-chat-enter {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n\n .chatllm-root {\n --chatllm-primary: #4A90E2;\n --chatllm-primary-hover: #357ABD;\n --chatllm-primary-light: rgba(74, 144, 226, 0.1);\n --chatllm-bg: #F5F5F5;\n --chatllm-bg-secondary: #F5F5F5;\n --chatllm-bg-tertiary: #EDEDED;\n --chatllm-bg-hover: rgba(255, 255, 255, 0.4);\n --chatllm-bg-active: rgba(255, 255, 255, 0.6);\n --chatllm-bg-disabled: #E5E7EB;\n --chatllm-sidebar-bg: #F5F5F5;\n --chatllm-content-bg: #FFFFFF;\n --chatllm-input-bg: #FFFFFF;\n --chatllm-user-bubble: #EDEDED;\n --chatllm-text: #1e293b;\n --chatllm-text-secondary: #475569;\n --chatllm-text-muted: #94a3b8;\n --chatllm-border: #e2e8f0;\n --chatllm-border-light: rgba(226, 232, 240, 0.5);\n --chatllm-error: #ef4444;\n --chatllm-success: #22c55e;\n --chatllm-radius: 1rem;\n --chatllm-radius-lg: 1.5rem;\n --chatllm-shadow-sheet: 0 4px 20px -2px rgba(0, 0, 0, 0.05), 0 2px 6px -2px rgba(0, 0, 0, 0.03);\n --chatllm-shadow-input: 0 10px 40px -10px rgba(0, 0, 0, 0.1);\n }\n\n .chatllm-root.chatllm-dark {\n --chatllm-primary: #60a5fa;\n --chatllm-primary-hover: #3b82f6;\n --chatllm-primary-light: rgba(96, 165, 250, 0.15);\n --chatllm-bg: #0f172a;\n --chatllm-bg-secondary: #1e293b;\n --chatllm-bg-tertiary: #334155;\n --chatllm-bg-hover: rgba(51, 65, 85, 0.5);\n --chatllm-bg-active: rgba(51, 65, 85, 0.8);\n --chatllm-sidebar-bg: #0f172a;\n --chatllm-content-bg: #1e293b;\n --chatllm-input-bg: #1e293b;\n --chatllm-user-bubble: #334155;\n --chatllm-text: #f1f5f9;\n --chatllm-text-secondary: #cbd5e1;\n --chatllm-text-muted: #64748b;\n --chatllm-border: #334155;\n --chatllm-border-light: rgba(51, 65, 85, 0.5);\n }\n\n .chatllm-root {\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n .chatllm-root * {\n box-sizing: border-box;\n }\n\n .chatllm-root textarea::placeholder {\n color: var(--chatllm-text-muted);\n }\n\n .chatllm-root button:focus-visible {\n outline: 2px solid var(--chatllm-primary);\n outline-offset: 2px;\n }\n\n .chatllm-scrollbar::-webkit-scrollbar {\n width: 5px;\n }\n\n .chatllm-scrollbar::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .chatllm-scrollbar::-webkit-scrollbar-thumb {\n background: #E0E0E0;\n border-radius: 10px;\n }\n\n .chatllm-sheet {\n background: var(--chatllm-content-bg);\n border-radius: var(--chatllm-radius-lg);\n box-shadow: var(--chatllm-shadow-sheet);\n border: 1px solid var(--chatllm-border);\n }\n\n .chatllm-input-container {\n background: var(--chatllm-input-bg);\n border-radius: var(--chatllm-radius-lg);\n box-shadow: var(--chatllm-shadow-input);\n border: 1px solid var(--chatllm-border);\n transition: all 0.3s ease;\n }\n\n .chatllm-input-container:focus-within {\n border-color: rgba(74, 144, 226, 0.3);\n box-shadow: var(--chatllm-shadow-input), 0 0 0 4px rgba(74, 144, 226, 0.05);\n }\n\n .chatllm-dot-bounce {\n animation: chatllm-bounce 0.6s infinite ease-in-out;\n }\n\n .chatllm-dot-bounce:nth-child(2) {\n animation-delay: 0.1s;\n }\n\n .chatllm-dot-bounce:nth-child(3) {\n animation-delay: 0.2s;\n }\n\n .chatllm-skeleton-pulse {\n animation: chatllm-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n }\n\n .chatllm-sidebar-transition {\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .chatllm-table {\n width: 100%;\n border-collapse: collapse;\n margin: 12px 0;\n }\n\n .chatllm-table th,\n .chatllm-table td {\n border: 1px solid var(--chatllm-border);\n padding: 10px 12px;\n }\n\n .chatllm-table th {\n background-color: var(--chatllm-bg-tertiary);\n font-weight: 600;\n }\n\n .chatllm-table tr:hover {\n background-color: var(--chatllm-bg-hover);\n }\n\n .chatllm-image {\n max-width: 100%;\n border-radius: var(--chatllm-radius);\n margin: 8px 0;\n display: block;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n\n .chatllm-image:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n\n .chatllm-btn-primary {\n background: var(--chatllm-primary);\n color: white;\n border: none;\n border-radius: var(--chatllm-radius);\n font-weight: 600;\n transition: all 0.2s ease;\n box-shadow: 0 2px 8px rgba(74, 144, 226, 0.25);\n }\n\n .chatllm-btn-primary:hover {\n background: var(--chatllm-primary-hover);\n }\n\n .chatllm-btn-primary:active {\n transform: scale(0.98);\n }\n\n .chatllm-btn-secondary {\n background: var(--chatllm-content-bg);\n color: var(--chatllm-text-secondary);\n border: 1px solid var(--chatllm-border);\n border-radius: 9999px;\n font-weight: 500;\n transition: all 0.2s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n }\n\n .chatllm-btn-secondary:hover {\n background: var(--chatllm-bg-hover);\n border-color: rgba(74, 144, 226, 0.3);\n }\n `;\n\n document.head.appendChild(style);\n};\n\n// ============================================================================\n// ChatUIView - 순수 렌더링 컴포넌트\n// ============================================================================\n\n/**\n * @description 상태를 외부에서 주입받아 렌더링하는 순수 뷰 컴포넌트\n * @Todo vibecode - chatState prop 지원을 위해 렌더링 로직 분리\n */\ninterface ChatUIViewProps {\n state: UseChatUIReturn;\n models: ModelConfig[];\n actions: ActionItem[];\n templates: PromptTemplate[];\n showSidebar: boolean;\n sidebarWidth?: number | string;\n /** @Todo vibecode - 사이드바 커스텀 슬롯 */\n sidebarRenderAfterHeader?: () => React.ReactNode;\n sidebarRenderFooter?: () => React.ReactNode;\n showSettings: boolean;\n showMemoryTab: boolean;\n showModelSelector: boolean;\n showThinking: boolean;\n thinkingDefaultOpen: boolean;\n theme?: ChatUIProps['theme'];\n className: string;\n apiKey?: string;\n onApiKeyChange?: (key: string) => void;\n deepResearchEnabled: boolean;\n /** @Todo vibecode - Welcome Screen 제안 칩 */\n suggestedPrompts?: SuggestedPrompt[];\n}\n\nconst ChatUIView: React.FC<ChatUIViewProps> = ({\n state,\n models,\n actions,\n templates,\n showSidebar,\n sidebarWidth,\n sidebarRenderAfterHeader,\n sidebarRenderFooter,\n showSettings,\n showMemoryTab,\n showModelSelector,\n showThinking,\n thinkingDefaultOpen,\n theme,\n className,\n apiKey,\n onApiKeyChange,\n deepResearchEnabled,\n suggestedPrompts,\n}) => {\n const {\n sessions,\n currentSession,\n currentSessionId,\n messages,\n input,\n isLoading,\n selectedModel,\n sidebarOpen,\n settingsOpen,\n quotedText,\n selectedAction,\n copiedMessageId,\n editingMessageId,\n personalization: currentPersonalization,\n setInput,\n sendMessage,\n stopGeneration,\n newSession,\n selectSession,\n deleteSession,\n renameSession,\n setModel,\n toggleSidebar,\n openSettings,\n closeSettings,\n setQuotedText,\n setSelectedAction,\n copyMessage,\n startEdit,\n regenerate,\n askOtherModel,\n setActiveAlternative,\n activeAlternatives,\n loadingAlternativeFor,\n updatePersonalization,\n savePersonalization,\n models: hookModels,\n isDeepResearchMode,\n toggleDeepResearchMode,\n handlePollSubmit,\n globalMemory,\n compressionState,\n manualSkills,\n activeSkillExecution,\n executeManualSkill,\n attachments,\n addAttachments,\n removeAttachment,\n // Project\n projects,\n currentProjectId,\n currentProject,\n createProject,\n selectProject,\n updateProject,\n deleteProject,\n addProjectFile,\n deleteProjectFile,\n projectSettingsOpen,\n openProjectSettings,\n closeProjectSettings,\n projectMemory,\n isSessionsLoading,\n } = state;\n\n /** @Todo vibecode - AI 면책조항 모달 상태 */\n const [disclaimerOpen, setDisclaimerOpen] = React.useState(false);\n\n /** @Todo vibecode - Welcome → Chat 전환 애니메이션 */\n const [welcomeExiting, setWelcomeExiting] = React.useState(false);\n const prevMessageCountRef = React.useRef(messages.length);\n React.useEffect(() => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n if (prevMessageCountRef.current === 0 && messages.length > 0) {\n setWelcomeExiting(true);\n timer = setTimeout(() => setWelcomeExiting(false), 400);\n }\n prevMessageCountRef.current = messages.length;\n return () => { if (timer) clearTimeout(timer); };\n }, [messages.length]);\n\n const greeting = currentPersonalization.userProfile.nickname\n ? `안녕하세요, ${currentPersonalization.userProfile.nickname}님`\n : '안녕하세요';\n\n const handleTemplateClick = (template: PromptTemplate) => {\n setInput(template.prompt);\n };\n\n const handleActionSelect = (action: ActionItem) => {\n setSelectedAction(action);\n };\n\n const handleSubmit = () => {\n sendMessage();\n };\n\n const handleChoiceClick = (choice: { number: number; text: string; fullText: string }) => {\n setInput(choice.text);\n };\n\n /**\n * @description globalMemory entries → MemoryItem[] 변환\n * @Todo vibecode - 설정 모달 메모리 탭용\n */\n const memoryItems: MemoryItem[] = React.useMemo(() => {\n if (!globalMemory?.state.entries) return [];\n const items: MemoryItem[] = [];\n for (const [key, entry] of globalMemory.state.entries) {\n items.push({\n id: key,\n key,\n value: typeof entry.value === 'object' ? JSON.stringify(entry.value, null, 2) : String(entry.value),\n category: entry.category as MemoryItem['category'],\n timestamp: entry.updatedAt || entry.createdAt || Date.now(),\n });\n }\n return items;\n }, [globalMemory?.state.entries]);\n\n /**\n * @description projectMemory entries → MemoryItem[] 변환\n * @Todo vibecode - 설정 모달 프로젝트 메모리 탭용\n */\n const projectMemoryItems: MemoryItem[] = React.useMemo(() => {\n if (!projectMemory?.state.entries) return [];\n const items: MemoryItem[] = [];\n for (const [key, entry] of projectMemory.state.entries) {\n items.push({\n id: key,\n key,\n value: typeof entry.value === 'object' ? JSON.stringify(entry.value, null, 2) : String(entry.value),\n category: entry.category as MemoryItem['category'],\n timestamp: entry.updatedAt || entry.createdAt || Date.now(),\n });\n }\n return items;\n }, [projectMemory?.state.entries]);\n\n const themeClass = theme?.mode === 'dark' ? 'chatllm-dark' : '';\n\n return (\n <div\n className={`chatllm-root ${themeClass} ${className}`}\n style={{\n display: 'flex',\n height: '100%',\n width: '100%',\n backgroundColor: 'var(--chatllm-bg, #F5F5F5)',\n overflow: 'hidden',\n position: 'relative',\n }}\n >\n {/* Sidebar */}\n {showSidebar && (\n <ChatSidebar\n sessions={sessions}\n currentSessionId={currentSessionId}\n onSelectSession={selectSession}\n onNewSession={newSession}\n onDeleteSession={deleteSession}\n onRenameSession={renameSession}\n isOpen={sidebarOpen}\n onToggle={toggleSidebar}\n width={sidebarWidth}\n theme={theme?.mode}\n projects={projects.length > 0 ? projects : undefined}\n currentProjectId={currentProjectId}\n onSelectProject={projects.length > 0 ? selectProject : undefined}\n onNewProject={projects.length > 0 ? () => {\n if (typeof window === 'undefined') return;\n const title = window.prompt('프로젝트 이름을 입력하세요');\n if (title?.trim()) {\n createProject({ title: title.trim() });\n }\n } : undefined}\n onProjectSettings={projects.length > 0 ? (id: string) => {\n selectProject(id);\n openProjectSettings();\n } : undefined}\n renderAfterHeader={sidebarRenderAfterHeader}\n renderFooter={sidebarRenderFooter}\n isLoading={isSessionsLoading}\n />\n )}\n\n {/* Main Content */}\n <main\n style={{\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n position: 'relative',\n overflow: 'hidden',\n minWidth: 0,\n }}\n >\n {/* Header */}\n <ChatHeader\n title={currentSession?.title || '새 대화'}\n model={selectedModel}\n models={models}\n onModelChange={setModel}\n onSettingsOpen={openSettings}\n onSidebarToggle={toggleSidebar}\n sidebarOpen={sidebarOpen}\n showModelSelector={showModelSelector}\n showSettings={showSettings}\n />\n\n {/** @Todo vibecode - Welcome Screen: 메시지 없거나 exit 애니메이션 중 표시 */}\n {(messages.length === 0 || welcomeExiting) && (\n <div\n style={{\n ...(messages.length > 0\n ? { position: 'absolute' as const, inset: 0, zIndex: 5, background: 'var(--chatllm-bg)' }\n : { flex: 1 }),\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n padding: '24px',\n gap: '24px',\n animation: welcomeExiting ? 'chatllm-welcome-exit 0.3s ease forwards' : 'none',\n pointerEvents: welcomeExiting ? 'none' : 'auto',\n }}\n >\n {/* Welcome 텍스트 */}\n <h1\n style={{\n fontSize: '26px',\n fontWeight: 600,\n color: 'var(--chatllm-text)',\n margin: 0,\n textAlign: 'center',\n lineHeight: 1.4,\n }}\n >\n {greeting ? `${greeting} ✺` : '✺ 무엇을 생각해 볼까요?'}\n </h1>\n\n {/* ChatInput - inline 모드 */}\n <div style={{ width: '100%', maxWidth: '680px' }}>\n <ChatInput\n value={input}\n onChange={setInput}\n onSubmit={handleSubmit}\n onStop={stopGeneration}\n isLoading={isLoading}\n placeholder=\"메시지를 입력하세요...\"\n quotedText={quotedText}\n onClearQuote={() => setQuotedText(null)}\n selectedAction={selectedAction}\n onClearAction={() => setSelectedAction(null)}\n onActionSelect={setSelectedAction}\n actions={actions}\n onDeepResearch={toggleDeepResearchMode}\n isDeepResearchMode={isDeepResearchMode}\n deepResearchEnabled={deepResearchEnabled}\n manualSkills={manualSkills}\n onSkillSelect={executeManualSkill}\n activeSkillExecution={activeSkillExecution}\n attachments={attachments}\n onFileAttach={addAttachments}\n onRemoveAttachment={removeAttachment}\n onDisclaimerClick={() => setDisclaimerOpen(true)}\n inline\n />\n </div>\n\n {/* 제안 칩 */}\n {suggestedPrompts && suggestedPrompts.length > 0 && (\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '8px',\n justifyContent: 'center',\n maxWidth: '680px',\n }}\n >\n {suggestedPrompts.map((sp) => (\n <button\n key={sp.id}\n onClick={() => setInput(sp.prompt)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n padding: '8px 16px',\n borderRadius: '20px',\n border: '1px solid var(--chatllm-border)',\n background: 'var(--chatllm-content-bg)',\n color: 'var(--chatllm-text-secondary)',\n fontSize: '13px',\n fontFamily: 'inherit',\n cursor: 'pointer',\n transition: 'all 0.2s',\n }}\n >\n {sp.icon && <IconSvg name={sp.icon as any} size={16} color=\"var(--chatllm-text-muted)\" />}\n {sp.label}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n\n {/* Chat 모드: MessageList + ChatInput */}\n {messages.length > 0 && (\n <>\n <MessageList\n messages={messages}\n isLoading={isLoading}\n onCopy={copyMessage}\n onEdit={startEdit}\n onRegenerate={regenerate}\n onQuote={setQuotedText}\n onAskOtherModel={(userMessageId, assistantMessageId, targetModel) =>\n askOtherModel(assistantMessageId, targetModel)\n }\n onSetActiveAlternative={setActiveAlternative}\n activeAlternatives={activeAlternatives}\n models={hookModels}\n copiedId={copiedMessageId}\n editingId={editingMessageId}\n onChoiceClick={handleChoiceClick}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n loadingAlternativeFor={loadingAlternativeFor}\n onPollSubmit={handlePollSubmit}\n />\n <ChatInput\n value={input}\n onChange={setInput}\n onSubmit={handleSubmit}\n onStop={stopGeneration}\n isLoading={isLoading}\n placeholder=\"메시지를 입력하세요...\"\n quotedText={quotedText}\n onClearQuote={() => setQuotedText(null)}\n selectedAction={selectedAction}\n onClearAction={() => setSelectedAction(null)}\n onActionSelect={setSelectedAction}\n actions={actions}\n onDeepResearch={toggleDeepResearchMode}\n isDeepResearchMode={isDeepResearchMode}\n deepResearchEnabled={deepResearchEnabled}\n manualSkills={manualSkills}\n onSkillSelect={executeManualSkill}\n activeSkillExecution={activeSkillExecution}\n attachments={attachments}\n onFileAttach={addAttachments}\n onRemoveAttachment={removeAttachment}\n onDisclaimerClick={() => setDisclaimerOpen(true)}\n />\n </>\n )}\n\n </main>\n\n {/* Settings Modal */}\n {showSettings && (\n <SettingsModal\n isOpen={settingsOpen}\n onClose={closeSettings}\n personalization={currentPersonalization}\n onPersonalizationChange={updatePersonalization}\n apiKey={apiKey}\n onApiKeyChange={onApiKeyChange}\n onClearAllData={() => {\n sessions.forEach((s) => deleteSession(s.id));\n }}\n apiKeyLabel=\"API Key\"\n apiKeyDescription=\"Cloud 모델 사용에 필요합니다\"\n memoryItems={memoryItems}\n contextSummary={compressionState?.contextSummary}\n onDeleteMemory={globalMemory ? (key) => globalMemory.remove(key) : undefined}\n onClearMemory={globalMemory ? () => globalMemory.clear() : undefined}\n onSave={savePersonalization}\n showMemoryTab={showMemoryTab}\n enableProjects={projects.length > 0}\n projectMemoryItems={projectMemoryItems}\n onDeleteProjectMemory={projectMemory ? (key) => projectMemory.remove(key) : undefined}\n onClearProjectMemory={projectMemory ? () => projectMemory.clear() : undefined}\n currentProjectTitle={currentProject?.title}\n />\n )}\n\n {/* Project Settings Modal */}\n <ProjectSettingsModal\n isOpen={projectSettingsOpen}\n project={currentProject}\n onClose={closeProjectSettings}\n onUpdateProject={updateProject}\n onAddFile={addProjectFile}\n onDeleteFile={deleteProjectFile}\n onDeleteProject={deleteProject}\n />\n\n {/* AI Disclaimer Modal */}\n <DisclaimerModal isOpen={disclaimerOpen} onClose={() => setDisclaimerOpen(false)} />\n </div>\n );\n};\n\n// ============================================================================\n// ChatUIWithHook - 내부 Hook 호출 래퍼\n// ============================================================================\n\n/**\n * @description chatState 미제공 시 내부에서 useChatUI를 호출하는 래퍼\n * @Todo vibecode - React hooks 조건부 호출 불가 → 컴포넌트 경계에서 분기\n */\nconst ChatUIWithHook: React.FC<ChatUIProps> = ({\n models = DEFAULT_MODELS,\n actions = DEFAULT_ACTIONS,\n templates = DEFAULT_TEMPLATES,\n suggestedPrompts,\n personalization,\n onPersonalizationChange,\n onPersonalizationSave,\n apiKey,\n onApiKeyChange,\n apiEndpoint = '/api/chat',\n theme,\n showSidebar = true,\n sidebarWidth,\n sidebarRenderAfterHeader,\n sidebarRenderFooter,\n showSettings = true,\n showMemoryTab = true,\n showModelSelector = true,\n systemPrompt,\n contextCompressionThreshold = 20,\n keepRecentMessages = 6,\n storageKey = 'chatllm_sessions',\n initialSessionId,\n className = '',\n onSendMessage,\n onSessionChange,\n onError,\n onTitleChange,\n generateTitle,\n useExternalStorage = false,\n onLoadSessions,\n onCreateSession,\n onLoadSession,\n onDeleteSession,\n onUpdateSessionTitle,\n onSaveMessages,\n showThinking = true,\n thinkingDefaultOpen = false,\n deepResearch,\n skills,\n tools,\n onToolCall,\n continueAfterToolResult,\n onSkillComplete,\n onLoadModels,\n // Project options\n enableProjects,\n onLoadProjects,\n onCreateProject,\n onLoadProject,\n onUpdateProject,\n onDeleteProject,\n onAddProjectFile,\n onDeleteProjectFile,\n}) => {\n const hookOptions: UseChatUIOptions = {\n models,\n actions,\n initialPersonalization: personalization,\n onPersonalizationChange,\n onPersonalizationSave,\n initialSessionId,\n apiKey,\n apiEndpoint,\n initialModel: models[0]?.id,\n storageKey,\n contextCompressionThreshold,\n keepRecentMessages,\n onSendMessage,\n onSessionChange,\n onError,\n onTitleChange,\n generateTitle,\n useExternalStorage,\n onLoadSessions,\n onCreateSession,\n onLoadSession,\n onDeleteSession,\n onUpdateSessionTitle,\n onSaveMessages,\n deepResearch,\n skills,\n tools,\n onToolCall,\n continueAfterToolResult,\n onSkillComplete,\n onLoadModels,\n enableProjects,\n onLoadProjects,\n onCreateProject,\n onLoadProject,\n onUpdateProject,\n onDeleteProject,\n onAddProjectFile,\n onDeleteProjectFile,\n };\n\n const state = useChatUI(hookOptions);\n\n return (\n <ChatUIView\n state={state}\n models={models}\n actions={actions}\n templates={templates}\n showSidebar={showSidebar}\n sidebarWidth={sidebarWidth}\n sidebarRenderAfterHeader={sidebarRenderAfterHeader}\n sidebarRenderFooter={sidebarRenderFooter}\n showSettings={showSettings}\n showMemoryTab={showMemoryTab}\n showModelSelector={showModelSelector}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n theme={theme}\n className={className}\n apiKey={apiKey}\n onApiKeyChange={onApiKeyChange}\n deepResearchEnabled={!!deepResearch?.onWebSearch}\n suggestedPrompts={suggestedPrompts}\n />\n );\n};\n\n// ============================================================================\n// ChatUI - 메인 진입점\n// ============================================================================\n\n/**\n * @description ChatUI 메인 컴포넌트\n * @Todo vibecode - chatState 제공 시 외부 상태 사용, 미제공 시 내부 useChatUI 호출\n */\nexport const ChatUI: React.FC<ChatUIProps> = (props) => {\n injectStyles();\n\n if (props.chatState) {\n const {\n models = DEFAULT_MODELS,\n actions = DEFAULT_ACTIONS,\n templates = DEFAULT_TEMPLATES,\n showSidebar = true,\n sidebarWidth,\n sidebarRenderAfterHeader,\n sidebarRenderFooter,\n showSettings = true,\n showMemoryTab: chatStateShowMemoryTab = true,\n showModelSelector = true,\n showThinking = true,\n thinkingDefaultOpen = false,\n theme,\n className = '',\n apiKey,\n onApiKeyChange,\n deepResearch,\n suggestedPrompts: chatStateSuggestedPrompts,\n } = props;\n\n return (\n <ChatUIView\n state={props.chatState}\n models={models}\n actions={actions}\n templates={templates}\n showSidebar={showSidebar}\n sidebarWidth={sidebarWidth}\n sidebarRenderAfterHeader={sidebarRenderAfterHeader}\n sidebarRenderFooter={sidebarRenderFooter}\n showSettings={showSettings}\n showMemoryTab={chatStateShowMemoryTab}\n showModelSelector={showModelSelector}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n theme={theme}\n className={className}\n apiKey={apiKey}\n onApiKeyChange={onApiKeyChange}\n deepResearchEnabled={!!deepResearch?.onWebSearch}\n suggestedPrompts={chatStateSuggestedPrompts}\n />\n );\n }\n\n return <ChatUIWithHook {...props} />;\n};\n\nexport default ChatUI;\n","/**\n * @description Headless Chat UI Hook\n * 상태 관리와 로직만 제공, UI는 자유롭게 구현 가능\n */\n\nimport { useState, useRef, useCallback, useEffect, useMemo } from 'react';\nimport type {\n ChatSession,\n ChatMessage,\n ChatProject,\n ProjectFile,\n ActionItem,\n ModelConfig,\n PersonalizationConfig,\n UseChatUIReturn,\n SendMessageParams,\n SendMessageResponse,\n ProviderType,\n GlobalMemoryConfig,\n DeepResearchProgress,\n DeepResearchCallbacks,\n PollResponse,\n PollBlock,\n SkillConfig,\n SkillExecution,\n SkillExecutionResult,\n ManualSkillItem,\n ChatToolDefinition,\n ToolCallResult,\n MessageContentPart,\n ChatAttachment,\n} from '../types';\nimport { DEFAULT_PERSONALIZATION } from '../../types';\nimport { useGlobalMemory } from './useGlobalMemory';\nimport { useInfoExtraction } from './useInfoExtraction';\nimport { useSkills } from './useSkills';\nimport { useProject } from './useProject';\nimport { parsePollFromContent, formatPollResponse } from '../utils/pollParser';\nimport { convertToolsToSkills } from '../utils/toolAdapter';\nimport { parseSkillCallFromContent } from '../utils/skillParser';\n\n/**\n * @description SSE 스트리밍 Response에서 텍스트 추출\n * @Todo vibecode - 내부 LLM 호출(압축/추출) 응답 파싱 공통 유틸\n */\nconst parseSSEResponse = async (response: Response): Promise<string> => {\n const reader = response.body?.getReader();\n if (!reader) return '';\n\n const decoder = new TextDecoder();\n let buffer = '';\n let result = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n try {\n const parsed = JSON.parse(data);\n const chunk = parsed.content ?? parsed.text ?? '';\n if (chunk) result += chunk;\n } catch {\n // Ignore parse errors\n }\n }\n }\n }\n\n return result;\n};\nimport { writeSessionCache, readSessionCache, removeSessionCache } from '../utils/sessionCache';\nimport { migrateSessionsToProjects, DEFAULT_PROJECT_ID } from '../utils/projectMigration';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_STORAGE_KEY = 'chatllm_sessions';\nconst DEFAULT_PERSONALIZATION_KEY = 'chatllm_personalization';\nconst DEFAULT_COMPRESSION_THRESHOLD = 20;\nconst DEFAULT_KEEP_RECENT = 6;\nconst DEFAULT_RECOMPRESSION_THRESHOLD = 10;\nconst DEFAULT_TOKEN_LIMIT = 8000;\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\nconst generateId = (prefix: string): string =>\n `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n/**\n * @description File 객체를 base64 문자열로 변환\n * @Todo vibecode - autoConvertBase64 옵션 지원용 유틸리티\n */\nconst fileToBase64 = (file: File): Promise<string> =>\n new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve((reader.result as string).split(',')[1] || '');\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n\n/**\n * @description ChatAttachment 배열을 base64 변환된 객체 배열로 변환\n * @Todo vibecode - autoConvertBase64 옵션 지원\n */\nconst convertAttachmentsToBase64 = async (\n attachments: ChatAttachment[]\n): Promise<Array<{ name: string; mimeType: string; base64: string; size: number }>> =>\n Promise.all(\n attachments.map(async (att) => ({\n name: att.name,\n mimeType: att.mimeType,\n base64: await fileToBase64(att.file),\n size: att.size,\n }))\n );\n\nconst generateTitle = (messages: ChatMessage[]): string => {\n const firstUserMessage = messages.find((m) => m.role === 'user');\n if (!firstUserMessage) return '새 대화';\n const content = firstUserMessage.content;\n return content.length > 30 ? content.substring(0, 30) + '...' : content;\n};\n\n// ============================================================================\n// Hook Options\n// ============================================================================\n\nexport interface UseChatUIOptions {\n /** 사용 가능한 모델 목록 */\n models: ModelConfig[];\n /** 사용 가능한 Actions */\n actions?: ActionItem[];\n /** 초기 개인화 설정 */\n initialPersonalization?: Partial<PersonalizationConfig>;\n /** @Todo vibecode - 개인화 설정 변경 콜백 (실시간 UI 반영용) */\n onPersonalizationChange?: (config: PersonalizationConfig) => void;\n /** @Todo vibecode - 개인화 설정 저장 콜백 (저장 버튼 클릭 시 백엔드 저장용) */\n onPersonalizationSave?: (config: PersonalizationConfig) => void;\n /** @Todo vibecode - 초기 선택 세션 ID (미제공 시 sessions[0] 자동 선택) */\n initialSessionId?: string;\n /** API 키 */\n apiKey?: string;\n /** API 엔드포인트 */\n apiEndpoint?: string;\n /** 초기 모델 */\n initialModel?: string;\n /** 스토리지 키 */\n storageKey?: string;\n /** 컨텍스트 압축 임계값 */\n contextCompressionThreshold?: number;\n /** 압축 후 유지할 메시지 수 */\n keepRecentMessages?: number;\n /** 커스텀 메시지 전송 핸들러 */\n onSendMessage?: (params: SendMessageParams) => Promise<SendMessageResponse>;\n /** 세션 변경 핸들러 */\n onSessionChange?: (session: ChatSession | null) => void;\n /** 에러 핸들러 */\n onError?: (error: Error) => void;\n /** @Todo vibecode - 세션 제목 변경 핸들러 */\n onTitleChange?: (sessionId: string, newTitle: string) => void;\n /**\n * @description 첫 메시지 전송 시 LLM으로 제목 생성 콜백\n * @Todo vibecode - 자동 제목 생성 기능\n */\n generateTitle?: (firstMessage: string) => Promise<string> | string;\n\n // Memory Options\n /** 글로벌 메모리 사용 여부 (기본: true) */\n useGlobalMemoryEnabled?: boolean;\n /** 글로벌 메모리 설정 */\n globalMemoryConfig?: GlobalMemoryConfig;\n /** 자동 정보 추출 활성화 (기본: true) */\n enableAutoExtraction?: boolean;\n\n // External Storage Options\n /**\n * @description 외부 스토리지 사용 여부\n * @Todo vibecode - true 시 localStorage 대신 콜백 사용\n */\n useExternalStorage?: boolean;\n /**\n * @description 세션 목록 로드 콜백\n * @Todo vibecode - 컴포넌트 마운트 시 호출\n */\n onLoadSessions?: () => Promise<{ id: string; title: string }[]>;\n /**\n * @description 세션 생성 콜백\n * @Todo vibecode - 새 채팅 생성 시 호출\n */\n onCreateSession?: () => Promise<{ id: string; title: string }>;\n /**\n * @description 세션 상세 로드 콜백 (메시지 포함)\n * @Todo vibecode - 세션 선택 시 호출 (lazy loading)\n * API 응답 형식: { role: 'USER'|'ASSISTANT', message: string }\n */\n onLoadSession?: (sessionId: string) => Promise<{\n id: string;\n title: string;\n messages: Array<{\n id?: string;\n role: 'USER' | 'ASSISTANT' | 'user' | 'assistant';\n message?: string;\n content?: string;\n /** @Todo vibecode - 멀티 콘텐츠 파트 (이미지/파일 등 복원용) */\n contentParts?: MessageContentPart[];\n created_at?: string;\n }>;\n memory_data?: object;\n }>;\n /**\n * @description 세션 삭제 콜백\n * @Todo vibecode - 세션 삭제 시 호출\n */\n onDeleteSession?: (sessionId: string) => Promise<void>;\n /**\n * @description 세션 제목 수정 콜백\n * @Todo vibecode - 세션 제목 변경 시 호출\n */\n onUpdateSessionTitle?: (sessionId: string, title: string) => Promise<void>;\n /**\n * @description 메시지 저장 콜백\n * @Todo vibecode - 메시지 전송 완료 후 호출, contentParts로 이미지/파일 등 저장\n */\n onSaveMessages?: (\n sessionId: string,\n messages: { role: 'user' | 'assistant'; message: string; contentParts?: MessageContentPart[] }[]\n ) => Promise<void>;\n\n // Deep Research Options\n /**\n * @description 심층연구 콜백 (onWebSearch 필수)\n * @Todo vibecode - Perplexity 스타일 심층연구 기능\n */\n deepResearch?: DeepResearchCallbacks;\n\n // Poll Options\n /**\n * @description AI 주도 선택지 기능 활성화 (기본: true)\n * @Todo vibecode - AI가 자동으로 선택지를 제공하도록 시스템 프롬프트에 가이드 추가\n */\n enablePoll?: boolean;\n\n // Skills Options\n /**\n * @description 커스텀 스킬 등록\n * @Todo vibecode - AI가 자동/수동으로 활용하는 스킬 시스템\n */\n skills?: Record<string, SkillConfig>;\n\n // Tool Options\n /**\n * @description 도구 정의 목록 (호스트가 제공)\n * @Todo vibecode - AI가 자동으로 호출할 수 있는 도구 등록\n */\n tools?: ChatToolDefinition[];\n /**\n * @description 도구 실행 콜백 (호스트가 구현)\n * @Todo vibecode - 라이브러리가 도구 호출 판단 후 호스트에 실행 위임\n */\n onToolCall?: (name: string, params: Record<string, unknown>) => Promise<ToolCallResult>;\n\n // Project Options\n /**\n * @description 프로젝트 기능 활성화 여부 (기본: false)\n * @Todo vibecode - true 시 프로젝트 그룹핑, 지침, 메모리 계층 활성화\n */\n enableProjects?: boolean;\n /** @Todo vibecode - 프로젝트 목록 로드 콜백 */\n onLoadProjects?: () => Promise<{ id: string; title: string }[]>;\n /** @Todo vibecode - 프로젝트 생성 콜백 */\n onCreateProject?: (data: Partial<ChatProject>) => Promise<{ id: string; title: string }>;\n /** @Todo vibecode - 프로젝트 상세 로드 콜백 */\n onLoadProject?: (projectId: string) => Promise<ChatProject>;\n /** @Todo vibecode - 프로젝트 수정 콜백 */\n onUpdateProject?: (projectId: string, data: Partial<ChatProject>) => Promise<void>;\n /** @Todo vibecode - 프로젝트 삭제 콜백 */\n onDeleteProject?: (projectId: string) => Promise<void>;\n /** @Todo vibecode - 프로젝트 파일 추가 콜백 */\n onAddProjectFile?: (projectId: string, file: File) => Promise<ProjectFile>;\n /** @Todo vibecode - 프로젝트 파일 삭제 콜백 */\n onDeleteProjectFile?: (projectId: string, fileId: string) => Promise<void>;\n\n // Stream Control\n /**\n * @description 도구 실행 후 AI 스트리밍 계속 여부 (기본: true, 하위호환)\n * @Todo vibecode - false 시 도구 결과만 표시하고 AI 후속 응답 생략\n */\n continueAfterToolResult?: boolean;\n /**\n * @description 스킬 완료 시 콜백 (스트림 제어)\n * @Todo vibecode - 'continue' 반환 시 AI 응답 생성, 'stop' 반환 시 중단\n */\n onSkillComplete?: (skillName: string, result: SkillExecutionResult) => 'continue' | 'stop';\n\n // Dynamic Model Loading\n /**\n * @description 모델 목록 비동기 로드 콜백\n * @Todo vibecode - 제공 시 마운트 시 호출, 완료 전까지 models prop 사용\n */\n onLoadModels?: () => Promise<ModelConfig[]>;\n}\n\n// ============================================================================\n// Main Hook\n// ============================================================================\n\nexport const useChatUI = (options: UseChatUIOptions): UseChatUIReturn => {\n const {\n models,\n actions = [],\n initialPersonalization,\n apiKey,\n apiEndpoint = '/api/chat',\n initialModel,\n storageKey = DEFAULT_STORAGE_KEY,\n contextCompressionThreshold = DEFAULT_COMPRESSION_THRESHOLD,\n keepRecentMessages = DEFAULT_KEEP_RECENT,\n onSendMessage,\n onSessionChange,\n onError,\n onTitleChange,\n generateTitle: generateTitleCallback,\n // Memory options\n useGlobalMemoryEnabled = true,\n globalMemoryConfig,\n enableAutoExtraction: enableAutoExtractionProp,\n // External storage options\n useExternalStorage = false,\n onLoadSessions,\n onCreateSession,\n onLoadSession,\n onDeleteSession: onDeleteSessionCallback,\n onUpdateSessionTitle,\n onSaveMessages,\n // Deep Research options\n deepResearch,\n // Poll options\n enablePoll = true,\n // Skills options\n skills,\n // Tool options\n tools,\n onToolCall,\n // Project options\n enableProjects = false,\n onLoadProjects,\n onCreateProject,\n onLoadProject,\n onUpdateProject,\n onDeleteProject,\n onAddProjectFile,\n onDeleteProjectFile,\n // Stream control\n continueAfterToolResult = true,\n onSkillComplete,\n // Dynamic model loading\n onLoadModels,\n } = options;\n\n /** @Todo vibecode - 외부 스토리지 모드에서는 자동 추출 기본 비활성화 (404 방지) */\n const enableAutoExtraction = enableAutoExtractionProp ?? !useExternalStorage;\n\n // ============================================================================\n // State\n // ============================================================================\n\n const [sessions, setSessions] = useState<ChatSession[]>([]);\n const [currentSessionId, setCurrentSessionId] = useState<string | null>(null);\n const [input, setInput] = useState('');\n const [isLoading, setIsLoading] = useState(false);\n const [selectedModel, setSelectedModel] = useState(initialModel || models[0]?.id || '');\n const [sidebarOpen, setSidebarOpen] = useState(true);\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [quotedText, setQuotedText] = useState<string | null>(null);\n const [selectedAction, setSelectedAction] = useState<ActionItem | null>(null);\n const [copiedMessageId, setCopiedMessageId] = useState<string | null>(null);\n const [editingMessageId, setEditingMessageId] = useState<string | null>(null);\n const [personalization, setPersonalization] = useState<PersonalizationConfig>({\n ...DEFAULT_PERSONALIZATION,\n ...initialPersonalization,\n });\n const [activeAlternatives, setActiveAlternatives] = useState<Record<string, number>>({});\n /**\n * @description 다른 모델 응답 생성 중인 메시지 ID\n * @Todo vibecode - 로딩 인디케이터 표시용\n */\n const [loadingAlternativeFor, setLoadingAlternativeFor] = useState<string | null>(null);\n\n /**\n * @description 외부 스토리지 로딩 상태\n * @Todo vibecode - 세션 목록 로드 중\n */\n const [isSessionsLoading, setIsSessionsLoading] = useState(false);\n /**\n * @description 외부 스토리지 로딩 상태\n * @Todo vibecode - 단일 세션 로드 중\n */\n const [isSessionLoading, setIsSessionLoading] = useState(false);\n\n /**\n * @description 심층연구 모드 활성화 여부\n * @Todo vibecode - 심층연구 버튼 토글 상태\n */\n const [isDeepResearchMode, setIsDeepResearchMode] = useState(false);\n\n /**\n * @description 첨부파일 상태 (이미지/파일)\n * @Todo vibecode - 입력창 파일 첨부 상태 관리\n */\n const [attachments, setAttachments] = useState<ChatAttachment[]>([]);\n\n /**\n * @description 모델 목록 동적 로드 상태\n * @Todo vibecode - onLoadModels 제공 시 비동기 모델 목록 관리\n */\n const [isModelsLoading, setIsModelsLoading] = useState(false);\n const [loadedModels, setLoadedModels] = useState<ModelConfig[] | null>(null);\n\n /**\n * @description 심층연구 진행 상태\n * @Todo vibecode - 4단계 심층연구 프로세스 상태\n */\n const [deepResearchProgress, setDeepResearchProgress] = useState<DeepResearchProgress | null>(\n null\n );\n\n /** @Todo vibecode - 최신 sessions 접근용 ref (stale closure 방지) */\n const sessionsRef = useRef(sessions);\n useEffect(() => { sessionsRef.current = sessions; }, [sessions]);\n\n // ============================================================================\n // Callback Refs (stale closure 방지)\n // ============================================================================\n\n /** @Todo vibecode - 외부 콜백 useRef 래핑 (Provider 리렌더 시 참조 안정성 보장) */\n const onSendMessageRef = useRef(onSendMessage);\n const onSessionChangeRef = useRef(onSessionChange);\n const onErrorRef = useRef(onError);\n const onTitleChangeRef = useRef(onTitleChange);\n const generateTitleRef = useRef(generateTitleCallback);\n const onPersonalizationChangeRef = useRef(options.onPersonalizationChange);\n const onPersonalizationSaveRef = useRef(options.onPersonalizationSave);\n const onLoadSessionsRef = useRef(onLoadSessions);\n const onCreateSessionRef = useRef(onCreateSession);\n const onLoadSessionRef = useRef(onLoadSession);\n const onDeleteSessionCallbackRef = useRef(onDeleteSessionCallback);\n const onUpdateSessionTitleRef = useRef(onUpdateSessionTitle);\n const onSaveMessagesRef = useRef(onSaveMessages);\n const onToolCallRef = useRef(onToolCall);\n const onSkillCompleteRef = useRef(onSkillComplete);\n const onLoadModelsRef = useRef(onLoadModels);\n\n /** @Todo vibecode - 매 렌더 시 ref.current 동기화 (deps 없는 useEffect) */\n useEffect(() => {\n onSendMessageRef.current = onSendMessage;\n onSessionChangeRef.current = onSessionChange;\n onErrorRef.current = onError;\n onTitleChangeRef.current = onTitleChange;\n generateTitleRef.current = generateTitleCallback;\n onPersonalizationChangeRef.current = options.onPersonalizationChange;\n onPersonalizationSaveRef.current = options.onPersonalizationSave;\n onLoadSessionsRef.current = onLoadSessions;\n onCreateSessionRef.current = onCreateSession;\n onLoadSessionRef.current = onLoadSession;\n onDeleteSessionCallbackRef.current = onDeleteSessionCallback;\n onUpdateSessionTitleRef.current = onUpdateSessionTitle;\n onSaveMessagesRef.current = onSaveMessages;\n onToolCallRef.current = onToolCall;\n onSkillCompleteRef.current = onSkillComplete;\n onLoadModelsRef.current = onLoadModels;\n });\n\n const abortControllerRef = useRef<AbortController | null>(null);\n\n /**\n * @description Poll 응답 후 다음 AI 응답에서 poll 파싱 스킵 여부\n * @Todo vibecode - 사용자가 poll에 응답한 직후 AI가 또 poll을 생성하는 것을 방지\n */\n const skipNextPollParsingRef = useRef(false);\n\n /**\n * @description Skill 실행 후 다음 AI 응답에서 skill_use 파싱 스킵 여부\n * @Todo vibecode - 스킬 결과 전달 후 AI가 또 스킬을 호출하는 무한루프 방지\n */\n const skipNextSkillParsingRef = useRef(false);\n\n /**\n * @description 마지막 정보 추출 시점의 메시지 수\n * @Todo vibecode - 주기적 정보 추출 트리거용\n */\n const lastExtractionMsgCountRef = useRef(0);\n\n // ============================================================================\n // Memory Hooks\n // ============================================================================\n\n // 글로벌 메모리 설정\n const memoryOptions = useMemo(\n () => ({\n storageType: globalMemoryConfig?.storageType || 'localStorage',\n storageKey: globalMemoryConfig?.localStorage?.key || `${storageKey}_memory`,\n apiEndpoint: globalMemoryConfig?.postgresql?.apiEndpoint,\n userId: globalMemoryConfig?.postgresql?.userId,\n authToken: globalMemoryConfig?.postgresql?.authToken,\n }),\n [globalMemoryConfig, storageKey]\n );\n\n const globalMemory = useGlobalMemoryEnabled ? useGlobalMemory(memoryOptions) : null;\n\n // ============================================================================\n // Skills Hook\n // ============================================================================\n\n /**\n * @description Tools → Skills 병합 (도구가 같은 이름의 스킬 덮어씀)\n * @Todo vibecode - tools + skills 통합\n */\n /** @Todo vibecode - onToolCallRef 래핑으로 콜백 안정성 보장 */\n const stableToolCall = useCallback(\n (name: string, params: Record<string, unknown>) => onToolCallRef.current!(name, params),\n []\n );\n const mergedSkills = useMemo(() => {\n if (!tools || !onToolCall) return skills || {};\n const toolSkills = convertToolsToSkills(tools, stableToolCall);\n return { ...(skills || {}), ...toolSkills };\n }, [skills, tools, !!onToolCall, stableToolCall]);\n\n const {\n buildSkillsPrompt,\n handleSkillCall,\n manualSkills,\n executeManualSkill,\n activeSkillExecution,\n resolvedSkills,\n } = useSkills({\n skills: mergedSkills,\n deepResearch,\n });\n\n // ============================================================================\n // Project Hook\n // ============================================================================\n\n /** @Todo vibecode - 항상 호출 (Hook 규칙 준수), enabled로 내부 활성화 제어 */\n const projectHook = useProject({\n enabled: enableProjects,\n useExternalStorage,\n storageKey: `${storageKey}_projects`,\n onLoadProjects,\n onCreateProject,\n onLoadProject,\n onUpdateProject,\n onDeleteProject,\n onAddProjectFile,\n onDeleteProjectFile,\n onError,\n });\n\n /**\n * @description 프로젝트 설정 모달 열림 상태\n * @Todo vibecode - 프로젝트 설정 UI\n */\n const [projectSettingsOpen, setProjectSettingsOpen] = useState(false);\n\n /**\n * @description 프로젝트 메모리 (계층형 3-tier 중 프로젝트 레벨)\n * @Todo vibecode - currentProjectId 기반 스코프 키로 useGlobalMemory 재활용\n * Hook 규칙 때문에 항상 호출하되 키에 projectId 포함\n */\n const projectMemoryKey = enableProjects && projectHook.currentProjectId\n ? `${storageKey}_project_memory_${projectHook.currentProjectId}`\n : `${storageKey}_project_memory_none`;\n\n const projectMemoryOptions = useMemo(\n () => ({\n storageType: globalMemoryConfig?.storageType || 'localStorage',\n storageKey: projectMemoryKey,\n apiEndpoint: globalMemoryConfig?.postgresql?.apiEndpoint,\n userId: globalMemoryConfig?.postgresql?.userId,\n authToken: globalMemoryConfig?.postgresql?.authToken,\n }),\n [globalMemoryConfig, projectMemoryKey]\n );\n\n /** @Todo vibecode - 항상 호출 (Hook 규칙 준수), enableProjects=false이면 noop 키 사용 */\n const projectMemoryRaw = useGlobalMemory(projectMemoryOptions);\n const projectMemory = enableProjects ? projectMemoryRaw : null;\n\n // ============================================================================\n // Internal LLM Call (압축/추출용)\n // ============================================================================\n\n /**\n * @description 내부 LLM 호출 유틸 (압축, 정보 추출 등)\n * @Todo vibecode - onSendMessage 모드에서도 내부 LLM 호출 지원\n * apiEndpoint 없이 onSendMessage만 제공한 경우 호스트 콜백 재활용\n */\n const callInternalLLM = useCallback(async (prompt: string, model: string): Promise<string> => {\n if (onSendMessageRef.current) {\n const modelConfig = models.find((m) => m.id === model);\n const provider = modelConfig?.provider || 'ollama';\n\n const result = await onSendMessageRef.current({\n messages: [{ role: 'user', content: prompt }],\n model,\n provider,\n apiKey,\n });\n\n if (typeof result === 'string') return result;\n if (typeof result === 'object' && 'content' in result) return result.content;\n /** @Todo vibecode - ReadableStream 반환 시 SSE 파싱 */\n return parseSSEResponse(new Response(result as ReadableStream<Uint8Array>));\n }\n\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [{ role: 'user', content: prompt }],\n model,\n }),\n });\n if (!response.ok) return '';\n return parseSSEResponse(response);\n }, [apiEndpoint, apiKey, models]);\n\n // 정보 추출 설정\n const infoExtraction = useInfoExtraction({\n apiEndpoint,\n model: selectedModel,\n minConfidence: 0.8,\n globalMemory: globalMemory!,\n onCallLLM: callInternalLLM,\n });\n\n // ============================================================================\n // Derived State\n // ============================================================================\n\n const currentSession = sessions.find((s) => s.id === currentSessionId) || null;\n /** @description UI에 표시할 메시지 (hidden 제외) */\n const messages = currentSession?.messages.filter((m) => !m.hidden) || [];\n const compressionState = currentSession?.compressionState || null;\n\n /**\n * @description 프로젝트별 세션 필터링\n * @Todo vibecode - enableProjects 시 현재 프로젝트 소속 세션만 표시\n */\n const visibleSessions = useMemo(() => {\n if (!enableProjects || !projectHook.currentProjectId) return sessions;\n return sessions.filter((s) => s.projectId === projectHook.currentProjectId);\n }, [sessions, enableProjects, projectHook.currentProjectId]);\n\n // ============================================================================\n // Persistence\n // ============================================================================\n\n /**\n * @description 초기 세션 로드\n * @Todo vibecode - 외부 스토리지 사용 시 onLoadSessions 콜백 호출\n */\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n // 외부 스토리지 사용 시 콜백으로 세션 목록 로드\n if (useExternalStorage && onLoadSessionsRef.current) {\n setIsSessionsLoading(true);\n onLoadSessionsRef.current()\n .then((sessionList) => {\n // 세션 목록만 로드 (메시지는 selectSession에서 lazy load)\n const sessionsWithoutMessages: ChatSession[] = sessionList.map((s) => ({\n id: s.id,\n title: s.title,\n messages: [], // 메시지는 세션 선택 시 로드\n model: initialModel || models[0]?.id || '',\n createdAt: Date.now(),\n updatedAt: Date.now(),\n }));\n setSessions(sessionsWithoutMessages);\n /** @Todo vibecode - initialSessionId 우선 선택, 없으면 첫 번째 세션 */\n if (sessionsWithoutMessages.length > 0) {\n const targetId = options.initialSessionId && sessionsWithoutMessages.some(s => s.id === options.initialSessionId)\n ? options.initialSessionId\n : sessionsWithoutMessages[0].id;\n setCurrentSessionId(targetId);\n }\n })\n .catch((error) => {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to load sessions'));\n })\n .finally(() => {\n setIsSessionsLoading(false);\n });\n\n /** @Todo vibecode - 개인화 설정은 localStorage에서 로드 (외부 스토리지 모드에서도) */\n if (typeof window !== 'undefined') {\n const savedPersonalization = localStorage.getItem(`${storageKey}_personalization`);\n if (savedPersonalization) {\n try {\n setPersonalization(JSON.parse(savedPersonalization));\n } catch {\n // Ignore parse errors\n }\n }\n }\n return;\n }\n\n /** @Todo vibecode - enableProjects 시 기존 세션 마이그레이션 */\n if (enableProjects) {\n migrateSessionsToProjects(storageKey);\n }\n\n // 기존 localStorage 로직\n if (typeof window === 'undefined') return;\n const saved = localStorage.getItem(storageKey);\n if (saved) {\n try {\n const parsed = JSON.parse(saved) as ChatSession[];\n setSessions(parsed);\n /** @Todo vibecode - initialSessionId 우선 선택, 없으면 첫 번째 세션 */\n if (parsed.length > 0) {\n const targetSession = options.initialSessionId\n ? parsed.find(s => s.id === options.initialSessionId)\n : null;\n const selected = targetSession || parsed[0];\n setCurrentSessionId(selected.id);\n setSelectedModel(selected.model);\n }\n } catch {\n // Ignore parse errors\n }\n }\n\n const savedPersonalization = localStorage.getItem(`${storageKey}_personalization`);\n if (savedPersonalization) {\n try {\n setPersonalization(JSON.parse(savedPersonalization));\n } catch {\n // Ignore parse errors\n }\n }\n }, [storageKey, useExternalStorage, initialModel, models]);\n\n /**\n * @description 모델 목록 비동기 로드\n * @Todo vibecode - onLoadModels 제공 시 마운트 시 호출\n */\n useEffect(() => {\n if (!onLoadModelsRef.current) return;\n setIsModelsLoading(true);\n onLoadModelsRef.current()\n .then((modelList) => {\n setLoadedModels(modelList);\n if (modelList.length > 0 && !modelList.find((m) => m.id === selectedModel)) {\n setSelectedModel(modelList[0].id);\n }\n })\n .catch((error) => {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to load models'));\n })\n .finally(() => {\n setIsModelsLoading(false);\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n /** @Todo vibecode - 동적 로드 모델 우선, 없으면 props.models 사용 */\n const effectiveModels = loadedModels || models;\n\n /**\n * @description 세션 자동 저장\n * @Todo vibecode - 외부 스토리지 사용 시 localStorage 저장 스킵\n */\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n // 외부 스토리지 사용 시 localStorage 저장 스킵\n if (useExternalStorage) return;\n\n if (sessions.length > 0) {\n localStorage.setItem(storageKey, JSON.stringify(sessions));\n }\n }, [sessions, storageKey, useExternalStorage]);\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n localStorage.setItem(`${storageKey}_personalization`, JSON.stringify(personalization));\n }, [personalization, storageKey]);\n\n // ============================================================================\n // Session Change Callback\n // ============================================================================\n\n useEffect(() => {\n onSessionChangeRef.current?.(currentSession);\n }, [currentSession]);\n\n // ============================================================================\n // System Prompt Builder\n // ============================================================================\n\n const buildSystemPrompt = useCallback((): string => {\n const parts: string[] = [];\n const { userProfile, responseStyle, language } = personalization;\n\n /** @Todo vibecode - 닉네임 뒤 '님' 호칭 + 존대말 기본 지시 */\n if (userProfile.nickname) {\n parts.push(`사용자의 이름/닉네임: ${userProfile.nickname}님 (항상 '님'을 붙여서 호칭하고, 존대말(합쇼체/해요체)로 응답해주세요)`);\n }\n if (userProfile.occupation) {\n parts.push(`사용자의 직업: ${userProfile.occupation}`);\n }\n if (userProfile.additionalInfo) {\n parts.push(`사용자 추가 정보: ${userProfile.additionalInfo}`);\n }\n\n const styleDescriptions: string[] = [];\n if (responseStyle.warmth === 'high') styleDescriptions.push('따뜻하고 친근하게');\n else if (responseStyle.warmth === 'low') styleDescriptions.push('간결하고 사무적으로');\n\n if (responseStyle.enthusiasm === 'high') styleDescriptions.push('열정적이고 적극적으로');\n else if (responseStyle.enthusiasm === 'low') styleDescriptions.push('차분하게');\n\n if (responseStyle.emojiUsage === 'high') styleDescriptions.push('이모지를 적극 활용해서');\n else if (responseStyle.emojiUsage === 'low') styleDescriptions.push('이모지 사용을 자제해서');\n\n if (responseStyle.verbosity === 'concise') styleDescriptions.push('핵심만 간결하게');\n else if (responseStyle.verbosity === 'detailed') styleDescriptions.push('상세하고 자세하게');\n\n if (styleDescriptions.length > 0) {\n parts.push(`응답 스타일: ${styleDescriptions.join(', ')} 응답해주세요.`);\n }\n\n if (language !== 'auto') {\n const languageNames: Record<string, string> = { ko: '한국어', en: '영어', ja: '일본어' };\n parts.push(`응답 언어: ${languageNames[language] || language}로 응답해주세요.`);\n }\n\n // 글로벌 메모리 컨텍스트 추가\n if (useGlobalMemoryEnabled && globalMemory && personalization.useMemory) {\n const memoryContext = globalMemory.toPromptContext();\n if (memoryContext) {\n parts.push('');\n parts.push(memoryContext);\n }\n }\n\n /**\n * @description 프로젝트 지침 + 프로젝트 메모리 주입\n * @Todo vibecode - 계층형 메모리: Global → Project → Session\n */\n if (enableProjects && projectHook.currentProject) {\n if (projectHook.currentProject.instructions) {\n parts.push('');\n parts.push(`[프로젝트 지침]\\n${projectHook.currentProject.instructions}`);\n }\n if (projectMemory) {\n const projectMemoryContext = projectMemory.toPromptContext();\n if (projectMemoryContext) {\n parts.push('');\n parts.push(`[프로젝트 기억]\\n${projectMemoryContext}`);\n }\n }\n }\n\n // 스킬 가이드 추가\n const skillsPrompt = buildSkillsPrompt();\n if (skillsPrompt) {\n parts.push('');\n parts.push(skillsPrompt);\n }\n\n // Poll 기능 가이드 추가 (Claude Code 스타일)\n if (enablePoll) {\n parts.push('');\n parts.push(`## 선택지 질문 기능\n\n사용자 요청에 명확화가 필요하면 <poll> 태그로 질문하세요.\n**중요: 필요한 모든 질문을 한 번에 작성하세요. 질문을 나눠서 하지 마세요.**\n\n**예시 - 3개 질문을 한 번에:**\n<poll question=\"로고 용도는?\" multiSelect=\"false\">\n- 서비스/앱: 디지털 서비스용\n- 브랜드: 회사 아이덴티티\n- 개인: 개인 프로젝트\n</poll>\n\n<poll question=\"선호하는 스타일은?\" multiSelect=\"true\">\n- 미니멀: 심플하고 깔끔한\n- 모던: 트렌디하고 세련된\n- 클래식: 전통적이고 신뢰감 있는\n</poll>\n\n<poll question=\"주요 색상은?\" multiSelect=\"false\">\n- 블루 계열: 신뢰, 전문성\n- 그린 계열: 성장, 친환경\n- 다크 계열: 고급, 세련됨\n</poll>\n\n**규칙:**\n- 필요한 질문 1~3개를 **한 번에 모두** 작성\n- 각 질문은 서로 다른 내용\n- 옵션마다 짧은 설명 포함\n- 사용자가 모두 선택 후 진행`);\n }\n\n return parts.length > 0 ? parts.join('\\n') : '';\n }, [personalization, globalMemory, useGlobalMemoryEnabled, enablePoll, buildSkillsPrompt, enableProjects, projectHook.currentProject, projectMemory]);\n\n // ============================================================================\n // Context Compression\n // ============================================================================\n\n const compressContext = useCallback(async (\n messagesToCompress: ChatMessage[],\n model: string\n ): Promise<string> => {\n const conversationText = messagesToCompress\n .map((m) => `${m.role === 'user' ? '사용자' : 'AI'}: ${m.content}`)\n .join('\\n\\n');\n\n const summaryPrompt = `다음 대화 내용을 핵심 정보만 유지하면서 간결하게 요약해주세요.\n중요한 결정사항, 사용자 요구사항, 맥락 정보를 보존하세요.\n\n대화:\n${conversationText}\n\n요약:`;\n\n try {\n return await callInternalLLM(summaryPrompt, model);\n } catch {\n return '';\n }\n }, [callInternalLLM]);\n\n /**\n * @description 점진적 압축 - 기존 요약과 새 대화를 통합\n * @param existingSummary 기존 요약\n * @param newMessages 새로 추가된 메시지들\n * @param model 사용할 모델\n */\n const incrementalCompressContext = useCallback(\n async (\n existingSummary: string,\n newMessages: ChatMessage[],\n model: string\n ): Promise<string> => {\n const newConversation = newMessages\n .map((m) => `${m.role === 'user' ? '사용자' : 'AI'}: ${m.content}`)\n .join('\\n\\n');\n\n const mergePrompt = `기존 대화 요약과 새로운 대화 내용을 통합하여 하나의 요약으로 만들어주세요.\n\n[기존 요약]\n${existingSummary}\n\n[새로운 대화]\n${newConversation}\n\n통합 요약 작성 시 다음을 지켜주세요:\n1. 핵심 결정사항, 사용자 요구사항, 맥락 정보 보존\n2. 중복 정보 제거\n3. 시간순 흐름 유지\n4. 300자 이내로 간결하게\n\n통합 요약:`;\n\n try {\n const summary = await callInternalLLM(mergePrompt, model);\n return summary || existingSummary;\n } catch {\n return existingSummary;\n }\n },\n [callInternalLLM]\n );\n\n /**\n * @description 토큰 수 추정 (문자 길이 / 4)\n */\n const estimateTokens = useCallback((messages: ChatMessage[]): number => {\n return messages.reduce((sum, m) => sum + Math.ceil(m.content.length / 4), 0);\n }, []);\n\n // ============================================================================\n // Actions\n // ============================================================================\n\n /**\n * @description 새 세션 생성\n * @Todo vibecode - 외부 스토리지 사용 시 onCreateSession 콜백 호출\n */\n const newSession = useCallback(async () => {\n /** @Todo vibecode - 현재 프로젝트 ID (enableProjects 시 할당) */\n const projectId = enableProjects\n ? (projectHook.currentProjectId || DEFAULT_PROJECT_ID)\n : undefined;\n\n // 외부 스토리지 사용 시 콜백으로 세션 생성\n if (useExternalStorage && onCreateSessionRef.current) {\n setIsSessionLoading(true);\n try {\n const created = await onCreateSessionRef.current();\n const now = Date.now();\n const newSess: ChatSession = {\n id: created.id,\n title: created.title,\n messages: [],\n model: selectedModel,\n createdAt: now,\n updatedAt: now,\n ...(projectId && { projectId }),\n };\n setSessions((prev) => [newSess, ...prev]);\n setCurrentSessionId(newSess.id);\n } catch (error) {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to create session'));\n } finally {\n setIsSessionLoading(false);\n }\n return;\n }\n\n // 기존 로직\n const now = Date.now();\n const newSess: ChatSession = {\n id: generateId('session'),\n title: '새 대화',\n messages: [],\n model: selectedModel,\n createdAt: now,\n updatedAt: now,\n ...(projectId && { projectId }),\n };\n setSessions((prev) => [newSess, ...prev]);\n setCurrentSessionId(newSess.id);\n }, [selectedModel, useExternalStorage, enableProjects, projectHook.currentProjectId]);\n\n /**\n * @description 세션 선택\n * @Todo vibecode - 외부 스토리지 사용 시 onLoadSession 콜백 호출 (lazy loading)\n */\n const selectSession = useCallback(async (id: string) => {\n // 외부 스토리지 사용 시 세션 상세 로드\n if (useExternalStorage && onLoadSessionRef.current) {\n setIsSessionLoading(true);\n try {\n const sessionDetail = await onLoadSessionRef.current(id);\n\n /**\n * @description role 및 content 형식 변환\n * @Todo vibecode - API 응답 형식(message) -> 내부 형식(content) 변환\n */\n let loadedMessages: ChatMessage[] = sessionDetail.messages.map((m, idx) => ({\n id: m.id || generateId('msg'),\n role: (typeof m.role === 'string' ? m.role.toLowerCase() : m.role) as 'user' | 'assistant' | 'system',\n // API는 message 필드, 내부는 content 필드 사용\n content: m.content || m.message || '',\n timestamp: m.created_at ? new Date(m.created_at).getTime() : Date.now() - (sessionDetail.messages.length - idx) * 1000,\n model: (m as ChatMessage).model,\n alternatives: (m as ChatMessage).alternatives,\n sources: (m as ChatMessage).sources,\n /** @Todo vibecode - 백엔드에서 전달받은 contentParts 복원 (이미지/파일 등) */\n ...(m.contentParts && { contentParts: m.contentParts }),\n }));\n\n /**\n * @description 빈 응답 시 localStorage 캐시 fallback\n * @Todo vibecode - 서버가 빈 messages 반환 시 캐시에서 복원\n */\n let resolvedTitle = sessionDetail.title;\n if (loadedMessages.length === 0) {\n const cached = readSessionCache(storageKey, id);\n if (cached && cached.messages.length > 0) {\n console.warn('[useChatUI] Server returned empty messages, using localStorage cache');\n loadedMessages = cached.messages;\n if (!resolvedTitle && cached.title) {\n resolvedTitle = cached.title;\n }\n }\n }\n\n setSessions((prev) =>\n prev.map((s) =>\n s.id === id\n ? { ...s, title: resolvedTitle, messages: loadedMessages, updatedAt: Date.now() }\n : s\n )\n );\n setCurrentSessionId(id);\n\n /**\n * @description 성공적으로 로드된 세션을 캐시에 저장\n * @Todo vibecode - 다음 번 fallback 시 사용할 최신 데이터 보장\n */\n if (loadedMessages.length > 0) {\n const existingSession = sessions.find((s) => s.id === id);\n writeSessionCache(storageKey, {\n id,\n title: resolvedTitle,\n messages: loadedMessages,\n model: existingSession?.model || initialModel || models[0]?.id || '',\n createdAt: existingSession?.createdAt || Date.now(),\n updatedAt: Date.now(),\n });\n }\n\n // 세션의 모델 설정\n const existingSession = sessions.find((s) => s.id === id);\n if (existingSession) {\n setSelectedModel(existingSession.model);\n }\n } catch (error) {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to load session'));\n\n /**\n * @description onLoadSession 에러 시 localStorage 캐시 fallback\n * @Todo vibecode - 서버 장애 시에도 이전 대화 복원\n */\n const cached = readSessionCache(storageKey, id);\n if (cached && cached.messages.length > 0) {\n console.warn('[useChatUI] onLoadSession failed, using localStorage cache');\n setSessions((prev) =>\n prev.map((s) =>\n s.id === id\n ? { ...s, title: cached.title || s.title, messages: cached.messages, updatedAt: Date.now() }\n : s\n )\n );\n setCurrentSessionId(id);\n const existingSession = sessions.find((s) => s.id === id);\n if (existingSession) {\n setSelectedModel(existingSession.model);\n }\n }\n } finally {\n setIsSessionLoading(false);\n }\n return;\n }\n\n // 기존 로직\n const session = sessions.find((s) => s.id === id);\n if (session) {\n setCurrentSessionId(id);\n setSelectedModel(session.model);\n }\n }, [sessions, useExternalStorage, storageKey, initialModel, models]);\n\n /**\n * @description 세션 삭제\n * @Todo vibecode - 외부 스토리지 사용 시 onDeleteSession 콜백 호출\n */\n const deleteSession = useCallback(async (id: string) => {\n // 외부 스토리지 사용 시 콜백으로 삭제\n if (useExternalStorage && onDeleteSessionCallbackRef.current) {\n try {\n await onDeleteSessionCallbackRef.current(id);\n /** @Todo vibecode - localStorage 캐시도 함께 삭제 */\n removeSessionCache(storageKey, id);\n setSessions((prev) => {\n const filtered = prev.filter((s) => s.id !== id);\n if (currentSessionId === id) {\n setCurrentSessionId(filtered.length > 0 ? filtered[0].id : null);\n }\n return filtered;\n });\n } catch (error) {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to delete session'));\n }\n return;\n }\n\n // 기존 로직\n setSessions((prev) => {\n const filtered = prev.filter((s) => s.id !== id);\n if (currentSessionId === id) {\n setCurrentSessionId(filtered.length > 0 ? filtered[0].id : null);\n }\n if (filtered.length === 0 && typeof window !== 'undefined') {\n localStorage.removeItem(storageKey);\n }\n return filtered;\n });\n }, [currentSessionId, storageKey, useExternalStorage]);\n\n /**\n * @description 세션 제목 변경\n * @Todo vibecode - 외부 스토리지 사용 시 onUpdateSessionTitle 콜백 호출\n */\n const renameSession = useCallback(async (id: string, newTitle: string) => {\n if (!newTitle.trim()) return;\n\n // 외부 스토리지 사용 시 콜백으로 제목 변경\n if (useExternalStorage && onUpdateSessionTitleRef.current) {\n try {\n await onUpdateSessionTitleRef.current(id, newTitle.trim());\n setSessions((prev) =>\n prev.map((s) =>\n s.id === id ? { ...s, title: newTitle.trim(), updatedAt: Date.now() } : s\n )\n );\n onTitleChangeRef.current?.(id, newTitle.trim());\n } catch (error) {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to update session title'));\n }\n return;\n }\n\n // 기존 로직\n setSessions((prev) =>\n prev.map((s) =>\n s.id === id ? { ...s, title: newTitle.trim(), updatedAt: Date.now() } : s\n )\n );\n onTitleChangeRef.current?.(id, newTitle.trim());\n }, [useExternalStorage]);\n\n const setModel = useCallback((model: string) => {\n setSelectedModel(model);\n if (currentSessionId) {\n setSessions((prev) =>\n prev.map((s) => (s.id === currentSessionId ? { ...s, model } : s))\n );\n }\n }, [currentSessionId]);\n\n const toggleSidebar = useCallback(() => setSidebarOpen((prev) => !prev), []);\n const openSettings = useCallback(() => setSettingsOpen(true), []);\n const closeSettings = useCallback(() => setSettingsOpen(false), []);\n\n const copyMessage = useCallback((content: string, id: string) => {\n if (typeof navigator !== 'undefined') {\n navigator.clipboard.writeText(content).then(() => {\n setCopiedMessageId(id);\n setTimeout(() => setCopiedMessageId(null), 2000);\n });\n }\n }, []);\n\n const startEdit = useCallback((message: ChatMessage) => {\n if (message.role === 'user') {\n setEditingMessageId(message.id);\n }\n }, []);\n\n const cancelEdit = useCallback(() => {\n setEditingMessageId(null);\n }, []);\n\n const stopGeneration = useCallback(() => {\n abortControllerRef.current?.abort();\n }, []);\n\n /**\n * @description 개인화 설정 업데이트 + 외부 콜백 호출\n * @Todo vibecode - 로컬 상태 업데이트 후 onPersonalizationChange로 백엔드 저장 트리거\n */\n const updatePersonalization = useCallback((config: Partial<PersonalizationConfig>) => {\n setPersonalization((prev) => {\n const next = { ...prev, ...config };\n onPersonalizationChangeRef.current?.(next);\n return next;\n });\n }, []);\n\n /**\n * @description 개인화 설정 저장 (저장 버튼 클릭 시)\n * @Todo vibecode - onPersonalizationSave 콜백 1회 호출\n */\n const savePersonalization = useCallback(() => {\n onPersonalizationSaveRef.current?.(personalization);\n }, [personalization]);\n\n /**\n * @description 파일 첨부 추가 (File[] → ChatAttachment[] 변환)\n * @Todo vibecode - 이미지는 URL.createObjectURL로 프리뷰 생성\n */\n const addAttachments = useCallback((files: File[]) => {\n const newAttachments: ChatAttachment[] = files.map((file) => {\n const isImage = file.type.startsWith('image/');\n return {\n id: generateId('attach'),\n file,\n name: file.name,\n type: isImage ? 'image' : 'file',\n previewUrl: isImage ? URL.createObjectURL(file) : undefined,\n mimeType: file.type,\n size: file.size,\n };\n });\n setAttachments((prev) => [...prev, ...newAttachments]);\n }, []);\n\n /**\n * @description 첨부파일 제거 (objectURL 해제 포함)\n * @Todo vibecode - 프리뷰에서 X 버튼 클릭 시\n */\n const removeAttachment = useCallback((id: string) => {\n setAttachments((prev) => {\n const target = prev.find((a) => a.id === id);\n if (target?.previewUrl) {\n URL.revokeObjectURL(target.previewUrl);\n }\n return prev.filter((a) => a.id !== id);\n });\n }, []);\n\n /**\n * @description 심층연구 모드 토글\n * @Todo vibecode - 심층연구 버튼 클릭 핸들러\n */\n const toggleDeepResearchMode = useCallback(() => {\n setIsDeepResearchMode((prev) => !prev);\n }, []);\n\n // ============================================================================\n // Send Message\n // ============================================================================\n\n const sendMessage = useCallback(async (content?: string, options?: { hiddenUserMessage?: boolean }) => {\n const messageContent = content || input;\n /** @Todo vibecode - 텍스트 없이 첨부파일만 전송 허용 */\n if ((!messageContent.trim() && attachments.length === 0) || isLoading) return;\n\n /** @Todo vibecode - 중복 전송 방지: entry guard 직후 즉시 로딩 상태 전환 */\n setIsLoading(true);\n\n let sessionId = currentSessionId;\n if (!sessionId) {\n /**\n * @description 세션 없이 메시지 전송 시 자동 세션 생성\n * @Todo vibecode - useExternalStorage 모드에서 onCreateSession 콜백 호출 보장\n */\n if (useExternalStorage && onCreateSessionRef.current) {\n try {\n const created = await onCreateSessionRef.current();\n const now = Date.now();\n const newSess: ChatSession = {\n id: created.id,\n title: created.title,\n messages: [],\n model: selectedModel,\n createdAt: now,\n updatedAt: now,\n };\n setSessions((prev) => [newSess, ...prev]);\n sessionId = newSess.id;\n setCurrentSessionId(sessionId);\n } catch (error) {\n onErrorRef.current?.(error instanceof Error ? error : new Error('Failed to create session'));\n setIsLoading(false);\n return;\n }\n } else {\n const now = Date.now();\n const newSess: ChatSession = {\n id: generateId('session'),\n title: '새 대화',\n messages: [],\n model: selectedModel,\n createdAt: now,\n updatedAt: now,\n };\n setSessions((prev) => [newSess, ...prev]);\n sessionId = newSess.id;\n setCurrentSessionId(sessionId);\n }\n }\n\n // 메시지 조합\n let finalContent = messageContent.trim();\n if (quotedText) {\n finalContent = `\"${quotedText}\"\\n\\n${finalContent}`;\n }\n if (selectedAction) {\n finalContent = `[${selectedAction.label}] ${finalContent}`;\n }\n\n const actionPrompt = selectedAction?.systemPrompt;\n const isHidden = options?.hiddenUserMessage ?? false;\n\n /**\n * @description 첨부파일 → contentParts 변환\n * @Todo vibecode - 텍스트 + 이미지/파일을 contentParts 배열로 구성\n */\n const currentAttachments = attachments;\n let userContentParts: MessageContentPart[] | undefined;\n if (currentAttachments.length > 0) {\n userContentParts = [];\n if (finalContent.trim()) {\n userContentParts.push({ type: 'text', content: finalContent });\n }\n for (const att of currentAttachments) {\n if (att.type === 'image' && att.previewUrl) {\n userContentParts.push({ type: 'image', url: att.previewUrl, alt: att.name });\n } else {\n userContentParts.push({ type: 'file', name: att.name, url: att.previewUrl || '', mimeType: att.mimeType, size: att.size });\n }\n }\n }\n\n const userMessage: ChatMessage = {\n id: generateId('msg'),\n role: 'user',\n content: finalContent,\n timestamp: Date.now(),\n ...(isHidden && { hidden: true }),\n ...(userContentParts && { contentParts: userContentParts }),\n };\n\n /**\n * @description 세션 상태 캡처 + 메시지 추가 (attachment 스킬 실행 전)\n * @Todo vibecode - React 상태 업데이트는 비동기이므로 setSessions 이전에 기존 상태 캡처 필수\n */\n const capturedSessionId = sessionId;\n const currentSession = sessions.find((s) => s.id === capturedSessionId);\n const existingMessages = currentSession?.messages || [];\n const isFirstMessage = !existingMessages.length;\n const contextSummary = currentSession?.compressionState?.contextSummary || currentSession?.contextSummary;\n const summaryAfterIndex = currentSession?.compressionState?.summaryAfterIndex || currentSession?.summaryAfterIndex || 0;\n let compressionCount = currentSession?.compressionState?.compressionCount || 0;\n\n const assistantMessageId = generateId('msg');\n const assistantMessage: ChatMessage = {\n id: assistantMessageId,\n role: 'assistant',\n content: '',\n model: selectedModel,\n timestamp: Date.now(),\n };\n\n // Clear input state\n setInput('');\n setQuotedText(null);\n setSelectedAction(null);\n setAttachments([]);\n\n // Add messages to session\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n const newMessages = [...s.messages, userMessage, assistantMessage];\n return {\n ...s,\n messages: newMessages,\n title: s.messages.length === 0 ? generateTitle([userMessage]) : s.title,\n updatedAt: Date.now(),\n };\n }\n return s;\n })\n );\n\n /**\n * @description attachment trigger 스킬 자동 실행 (로딩 → 완료 UI 전환 포함)\n * @Todo vibecode - 파일 첨부 시 trigger:'attachment' 스킬 찾아서 File 객체 전달\n */\n let attachmentResults: MessageContentPart[] = [];\n if (currentAttachments.length > 0) {\n const attachmentSkills = Object.entries(resolvedSkills).filter(\n ([, config]) => config.trigger === 'attachment'\n );\n\n for (const [skillName, skillConfig] of attachmentSkills) {\n /** @Todo vibecode - acceptedTypes MIME 매칭 (와일드카드, 확장자 지원) */\n const matchedFiles = currentAttachments.filter((att) => {\n if (!skillConfig.acceptedTypes || skillConfig.acceptedTypes.length === 0) return true;\n return skillConfig.acceptedTypes.some((type) => {\n if (type.startsWith('.')) return att.name.toLowerCase().endsWith(type.toLowerCase());\n if (type.includes('*')) {\n const regex = new RegExp('^' + type.replace('*', '.*') + '$');\n return regex.test(att.mimeType);\n }\n return att.mimeType === type;\n });\n });\n\n if (matchedFiles.length === 0) continue;\n\n /** @Todo vibecode - tool_loading 상태 표시 후 execute → tool_result로 전환 */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n contentParts: [...(m.contentParts || []), {\n type: 'tool_loading' as const,\n toolName: skillName,\n label: skillConfig.label,\n }],\n };\n }),\n };\n })\n );\n\n try {\n /** @Todo vibecode - autoConvertBase64 시 File → base64 자동 변환 */\n const filesToPass = skillConfig.autoConvertBase64\n ? await convertAttachmentsToBase64(matchedFiles)\n : matchedFiles;\n const result = await skillConfig.execute({ files: filesToPass, userMessage: finalContent });\n const toolResultPart: MessageContentPart = {\n type: 'tool_result',\n toolName: skillName,\n label: skillConfig.label,\n icon: skillConfig.icon,\n result: {\n type: 'text',\n content: result.content,\n metadata: result.metadata,\n sources: result.sources,\n },\n };\n attachmentResults.push(toolResultPart);\n\n /** @Todo vibecode - tool_loading → tool_result 전환 */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n contentParts: (m.contentParts || []).map((p) =>\n p.type === 'tool_loading' && (p as any).toolName === skillName ? toolResultPart : p\n ),\n };\n }),\n };\n })\n );\n } catch (error) {\n console.error(`[useChatUI] attachment skill ${skillName} failed:`, error);\n /** @Todo vibecode - 실패 시 tool_loading 제거 */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n contentParts: (m.contentParts || []).filter((p) =>\n !(p.type === 'tool_loading' && (p as any).toolName === skillName)\n ),\n };\n }),\n };\n })\n );\n }\n }\n }\n\n /**\n * @description attachment trigger 후 스트림 제어\n * @Todo vibecode - onSkillComplete 우선, continueAfterToolResult fallback\n */\n let shouldContinueAfterAttachment = continueAfterToolResult;\n if (attachmentResults.length > 0) {\n for (const part of attachmentResults) {\n if (part.type === 'tool_result' && onSkillCompleteRef.current) {\n const decision = onSkillCompleteRef.current(part.toolName, {\n content: part.result.content,\n metadata: part.result.metadata,\n sources: part.result.sources,\n });\n shouldContinueAfterAttachment = decision === 'continue';\n if (!shouldContinueAfterAttachment) break;\n }\n }\n }\n\n /**\n * @description 첫 메시지일 때 generateTitleCallback 호출\n * @Todo vibecode - 비동기 제목 생성 로직\n */\n if (isFirstMessage && generateTitleRef.current) {\n // 비동기로 제목 생성 (백그라운드에서 실행)\n Promise.resolve(generateTitleRef.current(finalContent))\n .then((generatedTitle) => {\n if (generatedTitle && generatedTitle.trim()) {\n setSessions((prev) =>\n prev.map((s) =>\n s.id === capturedSessionId\n ? { ...s, title: generatedTitle.trim(), updatedAt: Date.now() }\n : s\n )\n );\n onTitleChangeRef.current?.(capturedSessionId, generatedTitle.trim());\n }\n })\n .catch(() => {\n /* 제목 생성 실패 시 기존 제목 유지 */\n });\n }\n\n /**\n * @description attachment 결과만 표시하고 AI 호출 생략 (shouldContinueAfterAttachment === false)\n * @Todo vibecode - 'stop' 시 contentParts에 결과가 이미 있으므로 추가 AI 호출 불필요\n */\n if (attachmentResults.length > 0 && !shouldContinueAfterAttachment) {\n setIsLoading(false);\n return;\n }\n\n abortControllerRef.current = new AbortController();\n\n try {\n /**\n * @description skipNextSkillParsing 플래그를 로컬 변수로 캡처 후 즉시 리셋\n * @Todo vibecode - ref가 true로 남아 후속 sendMessage에서 skill 파싱이 영구 스킵되는 버그 방지\n * 이전 스킬 실행이 설정한 플래그를 이번 호출에서 소비하고, ref는 즉시 초기화\n */\n const shouldSkipSkillParsing = skipNextSkillParsingRef.current;\n skipNextSkillParsingRef.current = false;\n\n /**\n * @description 위에서 캡처한 existingMessages, contextSummary 등을 사용\n * @Todo vibecode - stale closure 방지를 위해 이미 캡처된 값 사용\n */\n let messagesToSend = [...existingMessages, userMessage];\n\n // Context compression (점진적 압축 지원)\n const recompressionThreshold = DEFAULT_RECOMPRESSION_THRESHOLD;\n const tokenLimit = DEFAULT_TOKEN_LIMIT;\n\n let currentContextSummary = contextSummary;\n\n // 새 메시지 수 계산\n const newMessageCount = messagesToSend.length - summaryAfterIndex;\n // 토큰 추정\n const estimatedTokensCount = estimateTokens(messagesToSend);\n\n // 압축 조건: 초기 압축 또는 재압축\n const needsInitialCompression =\n !currentContextSummary && messagesToSend.length > contextCompressionThreshold;\n const needsRecompression =\n currentContextSummary &&\n (newMessageCount > recompressionThreshold ||\n estimatedTokensCount > tokenLimit * 0.7);\n\n if (needsInitialCompression || needsRecompression) {\n const toCompress = messagesToSend.slice(0, -keepRecentMessages);\n let summary: string;\n\n if (needsRecompression && currentContextSummary) {\n // 점진적 압축: 기존 요약 + 새 대화\n const newMessages = toCompress.slice(summaryAfterIndex);\n summary = await incrementalCompressContext(currentContextSummary, newMessages, selectedModel);\n } else {\n // 초기 압축\n summary = await compressContext(toCompress, selectedModel);\n }\n\n if (summary) {\n currentContextSummary = summary;\n compressionCount += 1;\n setSessions((prev) =>\n prev.map((s) =>\n s.id === capturedSessionId\n ? {\n ...s,\n contextSummary: summary,\n summaryAfterIndex: toCompress.length,\n compressionState: {\n contextSummary: summary,\n summaryAfterIndex: toCompress.length,\n compressionCount,\n lastCompressionAt: Date.now(),\n },\n }\n : s\n )\n );\n\n // 압축 시점에 정보 추출 (백그라운드)\n if (enableAutoExtraction && globalMemory) {\n const messagesForExtraction = toCompress.map((m) => ({\n role: m.role,\n content: m.content,\n }));\n // 비동기로 실행, 결과를 기다리지 않음\n infoExtraction.extractInfo(messagesForExtraction).catch(() => {\n /* @Todo vibecode - 정보 추출 실패 시 무시 */\n });\n }\n }\n }\n\n // Build chat messages\n let chatMessages: { role: 'user' | 'assistant' | 'system'; content: string }[];\n if (currentContextSummary) {\n const recentMessages = messagesToSend.slice(-keepRecentMessages);\n chatMessages = [\n { role: 'system', content: `[이전 대화 요약]\\n${currentContextSummary}` },\n ...recentMessages.map((m) => ({ role: m.role, content: m.content })),\n ];\n } else {\n chatMessages = messagesToSend.map((m) => ({ role: m.role, content: m.content }));\n }\n\n /**\n * @description attachment 스킬 결과를 AI 컨텍스트에 주입\n * @Todo vibecode - contentParts의 tool_result 내용을 chatMessages에 추가 (API 전용, UI 미저장)\n */\n if (attachmentResults.length > 0 && shouldContinueAfterAttachment) {\n /** @Todo vibecode - attachment 결과 기반 AI 응답에서 skill_use 태그 파싱 방지 */\n skipNextSkillParsingRef.current = true;\n const attachmentContext = attachmentResults\n .filter((part) => part.type === 'tool_result')\n .map((part) => `[${(part as any).label || (part as any).toolName} 결과]\\n${(part as any).result.content}`)\n .join('\\n\\n');\n if (attachmentContext) {\n chatMessages.push({\n role: 'user',\n /** @Todo vibecode - 원본 파일 재요청 방지 + skill_use 태그 사용 금지 명시 */\n content: `사용자가 첨부한 파일의 분석 결과입니다. 원본 파일 내용이 이미 아래에 포함되어 있으므로 원본 파일을 다시 요청하지 마세요.\\n\\n${attachmentContext}\\n\\n위 분석 결과만으로 사용자의 질문에 답변해주세요. skill_use 태그는 사용하지 마세요.`,\n });\n }\n }\n\n console.log('[ChatUI] Messages to send:', chatMessages.length, chatMessages.map(m => ({ role: m.role, content: m.content.slice(0, 50) })));\n\n // Build system prompt\n const baseSystemPrompt = buildSystemPrompt();\n const combinedSystemPrompt = [baseSystemPrompt, actionPrompt].filter(Boolean).join('\\n\\n');\n const messagesForApi = combinedSystemPrompt\n ? [{ role: 'system' as const, content: combinedSystemPrompt }, ...chatMessages]\n : chatMessages;\n\n // Get provider\n const modelConfig = models.find((m) => m.id === selectedModel);\n const provider = modelConfig?.provider || 'ollama';\n\n // Send request\n let response: Response;\n /** @Todo vibecode - ref 패턴으로 stale closure 방지 */\n if (onSendMessageRef.current) {\n const result = await onSendMessageRef.current({\n messages: messagesForApi,\n model: selectedModel,\n provider,\n apiKey,\n systemPrompt: combinedSystemPrompt,\n });\n\n if (typeof result === 'string') {\n // Direct string response\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) =>\n m.id === assistantMessageId ? { ...m, content: result } : m\n ),\n };\n }\n return s;\n })\n );\n return;\n }\n\n // Check for structured response with sources\n if (typeof result === 'object' && 'content' in result) {\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) =>\n m.id === assistantMessageId\n ? { ...m, content: result.content, sources: result.sources }\n : m\n ),\n };\n }\n return s;\n })\n );\n return;\n }\n\n // Create fake response from stream\n response = new Response(result as ReadableStream<Uint8Array>);\n } else {\n /**\n * @description Ollama는 직접 API 호출, 다른 provider는 프록시 경유\n * @Todo vibecode - provider별 요청 포맷 분기\n */\n const isOllama = provider === 'ollama' || apiEndpoint.includes('ollama') || apiEndpoint.includes('11434');\n const requestBody = isOllama\n ? { model: selectedModel, messages: messagesForApi, stream: true }\n : {\n messages: messagesForApi,\n model: selectedModel,\n provider,\n apiKey: provider === 'devdive' ? apiKey : undefined,\n stream: true,\n };\n\n response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(requestBody),\n signal: abortControllerRef.current.signal,\n });\n }\n\n if (!response.ok) throw new Error('API error');\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader');\n\n const decoder = new TextDecoder();\n let buffer = '';\n /** @Todo vibecode - 스트리밍 중 누적 content (stale closure 방지용) */\n let accumulatedContent = '';\n /**\n * @description </skill_use> 태그 감지 플래그\n * @Todo vibecode - 스트리밍 중 스킬 태그 닫힘 감지 시 즉시 중단\n */\n let skillTagDetected = false;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.trim()) continue;\n\n /**\n * @description SSE 형식 (data: ...) 또는 Ollama NDJSON 형식 처리\n * @Todo vibecode - 스트리밍 포맷 호환성\n */\n let data = line;\n if (line.startsWith('data: ')) {\n data = line.slice(6);\n if (data === '[DONE]') continue;\n }\n\n try {\n const parsed = JSON.parse(data);\n\n /**\n * @description Ollama 형식 처리 (thinking 모델 지원)\n * @Todo vibecode - thinking 필드가 있으면 <thinking> 태그로 감싸서 표시\n */\n const content = parsed.message?.content || parsed.content || parsed.text || '';\n const thinking = parsed.message?.thinking || '';\n\n // content 또는 thinking이 있으면 추가\n if (content || thinking) {\n /** @Todo vibecode - 로컬 변수에도 누적 (stale closure 방지) */\n if (content) accumulatedContent += content;\n\n /**\n * @description </skill_use> 닫힘 태그 감지 시 스트림 즉시 트런케이트\n * @Todo vibecode - 태그 이후 불필요한 AI 텍스트 차단 (이미지 설명 반복 방지)\n */\n if (!shouldSkipSkillParsing && accumulatedContent.includes('</skill_use>')) {\n const endIdx = accumulatedContent.indexOf('</skill_use>');\n accumulatedContent = accumulatedContent.substring(0, endIdx + '</skill_use>'.length);\n skillTagDetected = true;\n }\n\n /** @Todo vibecode - skillTag 감지 시 트런케이트된 content로 세션 업데이트 */\n const displayContent = skillTagDetected ? accumulatedContent : null;\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n\n /** @Todo vibecode - 트런케이트 시 전체 교체, 아니면 기존 누적 */\n if (displayContent) {\n return { ...m, content: displayContent };\n }\n\n let newContent = m.content;\n\n // thinking 처리: <thinking> 태그 안에 추가\n if (thinking) {\n if (!newContent.includes('<thinking>')) {\n newContent = '<thinking>' + thinking;\n } else if (!newContent.includes('</thinking>')) {\n // 아직 닫히지 않은 thinking 블록에 추가\n newContent += thinking;\n }\n }\n\n // content 처리: thinking 블록 닫고 실제 내용 추가\n if (content) {\n if (newContent.includes('<thinking>') && !newContent.includes('</thinking>')) {\n newContent += '</thinking>\\n\\n';\n }\n newContent += content;\n }\n\n return { ...m, content: newContent };\n }),\n };\n }\n return s;\n })\n );\n\n /** @Todo vibecode - skillTag 감지 후 for 루프 탈출 */\n if (skillTagDetected) break;\n }\n\n } catch {\n // Ignore parse errors\n }\n }\n\n /** @Todo vibecode - skillTag 감지 후 while 루프 탈출 (스트리밍 중단) */\n if (skillTagDetected) break;\n }\n\n /**\n * @description 남은 버퍼 처리\n * @Todo vibecode - 마지막 줄이 개행 없이 끝나는 경우\n */\n if (buffer.trim()) {\n try {\n const parsed = JSON.parse(buffer);\n const content = parsed.message?.content || parsed.content || parsed.text;\n if (content) {\n /** @Todo vibecode - 남은 버퍼도 로컬 변수에 누적 */\n accumulatedContent += content;\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) =>\n m.id === assistantMessageId\n ? { ...m, content: m.content + content }\n : m\n ),\n };\n }\n return s;\n })\n );\n }\n } catch {\n // Ignore parse errors\n }\n }\n\n /**\n * @description AI 응답에서 Skill 호출 감지 및 실행\n * @Todo vibecode - <skill_use> 태그 파싱 → 스킬 실행 (onProgress/onStream 콜백 연결)\n * 고도화: 스트리밍 보고서 스킬은 hidden 메시지 불필요, 단순 스킬은 기존 흐름 유지\n */\n if (!shouldSkipSkillParsing) {\n /** @Todo vibecode - accumulatedContent 사용 (stale closure 방지) */\n const assistantContent = accumulatedContent;\n\n const { skillCall: detectedSkill, cleanContent: skillCleanContent } =\n parseSkillCallFromContent(assistantContent);\n\n if (detectedSkill && resolvedSkills[detectedSkill.name]) {\n /** @Todo vibecode - skill_use 태그 제거 + 실행 상태 첨부 */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n content: skillCleanContent,\n skillExecution: {\n skillName: detectedSkill.name,\n params: detectedSkill.params,\n status: 'executing' as const,\n },\n };\n }),\n };\n })\n );\n\n /**\n * @Todo vibecode - 스킬 실행 (onProgress/onStream 콜백으로 실시간 UI 업데이트)\n * onStream이 호출되면 보고서가 스킬 내부에서 이미 생성된 것이므로 hidden 메시지 불필요\n */\n let streamedReport = '';\n const { result } = await handleSkillCall(assistantContent, {\n onProgress: (progress) => {\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n skillExecution: { ...m.skillExecution!, progress },\n };\n }),\n };\n })\n );\n },\n onStream: (chunk) => {\n streamedReport += chunk;\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return { ...m, content: streamedReport };\n }),\n };\n })\n );\n },\n signal: abortControllerRef.current?.signal,\n });\n\n if (result) {\n /**\n * @description 도구 결과 처리 (metadata.__toolResult__ 플래그로 식별)\n * @Todo vibecode - 도구 결과를 contentParts로 변환 + AI 피드백 전송\n */\n if (result.metadata?.__toolResult__) {\n const resultType = result.metadata.resultType as string;\n const toolName = result.metadata.toolName as string;\n const toolLabel = result.metadata.toolLabel as string | undefined;\n const toolIcon = result.metadata.toolIcon as string | undefined;\n\n /**\n * @Todo vibecode - 도구 결과를 tool_result 타입으로 통일\n * ToolStatusCard에서 상태 표시 + 접이식 소스 렌더링\n */\n const parts: MessageContentPart[] = [];\n if (skillCleanContent.trim()) {\n parts.push({ type: 'text', content: skillCleanContent });\n }\n\n parts.push({\n type: 'tool_result',\n toolName,\n label: toolLabel,\n icon: toolIcon,\n result: {\n type: resultType as 'text' | 'image' | 'file' | 'error',\n content: result.content,\n metadata: result.metadata,\n sources: result.sources,\n },\n });\n\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n contentParts: parts,\n skillExecution: {\n ...m.skillExecution!,\n status: 'done' as const,\n result,\n },\n };\n }),\n };\n })\n );\n\n /**\n * @description 이미지/파일 결과는 후속 API 호출 생략 (자체 완결)\n * @Todo vibecode - 이미지는 contentParts로 직접 표시, 텍스트 결과만 AI 피드백 필요\n */\n if (resultType === 'image' || resultType === 'file') {\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n\n /**\n * @description 도구 실행 후 스트림 제어\n * @Todo vibecode - onSkillComplete 콜백 또는 continueAfterToolResult 옵션으로 중단 결정\n */\n let shouldContinue = continueAfterToolResult;\n if (onSkillCompleteRef.current) {\n const decision = onSkillCompleteRef.current(toolName, result);\n shouldContinue = decision === 'continue';\n }\n\n if (!shouldContinue) {\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n\n skipNextSkillParsingRef.current = true;\n const feedbackPrompt = resultType === 'error'\n ? `도구 \"${toolName}\" 실행 중 오류 발생: ${result.content}\\n\\n사용자에게 오류를 안내해주세요. skill_use 태그는 사용하지 마세요.`\n : `도구 \"${toolName}\" 결과:\\n\\n${result.content}\\n\\n위 결과를 바탕으로 답변해주세요. skill_use 태그는 사용하지 마세요.`;\n setTimeout(() => {\n sendMessage(feedbackPrompt, { hiddenUserMessage: true });\n }, 100);\n\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n\n /** @Todo vibecode - 실행 완료 상태 + sources 저장 */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n return {\n ...m,\n sources: result.sources || m.sources,\n skillExecution: {\n ...m.skillExecution!,\n status: 'done' as const,\n result,\n },\n };\n }),\n };\n })\n );\n\n if (streamedReport) {\n /**\n * @Todo vibecode - 스트리밍 보고서 완료: hidden 메시지 불필요\n * 보고서가 스킬 내부 LLM에서 이미 생성되어 onStream으로 전달됨\n */\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n\n /**\n * @description 일반 스킬 완료 후 스트림 제어\n * @Todo vibecode - onSkillComplete / continueAfterToolResult로 중단 결정\n */\n let shouldContinueSkill = continueAfterToolResult;\n if (onSkillCompleteRef.current) {\n const decision = onSkillCompleteRef.current(detectedSkill.name, result);\n shouldContinueSkill = decision === 'continue';\n }\n\n if (!shouldContinueSkill) {\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n\n /** @Todo vibecode - 단순 스킬: 결과를 hidden 메시지로 AI에 전달하여 최종 응답 생성 */\n skipNextSkillParsingRef.current = true;\n const resultPrompt = `스킬 \"${detectedSkill.name}\" 실행 결과:\\n\\n${result.content}\\n\\n위 결과를 바탕으로 사용자의 원래 질문에 답변해주세요. skill_use 태그는 사용하지 마세요.`;\n setTimeout(() => {\n sendMessage(resultPrompt, { hiddenUserMessage: true });\n }, 100);\n\n /** @Todo vibecode - 스킬 실행 후에는 poll 파싱도 스킵 (최종 응답에서만 파싱) */\n setIsLoading(false);\n abortControllerRef.current = null;\n return;\n }\n }\n }\n\n /**\n * @description AI 응답에서 Poll 파싱\n * @Todo vibecode - <poll> 태그 감지 및 pollBlock 추가\n * Poll 응답 직후에는 파싱 스킵하되, 태그는 항상 제거\n */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== capturedSessionId) return s;\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n const { pollBlock, cleanContent } = parsePollFromContent(m.content);\n // poll 태그는 항상 제거, 단 skipNextPollParsing이면 pollBlock은 추가 안 함\n if (skipNextPollParsingRef.current) {\n skipNextPollParsingRef.current = false;\n return { ...m, content: cleanContent }; // 태그만 제거, pollBlock 없음\n }\n if (pollBlock) {\n return { ...m, content: cleanContent, pollBlock };\n }\n return m;\n }),\n };\n })\n );\n\n /**\n * @description 외부 스토리지에 메시지 저장 + localStorage 캐시 동시 저장\n * @Todo vibecode - accumulatedContent 사용 (stale closure 방지), 캐시로 fallback 복원 보장\n */\n if (useExternalStorage && capturedSessionId) {\n /** @Todo vibecode - stale closure 방지: sessions.find() 대신 accumulatedContent 직접 사용 */\n const assistantContentForSave = accumulatedContent;\n\n if (assistantContentForSave && onSaveMessagesRef.current) {\n /**\n * @Todo vibecode - contentParts 포함 저장 (이미지/파일 등 복원용)\n * sessionsRef에서 최신 메시지를 가져와 contentParts 추출\n */\n const latestSession = sessionsRef.current.find((s) => s.id === capturedSessionId);\n const latestMessages = latestSession?.messages || [];\n const userMsg = latestMessages.find((m) => m.role === 'user' && m.content === finalContent);\n const assistantMsg = [...latestMessages].reverse().find((m: ChatMessage) => m.role === 'assistant');\n\n const messagesToSave = [\n { role: 'user' as const, message: finalContent, ...(userMsg?.contentParts && { contentParts: userMsg.contentParts }) },\n { role: 'assistant' as const, message: assistantContentForSave, ...(assistantMsg?.contentParts && { contentParts: assistantMsg.contentParts }) },\n ];\n\n onSaveMessagesRef.current!(capturedSessionId, messagesToSave).catch((saveError) => {\n console.error('[useChatUI] Failed to save messages:', saveError);\n });\n }\n\n /** @Todo vibecode - localStorage 캐시 저장 (sessionsRef로 최신 상태 접근) */\n queueMicrotask(() => {\n const sessionToCache = sessionsRef.current.find((s) => s.id === capturedSessionId);\n if (sessionToCache && sessionToCache.messages.length > 0) {\n writeSessionCache(storageKey, sessionToCache);\n }\n });\n }\n /**\n * @description 주기적 정보 추출 (매 4개 메시지 = 약 2회 대화마다)\n * @Todo vibecode - 압축 시점까지 기다리지 않고 조기에 메모리 축적\n */\n if (enableAutoExtraction && globalMemory) {\n const currentMsgCount = existingMessages.length + 2; // +user +assistant\n const sinceLastExtraction = currentMsgCount - lastExtractionMsgCountRef.current;\n if (sinceLastExtraction >= 4) {\n lastExtractionMsgCountRef.current = currentMsgCount;\n const recentForExtraction = [...existingMessages.slice(-6), userMessage].map(\n (m) => ({ role: m.role, content: m.content })\n );\n infoExtraction.extractInfo(recentForExtraction).catch(() => {\n /* @Todo vibecode - 정보 추출 실패 시 무시 */\n });\n }\n }\n\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n return;\n }\n const err = error instanceof Error ? error : new Error('Unknown error');\n onErrorRef.current?.(err);\n\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) =>\n m.id === assistantMessageId\n ? { ...m, content: '오류가 발생했습니다. 다시 시도해주세요.' }\n : m\n ),\n };\n }\n return s;\n })\n );\n } finally {\n setIsLoading(false);\n abortControllerRef.current = null;\n }\n }, [\n input,\n isLoading,\n currentSessionId,\n sessions,\n selectedModel,\n quotedText,\n selectedAction,\n apiEndpoint,\n apiKey,\n models,\n contextCompressionThreshold,\n keepRecentMessages,\n buildSystemPrompt,\n compressContext,\n useExternalStorage,\n handleSkillCall,\n resolvedSkills,\n /** @Todo vibecode - attachments, continueAfterToolResult를 deps에 추가하여 stale closure 방지 */\n attachments,\n continueAfterToolResult,\n ]);\n\n /**\n * @description Poll 응답 처리 (여러 질문의 응답)\n * @Todo vibecode - 사용자가 모든 선택지 선택 완료 시 호출\n * 상태 업데이트와 메시지 발송을 분리하여 순서대로 실행\n */\n const handlePollSubmit = useCallback(\n (messageId: string, responses: PollResponse[]) => {\n // 1. 현재 세션에서 해당 메시지의 pollBlock 정보 추출\n const currentSess = sessions.find((s) => s.id === currentSessionId);\n const targetMessage = currentSess?.messages.find((m) => m.id === messageId);\n if (!targetMessage?.pollBlock) return;\n\n const pollBlock = targetMessage.pollBlock;\n\n // 2. 응답 포맷팅\n const formattedParts: string[] = [];\n responses.forEach((response) => {\n const question = pollBlock.questions.find((q) => q.id === response.questionId);\n if (!question) return;\n if (response.skipped || (response.selectedOptions.length === 0 && !response.otherText)) return;\n\n const formatted = formatPollResponse(question, response.selectedOptions, response.otherText);\n formattedParts.push(`- ${question.question}: ${formatted}`);\n });\n\n const hasValidResponses = formattedParts.length > 0;\n const isAutoGenerate = responses.every((r) => r.skipped);\n\n // 3. pollBlock 제거 + 안내 메시지 직접 추가\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id !== currentSessionId) return s;\n const updatedMessages = s.messages.map((m) => {\n if (m.id !== messageId) return m;\n return { ...m, pollBlock: undefined };\n });\n\n /**\n * @description 안내 메시지를 assistant로 직접 추가\n * @Todo vibecode - API 호출 없이 즉시 표시\n */\n updatedMessages.push({\n id: generateId('msg'),\n role: 'assistant',\n content: isAutoGenerate\n ? '자동으로 최적의 옵션을 선택하여 응답하겠습니다. 이제 시작하겠습니다.'\n : '선택하신 내용을 기반으로 응답하겠습니다. 이제 시작하겠습니다.',\n model: selectedModel,\n timestamp: Date.now(),\n });\n\n return { ...s, messages: updatedMessages };\n })\n );\n\n // 4. 숨겨진 프롬프트로 실제 답변 요청 (유저에게 안 보임)\n skipNextPollParsingRef.current = true;\n const hiddenPrompt = isAutoGenerate\n ? '사용자가 직접 선택하지 않고 자동생성을 요청했습니다. 원래 요청에 대해 가장 적절한 옵션을 스스로 판단하여 구체적이고 실질적으로 답변해주세요. poll 태그는 사용하지 마세요.'\n : `사용자의 선택 결과:\\n${formattedParts.join('\\n')}\\n\\n위 선택을 반영하여 원래 요청에 대해 구체적이고 실질적으로 답변해주세요. poll 태그는 사용하지 마세요.`;\n setTimeout(() => {\n sendMessage(hiddenPrompt, { hiddenUserMessage: true });\n }, 100);\n },\n [sessions, currentSessionId, selectedModel, sendMessage]\n );\n\n // ============================================================================\n // Edit & Regenerate\n // ============================================================================\n\n const saveEdit = useCallback(async (content: string) => {\n if (!editingMessageId || !currentSession || !currentSessionId) return;\n\n const messageIndex = currentSession.messages.findIndex((m) => m.id === editingMessageId);\n if (messageIndex === -1) return;\n\n const capturedSessionId = currentSessionId;\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n const newMessages = s.messages.slice(0, messageIndex);\n return { ...s, messages: newMessages, updatedAt: Date.now() };\n }\n return s;\n })\n );\n\n setEditingMessageId(null);\n await sendMessage(content);\n }, [editingMessageId, currentSession, currentSessionId, sendMessage]);\n\n const regenerate = useCallback(async (messageId: string) => {\n console.log('[ChatUI] Regenerate called:', { messageId, currentSessionId, isLoading });\n if (!currentSession || !currentSessionId || isLoading) {\n console.log('[ChatUI] Regenerate early return - missing session or loading');\n return;\n }\n\n const assistantIndex = currentSession.messages.findIndex((m) => m.id === messageId);\n console.log('[ChatUI] Assistant index:', assistantIndex);\n if (assistantIndex === -1) return;\n\n const userMessage = currentSession.messages[assistantIndex - 1];\n console.log('[ChatUI] User message:', userMessage?.content?.slice(0, 50));\n if (!userMessage || userMessage.role !== 'user') return;\n\n const capturedSessionId = currentSessionId;\n\n /**\n * @description user 메시지는 유지하고 assistant 메시지만 제거 후 재생성\n * @Todo vibecode - 기존 user 메시지 유지, assistant 응답만 재생성\n */\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n // user 메시지까지만 유지 (assistant 메시지 제거)\n return {\n ...s,\n messages: s.messages.slice(0, assistantIndex),\n updatedAt: Date.now(),\n };\n }\n return s;\n })\n );\n\n // 기존 user 메시지의 content로 재생성 (새 user 메시지 추가하지 않음)\n // sendMessage 대신 직접 API 호출하여 assistant 응답만 생성\n setIsLoading(true);\n abortControllerRef.current = new AbortController();\n\n try {\n const assistantMessageId = `msg_${Date.now()}_assistant`;\n\n // 빈 assistant 메시지 추가\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: [\n ...s.messages,\n {\n id: assistantMessageId,\n role: 'assistant' as const,\n content: '',\n model: selectedModel,\n timestamp: Date.now(),\n },\n ],\n };\n }\n return s;\n })\n );\n\n // 메시지 준비\n const messagesUpToUser = currentSession.messages.slice(0, assistantIndex);\n const chatMessages = messagesUpToUser.map((m) => ({ role: m.role, content: m.content }));\n const baseSystemPrompt = buildSystemPrompt();\n const messagesForApi = baseSystemPrompt\n ? [{ role: 'system' as const, content: baseSystemPrompt }, ...chatMessages]\n : chatMessages;\n\n const modelConfig = models.find((m) => m.id === selectedModel);\n const provider = modelConfig?.provider || 'ollama';\n\n /**\n * @description Ollama는 직접 API 호출, 다른 provider는 프록시 경유\n * @Todo vibecode - provider별 요청 포맷 분기\n */\n const isOllama = provider === 'ollama' || apiEndpoint.includes('ollama') || apiEndpoint.includes('11434');\n const requestBody = isOllama\n ? { model: selectedModel, messages: messagesForApi, stream: true }\n : {\n messages: messagesForApi,\n model: selectedModel,\n provider,\n apiKey: provider === 'devdive' ? apiKey : undefined,\n stream: true,\n };\n\n console.log('[ChatUI] Regenerate fetch:', { apiEndpoint, isOllama, model: selectedModel });\n\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(requestBody),\n signal: abortControllerRef.current.signal,\n });\n\n console.log('[ChatUI] Regenerate response status:', response.status);\n if (!response.ok) throw new Error(`API error: ${response.status}`);\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.trim()) continue;\n\n let data = line;\n if (line.startsWith('data: ')) {\n data = line.slice(6);\n if (data === '[DONE]') continue;\n }\n\n try {\n const parsed = JSON.parse(data);\n const content = parsed.message?.content || parsed.content || parsed.text || '';\n const thinking = parsed.message?.thinking || '';\n\n if (content || thinking) {\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n\n let newContent = m.content;\n if (thinking) {\n if (!newContent.includes('<thinking>')) {\n newContent = '<thinking>' + thinking;\n } else if (!newContent.includes('</thinking>')) {\n newContent += thinking;\n }\n }\n if (content) {\n if (newContent.includes('<thinking>') && !newContent.includes('</thinking>')) {\n newContent += '</thinking>\\n\\n';\n }\n newContent += content;\n }\n return { ...m, content: newContent };\n }),\n };\n }\n return s;\n })\n );\n }\n } catch {\n // Ignore parse errors\n }\n }\n }\n\n // 남은 버퍼 처리\n if (buffer.trim()) {\n try {\n const parsed = JSON.parse(buffer);\n const content = parsed.message?.content || parsed.content || parsed.text || '';\n const thinking = parsed.message?.thinking || '';\n if (content || thinking) {\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id !== assistantMessageId) return m;\n let newContent = m.content;\n if (thinking) {\n if (!newContent.includes('<thinking>')) {\n newContent = '<thinking>' + thinking;\n } else if (!newContent.includes('</thinking>')) {\n newContent += thinking;\n }\n }\n if (content) {\n if (newContent.includes('<thinking>') && !newContent.includes('</thinking>')) {\n newContent += '</thinking>\\n\\n';\n }\n newContent += content;\n }\n return { ...m, content: newContent };\n }),\n };\n }\n return s;\n })\n );\n }\n } catch {\n // Ignore parse errors\n }\n }\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n return;\n }\n console.error('[ChatUI] Regenerate error:', error);\n // 에러 발생 시에도 빈 assistant 메시지는 유지 (UI에서 에러 상태 표시)\n onErrorRef.current?.(error instanceof Error ? error : new Error('Unknown error'));\n } finally {\n setIsLoading(false);\n }\n }, [currentSession, currentSessionId, isLoading, selectedModel, models, apiEndpoint, apiKey, buildSystemPrompt]);\n\n // ============================================================================\n // Ask Other Model (Alternative Response)\n // ============================================================================\n\n const askOtherModel = useCallback(async (messageId: string, targetModel: string) => {\n if (!currentSession || !currentSessionId || isLoading) return;\n\n // Find the assistant message\n const assistantIndex = currentSession.messages.findIndex((m) => m.id === messageId);\n if (assistantIndex === -1) return;\n\n const assistantMessage = currentSession.messages[assistantIndex];\n if (assistantMessage.role !== 'assistant') return;\n\n // Find the user message before this assistant message\n const userMessage = currentSession.messages[assistantIndex - 1];\n if (!userMessage || userMessage.role !== 'user') return;\n\n setIsLoading(true);\n setLoadingAlternativeFor(messageId);\n abortControllerRef.current = new AbortController();\n\n try {\n // Build messages to send (all messages up to and including user message)\n const messagesToSend = currentSession.messages.slice(0, assistantIndex);\n\n // Build chat messages\n let chatMessages: { role: 'user' | 'assistant' | 'system'; content: string }[];\n if (currentSession.contextSummary) {\n const recentMessages = messagesToSend.slice(-keepRecentMessages);\n chatMessages = [\n { role: 'system', content: `[이전 대화 요약]\\n${currentSession.contextSummary}` },\n ...recentMessages.map((m) => ({ role: m.role, content: m.content })),\n ];\n } else {\n chatMessages = messagesToSend.map((m) => ({ role: m.role, content: m.content }));\n }\n\n // Build system prompt\n const baseSystemPrompt = buildSystemPrompt();\n const messagesForApi = baseSystemPrompt\n ? [{ role: 'system' as const, content: baseSystemPrompt }, ...chatMessages]\n : chatMessages;\n\n // Get provider for target model\n const modelConfig = models.find((m) => m.id === targetModel);\n const provider = modelConfig?.provider || 'ollama';\n\n // Collect response content and sources\n let responseContent = '';\n let responseSources: import('../types').SourceItem[] | undefined;\n\n /** @Todo vibecode - ref 패턴으로 stale closure 방지 (poll 경로) */\n if (onSendMessageRef.current) {\n const result = await onSendMessageRef.current({\n messages: messagesForApi,\n model: targetModel,\n provider,\n apiKey,\n systemPrompt: baseSystemPrompt,\n });\n\n if (typeof result === 'string') {\n responseContent = result;\n } else if (typeof result === 'object' && 'content' in result) {\n // Structured response with sources\n responseContent = result.content;\n responseSources = result.sources;\n } else {\n // Stream response\n const reader = (result as ReadableStream<Uint8Array>).getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n try {\n const parsed = JSON.parse(data);\n { const chunk = parsed.content ?? parsed.text ?? ''; if (chunk) responseContent += chunk; }\n } catch {\n // Ignore parse errors\n }\n }\n }\n }\n }\n } else {\n /**\n * @description Ollama는 직접 API 호출, 다른 provider는 프록시 경유\n * @Todo vibecode - provider별 요청 포맷 분기\n */\n const isOllama = provider === 'ollama' || apiEndpoint.includes('ollama') || apiEndpoint.includes('11434');\n const requestBody = isOllama\n ? { model: targetModel, messages: messagesForApi, stream: true }\n : {\n messages: messagesForApi,\n model: targetModel,\n provider,\n apiKey: provider === 'devdive' ? apiKey : undefined,\n stream: true,\n };\n\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(requestBody),\n signal: abortControllerRef.current.signal,\n });\n\n if (!response.ok) throw new Error('API error');\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n try {\n const parsed = JSON.parse(data);\n { const chunk = parsed.content ?? parsed.text ?? ''; if (chunk) responseContent += chunk; }\n } catch {\n // Ignore parse errors\n }\n }\n }\n }\n }\n\n // Add alternative to the assistant message\n const alternative = {\n id: generateId('alt'),\n model: targetModel,\n content: responseContent,\n timestamp: Date.now(),\n sources: responseSources,\n };\n\n const capturedSessionId = currentSessionId;\n\n // 현재 alternatives 개수 계산 (새 응답의 인덱스 결정용)\n const currentAltsCount = currentSession.messages.find(m => m.id === messageId)?.alternatives?.length || 0;\n const newAlternativeIndex = currentAltsCount + 1; // 0은 원본, 1부터 alternatives\n\n setSessions((prev) =>\n prev.map((s) => {\n if (s.id === capturedSessionId) {\n return {\n ...s,\n messages: s.messages.map((m) => {\n if (m.id === messageId) {\n const existingAlts = m.alternatives || [];\n return {\n ...m,\n alternatives: [...existingAlts, alternative],\n };\n }\n return m;\n }),\n updatedAt: Date.now(),\n };\n }\n return s;\n })\n );\n\n // 새 응답으로 자동 이동\n setActiveAlternatives((prev) => ({\n ...prev,\n [messageId]: newAlternativeIndex,\n }));\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n return;\n }\n const err = error instanceof Error ? error : new Error('Unknown error');\n onErrorRef.current?.(err);\n } finally {\n setIsLoading(false);\n setLoadingAlternativeFor(null);\n abortControllerRef.current = null;\n }\n }, [\n currentSession,\n currentSessionId,\n isLoading,\n keepRecentMessages,\n buildSystemPrompt,\n models,\n apiEndpoint,\n apiKey,\n onSendMessage,\n onError,\n ]);\n\n // ============================================================================\n // Alternative Navigation\n // ============================================================================\n\n const setActiveAlternative = useCallback((assistantMessageId: string, index: number) => {\n setActiveAlternatives((prev) => ({\n ...prev,\n [assistantMessageId]: index,\n }));\n }, []);\n\n const getActiveAlternative = useCallback((assistantMessageId: string): number => {\n return activeAlternatives[assistantMessageId] ?? 0;\n }, [activeAlternatives]);\n\n // ============================================================================\n // Return\n // ============================================================================\n\n return {\n // State (enableProjects 시 프로젝트별 필터링된 세션)\n sessions: enableProjects ? visibleSessions : sessions,\n currentSession,\n currentSessionId,\n messages,\n input,\n isLoading,\n selectedModel,\n sidebarOpen,\n settingsOpen,\n quotedText,\n selectedAction,\n copiedMessageId,\n editingMessageId,\n personalization,\n activeAlternatives,\n loadingAlternativeFor,\n\n // Actions\n setInput,\n sendMessage,\n stopGeneration,\n newSession,\n selectSession,\n deleteSession,\n renameSession,\n setModel,\n toggleSidebar,\n openSettings,\n closeSettings,\n setQuotedText,\n setSelectedAction,\n copyMessage,\n startEdit,\n cancelEdit,\n saveEdit,\n regenerate,\n askOtherModel,\n setActiveAlternative,\n getActiveAlternative,\n updatePersonalization,\n savePersonalization,\n models: effectiveModels,\n isModelsLoading,\n\n // Memory\n globalMemory,\n compressionState,\n extractUserInfo: async () => {\n if (!enableAutoExtraction || !globalMemory) return;\n const recentMessages = messages.slice(-10).map((m) => ({\n role: m.role,\n content: m.content,\n }));\n await infoExtraction.extractInfo(recentMessages);\n },\n\n // External Storage Loading States\n /**\n * @description 세션 목록 로딩 상태\n * @Todo vibecode - 외부 스토리지 사용 시\n */\n isSessionsLoading,\n /**\n * @description 단일 세션 로딩 상태\n * @Todo vibecode - 외부 스토리지 사용 시\n */\n isSessionLoading,\n\n // Deep Research\n /**\n * @description 심층연구 모드 활성화 여부\n * @Todo vibecode - 심층연구 버튼 토글 상태\n */\n isDeepResearchMode,\n /**\n * @description 심층연구 모드 토글\n * @Todo vibecode - 심층연구 버튼 클릭 핸들러\n */\n toggleDeepResearchMode,\n /**\n * @description 심층연구 진행 상태\n * @Todo vibecode - 현재 진행 중인 심층연구 상태\n */\n deepResearchProgress,\n\n // Poll (AI-driven choices)\n /**\n * @description Poll 응답 처리\n * @Todo vibecode - 사용자가 선택지 선택 완료 시 호출\n */\n handlePollSubmit,\n\n // Attachments\n /**\n * @description 현재 첨부된 파일 목록\n * @Todo vibecode - 입력창 파일 첨부 상태\n */\n attachments,\n /**\n * @description 파일 첨부 추가 핸들러\n * @Todo vibecode - File[] → ChatAttachment 변환\n */\n addAttachments,\n /**\n * @description 첨부 파일 제거 핸들러\n * @Todo vibecode - objectURL 해제 포함\n */\n removeAttachment,\n\n // Skills\n /**\n * @description 현재 실행 중인 스킬 상태\n * @Todo vibecode - 스킬 실행 상태 추적\n */\n activeSkillExecution,\n /**\n * @description manual 트리거 스킬 목록 (UI 표시용)\n * @Todo vibecode - 입력창 메뉴에 표시\n */\n manualSkills,\n /**\n * @description manual 스킬/도구 선택 핸들러\n * @Todo vibecode - 도구 스킬은 selectedAction으로 변환, 일반 스킬은 즉시 실행\n */\n executeManualSkill: (skillName: string) => {\n const isToolSkill = tools?.some((t) => t.name === skillName);\n if (isToolSkill) {\n /** @Todo vibecode - 도구는 즉시 실행하지 않고 selectedAction으로 설정 */\n const toolConfig = tools!.find((t) => t.name === skillName)!;\n setSelectedAction({\n id: `tool_${skillName}`,\n label: toolConfig.label || toolConfig.name,\n icon: toolConfig.icon || 'sparkling',\n description: toolConfig.description,\n systemPrompt: `사용자가 \"${toolConfig.label || skillName}\" 도구를 사용하려고 합니다. 사용자의 메시지를 바탕으로 반드시 <skill_use name=\"${skillName}\"> 태그를 사용하여 이 도구를 호출하세요. 도구를 사용하지 않고 텍스트로만 답변하지 마세요.`,\n });\n } else {\n /** @Todo vibecode - manual 스킬 실행 후 AI 후속 응답 지원 */\n const currentQuery = input;\n executeManualSkill(skillName, { query: currentQuery }).then((result) => {\n if (!result || !result.content) return;\n\n let shouldContinue = continueAfterToolResult;\n if (onSkillCompleteRef.current) {\n const decision = onSkillCompleteRef.current(skillName, result);\n shouldContinue = decision === 'continue';\n }\n if (!shouldContinue) return;\n\n skipNextSkillParsingRef.current = true;\n const resultPrompt = `스킬 \"${skillName}\" 실행 결과:\\n\\n${result.content}\\n\\n위 결과를 바탕으로 사용자의 원래 질문에 답변해주세요. skill_use 태그는 사용하지 마세요.`;\n setTimeout(() => {\n sendMessage(resultPrompt, { hiddenUserMessage: true });\n }, 100);\n });\n }\n },\n\n // Project\n /** @Todo vibecode - 프로젝트 목록 (enableProjects=false이면 빈 배열) */\n projects: projectHook.projects,\n currentProjectId: projectHook.currentProjectId,\n currentProject: projectHook.currentProject,\n isProjectsLoading: projectHook.isProjectsLoading,\n createProject: projectHook.createProject,\n selectProject: async (projectId: string) => {\n if (!enableProjects) return;\n await projectHook.selectProject(projectId);\n /** @Todo vibecode - 프로젝트 전환 시 해당 프로젝트의 첫 번째 세션 선택 */\n const projectSessions = sessionsRef.current.filter((s) => s.projectId === projectId);\n if (projectSessions.length > 0) {\n setCurrentSessionId(projectSessions[0].id);\n } else {\n setCurrentSessionId(null);\n }\n },\n updateProject: projectHook.updateProject,\n deleteProject: async (projectId: string) => {\n if (!enableProjects) return;\n /** @Todo vibecode - 프로젝트 삭제 시 소속 세션도 함께 삭제 */\n const projectSessions = sessionsRef.current.filter((s) => s.projectId === projectId);\n for (const sess of projectSessions) {\n if (useExternalStorage && onDeleteSessionCallbackRef.current) {\n await onDeleteSessionCallbackRef.current(sess.id).catch(() => {});\n }\n removeSessionCache(storageKey, sess.id);\n }\n setSessions((prev) => prev.filter((s) => s.projectId !== projectId));\n await projectHook.deleteProject(projectId);\n },\n addProjectFile: projectHook.addFile,\n deleteProjectFile: projectHook.deleteFile,\n projectSettingsOpen,\n openProjectSettings: () => setProjectSettingsOpen(true),\n closeProjectSettings: () => setProjectSettingsOpen(false),\n projectMemory,\n };\n};\n\nexport default useChatUI;\n","/**\n * Core types for devdive-chatLLM\n */\n\n// ============================================================================\n// Provider Types\n// ============================================================================\n\nexport type ProviderType = 'openai' | 'anthropic' | 'google' | 'naver' | 'ollama';\n\nexport interface ProviderConfigs {\n openai?: OpenAIConfig;\n anthropic?: AnthropicConfig;\n google?: GoogleConfig;\n naver?: NaverConfig;\n ollama?: OllamaConfig;\n}\n\nexport interface OpenAIConfig {\n apiKey: string;\n baseUrl?: string;\n}\n\nexport interface AnthropicConfig {\n apiKey: string;\n baseUrl?: string;\n}\n\nexport interface GoogleConfig {\n apiKey: string;\n}\n\nexport interface NaverConfig {\n apiKey: string;\n apiGatewayKey: string;\n baseUrl?: string;\n}\n\nexport interface OllamaConfig {\n baseUrl?: string; // default: http://localhost:11434\n}\n\n// ============================================================================\n// Message Types\n// ============================================================================\n\nexport type Role = 'system' | 'user' | 'assistant' | 'tool';\n\nexport interface Message {\n id: string;\n role: Role;\n content: string;\n provider?: ProviderType;\n model?: string;\n toolCalls?: ToolCall[];\n toolCallId?: string;\n timestamp: number;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ToolCall {\n id: string;\n name: string;\n arguments: Record<string, unknown>;\n}\n\nexport interface ToolResult {\n toolCallId: string;\n result: unknown;\n error?: string;\n}\n\n// ============================================================================\n// Tool/Function Types\n// ============================================================================\n\nexport interface ParameterSchema {\n type: 'string' | 'number' | 'boolean' | 'object' | 'array';\n description?: string;\n enum?: string[];\n items?: ParameterSchema;\n properties?: Record<string, ParameterSchema>;\n required?: string[];\n}\n\nexport interface ToolDefinition {\n name: string;\n description: string;\n parameters: {\n type: 'object';\n properties: Record<string, ParameterSchema>;\n required?: string[];\n };\n handler: (params: Record<string, unknown>) => Promise<unknown> | unknown;\n}\n\n// ============================================================================\n// Chat & Session Types\n// ============================================================================\n\nexport interface ChatConfig {\n id?: string;\n providers: ProviderConfigs;\n defaultProvider: ProviderType;\n defaultModel?: string;\n storagePath?: string;\n systemPrompt?: string;\n /** 개인화 설정 */\n personalization?: Partial<PersonalizationConfig>;\n}\n\nexport interface Chat {\n id: string;\n config: ChatConfig;\n messages: Message[];\n tools: Map<string, ToolDefinition>;\n memory: Map<string, MemoryEntry>;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface SendOptions {\n provider?: ProviderType;\n model?: string;\n temperature?: number;\n maxTokens?: number;\n tools?: ToolDefinition[];\n systemPrompt?: string;\n}\n\n// ============================================================================\n// Streaming Types\n// ============================================================================\n\nexport type StreamEventType = 'text' | 'tool_call' | 'tool_result' | 'done' | 'error';\n\nexport interface StreamEvent {\n type: StreamEventType;\n content?: string;\n toolCall?: ToolCall;\n toolResult?: ToolResult;\n error?: Error;\n message?: Message;\n}\n\n// ============================================================================\n// Memory Types\n// ============================================================================\n\nexport interface MemoryEntry {\n key: string;\n value: unknown;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface GlobalMemoryStore {\n entries: Map<string, MemoryEntry>;\n storagePath: string;\n}\n\n// ============================================================================\n// Acontext Types\n// ============================================================================\n\nexport type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'failed';\n\nexport interface ObservedTask {\n id: string;\n description: string;\n status: TaskStatus;\n progress: number; // 0-100\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface UserPreference {\n key: string;\n value: unknown;\n confidence: number; // 0-1\n source: string; // which message extracted this\n}\n\nexport interface LearnedSkill {\n id: string;\n name: string;\n description: string;\n category: string;\n steps: SkillStep[];\n successRate: number;\n usageCount: number;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface SkillStep {\n order: number;\n action: string;\n expectedInput?: string;\n expectedOutput?: string;\n}\n\nexport interface ObserverConfig {\n extractTasks: boolean;\n extractPreferences: boolean;\n autoLearn: boolean;\n}\n\nexport interface ObserverState {\n enabled: boolean;\n config: ObserverConfig;\n tasks: ObservedTask[];\n preferences: UserPreference[];\n}\n\n// ============================================================================\n// Personalization Types (ChatGPT-style settings)\n// ============================================================================\n\nexport type StyleLevel = 'low' | 'medium' | 'high';\nexport type FormattingStyle = 'minimal' | 'default' | 'rich';\n\n/**\n * 응답 스타일 설정\n */\nexport interface ResponseStyle {\n /** 따뜻함 수준 */\n warmth: StyleLevel;\n /** 열정/에너지 수준 */\n enthusiasm: StyleLevel;\n /** 이모지 사용 수준 */\n emojiUsage: StyleLevel;\n /** 포맷팅 스타일 (헤더, 목록 등) */\n formatting: FormattingStyle;\n /** 응답 길이 선호 */\n verbosity: 'concise' | 'balanced' | 'detailed';\n}\n\n/**\n * 사용자 프로필 정보\n */\nexport interface UserProfile {\n /** 사용자 닉네임/호칭 */\n nickname?: string;\n /** 직업/역할 */\n occupation?: string;\n /** 추가 정보 (관심사, 가치, 선호 사항) */\n additionalInfo?: string;\n /** 선호 언어 */\n preferredLanguage?: string;\n /** 전문 분야 */\n expertise?: string[];\n /** 커스텀 지시사항 */\n customInstructions?: string;\n}\n\n/**\n * 개인화 설정 전체\n */\nexport interface PersonalizationConfig {\n /** 응답 스타일 */\n responseStyle: ResponseStyle;\n /** 사용자 프로필 */\n userProfile: UserProfile;\n /** 메모리 참조 활성화 */\n useMemory: boolean;\n /** 언어 설정 ('auto' | 'ko' | 'en' | etc.) */\n language: string;\n}\n\n/**\n * 개인화 설정 기본값\n */\nexport const DEFAULT_PERSONALIZATION: PersonalizationConfig = {\n responseStyle: {\n warmth: 'medium',\n enthusiasm: 'medium',\n emojiUsage: 'low',\n formatting: 'default',\n verbosity: 'balanced',\n },\n userProfile: {},\n useMemory: true,\n language: 'auto',\n};\n\n// ============================================================================\n// LLM Chat Hook Integration Types\n// ============================================================================\n\n/**\n * @description Hook 결과 타입 (React Query UseMutationResult 호환)\n */\nexport interface MutationResult<TData = unknown, TError = Error, TVariables = unknown> {\n mutate: (variables: TVariables) => void;\n mutateAsync: (variables: TVariables) => Promise<TData>;\n isPending: boolean;\n isError: boolean;\n isSuccess: boolean;\n data?: TData;\n error?: TError;\n reset: () => void;\n}\n\n/**\n * @description Tool/Action Hook 타입\n */\nexport type ToolHook<TRequest = unknown, TResponse = unknown> = () => MutationResult<TResponse, Error, TRequest>;\n\n/**\n * @description AI가 자동으로 호출하는 Tool 설정\n * AI가 사용자 메시지를 분석해서 필요시 자동 호출\n */\nexport interface LLMToolConfig<TRequest = unknown, TResponse = unknown> {\n /** Tool hook */\n hook: ToolHook<TRequest, TResponse>;\n /** AI가 판단할 때 사용하는 설명 */\n description: string;\n /** JSON Schema 형태의 파라미터 정의 (선택) */\n parameters?: {\n type: 'object';\n properties: Record<string, {\n type: string;\n description?: string;\n enum?: string[];\n }>;\n required?: string[];\n };\n}\n\n/**\n * @description 사용자가 UI에서 직접 선택하는 Action 설정\n */\nexport interface LLMActionConfig<TRequest = unknown, TResponse = unknown> {\n /** Action hook */\n hook: ToolHook<TRequest, TResponse>;\n /** UI에 표시할 레이블 */\n label: string;\n /** 아이콘 이름 또는 컴포넌트 */\n icon?: string;\n /** 비활성화 여부 */\n disabled?: boolean;\n}\n\n/**\n * @description 기본 채팅(텍스트 생성) 설정\n */\nexport interface LLMChatHookConfig<TRequest = unknown, TResponse = unknown> {\n /** 텍스트 생성 hook */\n hook: ToolHook<TRequest, TResponse>;\n /** 기본 시스템 프롬프트 */\n systemPrompt?: string;\n}\n\n/**\n * @description LLM Chat 컴포넌트 Props\n */\nexport interface LLMChatComponentProps {\n /** AI가 자동 호출하는 Tools */\n tools?: Record<string, LLMToolConfig>;\n /** 사용자가 직접 선택하는 Actions */\n actions?: Record<string, LLMActionConfig>;\n /** 기본 채팅 설정 */\n chat: LLMChatHookConfig;\n /** 스타일 클래스 */\n className?: string;\n /** 개인화 설정 */\n personalization?: Partial<PersonalizationConfig>;\n}\n","/**\n * @description 글로벌 메모리 관리 훅\n * localStorage 또는 PostgreSQL API를 통해 세션 간 정보 유지\n * @license MIT\n */\n\nimport { useState, useCallback, useEffect, useRef } from 'react';\nimport type {\n UseGlobalMemoryOptions,\n UseGlobalMemoryReturn,\n GlobalMemoryState,\n ExtendedMemoryEntry,\n MemoryStorageAdapter,\n} from '../types/memory';\nimport { LocalStorageAdapter } from '../adapters/LocalStorageAdapter';\nimport { PostgreSQLAdapter } from '../adapters/PostgreSQLAdapter';\n\n/**\n * @description 저장소 어댑터 생성\n */\nfunction createAdapter(options: UseGlobalMemoryOptions): MemoryStorageAdapter {\n switch (options.storageType) {\n case 'postgresql':\n if (!options.apiEndpoint || !options.userId) {\n console.warn('[useGlobalMemory] PostgreSQL requires apiEndpoint and userId, falling back to localStorage');\n return new LocalStorageAdapter(options.storageKey);\n }\n return new PostgreSQLAdapter(options.apiEndpoint, options.userId, options.authToken);\n case 'localStorage':\n case 'memory':\n default:\n return new LocalStorageAdapter(options.storageKey);\n }\n}\n\n/**\n * @description 글로벌 메모리 훅\n * @param options 설정 옵션\n */\nexport function useGlobalMemory(options: UseGlobalMemoryOptions): UseGlobalMemoryReturn {\n const [state, setState] = useState<GlobalMemoryState>({\n entries: new Map(),\n isLoading: true,\n error: null,\n });\n\n const adapterRef = useRef<MemoryStorageAdapter>(createAdapter(options));\n\n /**\n * @description 메모리 새로고침\n */\n const refresh = useCallback(async () => {\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n try {\n const allData = await adapterRef.current.getAll();\n const entries = new Map<string, ExtendedMemoryEntry>();\n\n for (const [key, value] of allData) {\n if (typeof value === 'object' && value !== null && 'value' in value) {\n // 이미 ExtendedMemoryEntry 형식인 경우\n entries.set(key, value as ExtendedMemoryEntry);\n } else {\n // 단순 값인 경우 래핑\n entries.set(key, {\n key,\n value,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n });\n }\n }\n\n setState({ entries, isLoading: false, error: null });\n } catch (error) {\n setState((prev) => ({\n ...prev,\n isLoading: false,\n error: error instanceof Error ? error : new Error('Unknown error'),\n }));\n }\n }, []);\n\n /**\n * @description 메모리 설정\n */\n const set = useCallback(\n async (key: string, value: unknown, meta?: Partial<ExtendedMemoryEntry>) => {\n const now = Date.now();\n const existingEntry = state.entries.get(key);\n\n const entry: ExtendedMemoryEntry = {\n key,\n value,\n createdAt: existingEntry?.createdAt ?? now,\n updatedAt: now,\n category: meta?.category ?? existingEntry?.category,\n confidence: meta?.confidence ?? existingEntry?.confidence,\n source: meta?.source ?? existingEntry?.source,\n };\n\n try {\n await adapterRef.current.write(key, entry);\n setState((prev) => {\n const newEntries = new Map(prev.entries);\n newEntries.set(key, entry);\n return { ...prev, entries: newEntries };\n });\n } catch (error) {\n console.error('[useGlobalMemory] Failed to set:', error);\n }\n },\n [state.entries]\n );\n\n /**\n * @description 메모리 조회\n */\n const get = useCallback(\n <T>(key: string): T | undefined => {\n const entry = state.entries.get(key);\n return entry?.value as T | undefined;\n },\n [state.entries]\n );\n\n /**\n * @description 메모리 삭제\n */\n const remove = useCallback(async (key: string) => {\n try {\n await adapterRef.current.delete(key);\n setState((prev) => {\n const newEntries = new Map(prev.entries);\n newEntries.delete(key);\n return { ...prev, entries: newEntries };\n });\n } catch (error) {\n console.error('[useGlobalMemory] Failed to remove:', error);\n }\n }, []);\n\n /**\n * @description 키 존재 여부 확인\n */\n const has = useCallback(\n (key: string): boolean => {\n return state.entries.has(key);\n },\n [state.entries]\n );\n\n /**\n * @description 전체 삭제\n */\n const clear = useCallback(async () => {\n try {\n // 모든 키 삭제\n for (const key of state.entries.keys()) {\n await adapterRef.current.delete(key);\n }\n setState((prev) => ({ ...prev, entries: new Map() }));\n } catch (error) {\n console.error('[useGlobalMemory] Failed to clear:', error);\n }\n }, [state.entries]);\n\n /**\n * @description 시스템 프롬프트용 컨텍스트 문자열 생성\n */\n const toPromptContext = useCallback((): string => {\n if (state.entries.size === 0) return '';\n\n const lines: string[] = ['[사용자 기억 정보]'];\n\n /**\n * @description 카테고리별 그룹화 (fact/skill/preference + 기존 호환)\n * @Todo vibecode - 추출 카테고리와 UI 카테고리 통일\n */\n const categorized: Record<string, Array<{ key: string; value: unknown }>> = {\n fact: [],\n skill: [],\n preference: [],\n other: [],\n };\n\n // 기존 카테고리 → 통일 카테고리 매핑\n const categoryMapping: Record<string, string> = {\n basic: 'fact',\n professional: 'skill',\n preferences: 'preference',\n context: 'other', // 대화 맥락은 세션별 compressionState로 관리\n fact: 'fact',\n skill: 'skill',\n preference: 'preference',\n };\n\n for (const [key, entry] of state.entries) {\n const rawCategory = entry.category || 'other';\n const category = categoryMapping[rawCategory] || 'other';\n categorized[category].push({ key, value: entry.value });\n }\n\n // 카테고리별 출력\n const categoryLabels: Record<string, string> = {\n fact: '사용자 정보',\n skill: '전문 분야/기술',\n preference: '선호도',\n other: '기타',\n };\n\n for (const [category, items] of Object.entries(categorized)) {\n if (items.length > 0) {\n lines.push(`\\n${categoryLabels[category]}:`);\n for (const { key, value } of items) {\n const valueStr = typeof value === 'object' ? JSON.stringify(value) : String(value);\n lines.push(`- ${key}: ${valueStr}`);\n }\n }\n }\n\n return lines.join('\\n');\n }, [state.entries]);\n\n // 초기 로드\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n // 옵션 변경 시 어댑터 재생성\n useEffect(() => {\n adapterRef.current = createAdapter(options);\n refresh();\n }, [options.storageType, options.storageKey, options.apiEndpoint, options.userId]);\n\n return {\n state,\n set,\n get,\n remove,\n has,\n clear,\n toPromptContext,\n refresh,\n };\n}\n\nexport default useGlobalMemory;\n","/**\n * @description localStorage 기반 메모리 저장소 어댑터\n * @license MIT\n */\n\nimport type { MemoryStorageAdapter } from '../types/memory';\n\n/**\n * @description localStorage 어댑터 구현\n */\nexport class LocalStorageAdapter implements MemoryStorageAdapter {\n private storageKey: string;\n\n constructor(storageKey: string = 'chatllm_global_memory') {\n this.storageKey = storageKey;\n }\n\n /**\n * @description 전체 데이터 로드\n */\n private loadData(): Record<string, unknown> {\n if (typeof window === 'undefined') return {};\n try {\n const data = localStorage.getItem(this.storageKey);\n return data ? JSON.parse(data) : {};\n } catch {\n return {};\n }\n }\n\n /**\n * @description 전체 데이터 저장\n */\n private saveData(data: Record<string, unknown>): void {\n if (typeof window === 'undefined') return;\n try {\n localStorage.setItem(this.storageKey, JSON.stringify(data));\n } catch (error) {\n console.error('[LocalStorageAdapter] Failed to save data:', error);\n }\n }\n\n async read<T>(key: string): Promise<T | null> {\n const data = this.loadData();\n const value = data[key];\n return value !== undefined ? (value as T) : null;\n }\n\n async write<T>(key: string, value: T): Promise<void> {\n const data = this.loadData();\n data[key] = value;\n this.saveData(data);\n }\n\n async delete(key: string): Promise<boolean> {\n const data = this.loadData();\n if (key in data) {\n delete data[key];\n this.saveData(data);\n return true;\n }\n return false;\n }\n\n async exists(key: string): Promise<boolean> {\n const data = this.loadData();\n return key in data;\n }\n\n async getAll(): Promise<Map<string, unknown>> {\n const data = this.loadData();\n return new Map(Object.entries(data));\n }\n\n /**\n * @description 전체 삭제\n */\n async clear(): Promise<void> {\n if (typeof window === 'undefined') return;\n localStorage.removeItem(this.storageKey);\n }\n}\n\nexport default LocalStorageAdapter;\n","/**\n * @description PostgreSQL REST API 기반 메모리 저장소 어댑터\n * @license MIT\n */\n\nimport type { MemoryStorageAdapter } from '../types/memory';\n\n/**\n * @description PostgreSQL 어댑터 구현\n * REST API를 통해 서버의 PostgreSQL DB와 통신\n */\nexport class PostgreSQLAdapter implements MemoryStorageAdapter {\n private apiEndpoint: string;\n private userId: string;\n private authToken?: string;\n\n constructor(apiEndpoint: string, userId: string, authToken?: string) {\n this.apiEndpoint = apiEndpoint.replace(/\\/$/, ''); // 끝의 슬래시 제거\n this.userId = userId;\n this.authToken = authToken;\n }\n\n /**\n * @description HTTP 헤더 생성\n */\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n return headers;\n }\n\n /**\n * @description API 요청 헬퍼\n */\n private async request<T>(\n path: string,\n options: RequestInit = {}\n ): Promise<T | null> {\n try {\n const response = await fetch(`${this.apiEndpoint}${path}`, {\n ...options,\n headers: {\n ...this.getHeaders(),\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n if (response.status === 404) return null;\n throw new Error(`API error: ${response.status}`);\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) {\n return response.json();\n }\n return null;\n } catch (error) {\n console.error('[PostgreSQLAdapter] Request failed:', error);\n return null;\n }\n }\n\n async read<T>(key: string): Promise<T | null> {\n const result = await this.request<{ value: T }>(\n `/memory/${this.userId}/${encodeURIComponent(key)}`\n );\n return result?.value ?? null;\n }\n\n async write<T>(key: string, value: T): Promise<void> {\n await this.request(`/memory/${this.userId}`, {\n method: 'POST',\n body: JSON.stringify({ key, value }),\n });\n }\n\n async delete(key: string): Promise<boolean> {\n const result = await this.request<{ success: boolean }>(\n `/memory/${this.userId}/${encodeURIComponent(key)}`,\n { method: 'DELETE' }\n );\n return result?.success ?? false;\n }\n\n async exists(key: string): Promise<boolean> {\n try {\n const response = await fetch(\n `${this.apiEndpoint}/memory/${this.userId}/${encodeURIComponent(key)}`,\n {\n method: 'HEAD',\n headers: this.getHeaders(),\n }\n );\n return response.ok;\n } catch {\n return false;\n }\n }\n\n async getAll(): Promise<Map<string, unknown>> {\n const result = await this.request<{ entries: Record<string, unknown> }>(\n `/memory/${this.userId}`\n );\n\n if (!result?.entries) {\n return new Map();\n }\n\n return new Map(Object.entries(result.entries));\n }\n\n /**\n * @description 전체 삭제\n */\n async clear(): Promise<void> {\n await this.request(`/memory/${this.userId}`, {\n method: 'DELETE',\n });\n }\n}\n\nexport default PostgreSQLAdapter;\n","/**\n * @description 자동 정보 추출 훅\n * LLM을 사용하여 대화에서 중요 정보를 자동으로 추출\n * @license MIT\n */\n\nimport { useState, useCallback } from 'react';\nimport type {\n UseInfoExtractionOptions,\n UseInfoExtractionReturn,\n ExtractedInfo,\n ExtractionResult,\n UseGlobalMemoryReturn,\n} from '../types/memory';\n\n/**\n * @description 정보 추출 프롬프트 생성\n */\nconst buildExtractionPrompt = (\n messages: Array<{ role: string; content: string }>\n): string => {\n const conversationText = messages\n .map((m) => `${m.role === 'user' ? '사용자' : 'AI'}: ${m.content}`)\n .join('\\n\\n');\n\n return `다음 대화에서 사용자에 대해 **세션을 넘어 기억해둘 만한** 중요한 정보를 추출해주세요.\n현재 대화의 맥락(진행 중인 작업, 일시적 요청 등)은 제외합니다.\n\n대화:\n${conversationText}\n\n다음 JSON 형식으로만 응답하세요 (JSON만 출력, 다른 텍스트 없이):\n{\n \"extracted\": [\n {\n \"category\": \"fact|skill|preference\",\n \"key\": \"정보 키 (예: userName, occupation, preferredLanguage)\",\n \"value\": \"정보 값\",\n \"confidence\": 0.0-1.0,\n \"source\": \"근거가 된 원문 일부\"\n }\n ],\n \"shouldStore\": true\n}\n\n카테고리 설명:\n- fact: 이름, 나이, 위치, 회사 등 사용자 기본 정보\n- skill: 직업, 전문 분야, 사용 기술, 개발 언어\n- preference: 선호하는 응답 스타일, 언어, 관심사\n\n규칙:\n1. 명시적으로 언급된 정보만 추출 (추론 금지)\n2. 개인정보 민감도가 높은 정보(주민번호, 비밀번호, 카드번호 등)는 제외\n3. confidence는 정보의 확실성 (0.8 이상 권장)\n4. 대화에서 중요 정보가 없으면 extracted를 빈 배열로 반환\n5. key는 영문 camelCase로 작성 (예: userName, currentProject)\n6. 현재 대화에서만 유효한 일시적 맥락은 추출하지 않음`;\n};\n\n/**\n * @description 추출 결과 파싱\n */\nconst parseExtractionResult = (text: string): ExtractionResult => {\n try {\n // JSON 블록 추출 시도\n const jsonMatch = text.match(/\\{[\\s\\S]*\\}/);\n if (!jsonMatch) {\n return { extracted: [], shouldStore: false };\n }\n\n const parsed = JSON.parse(jsonMatch[0]);\n\n if (!parsed.extracted || !Array.isArray(parsed.extracted)) {\n return { extracted: [], shouldStore: false };\n }\n\n // 유효성 검증\n const validExtracted = parsed.extracted.filter(\n (item: ExtractedInfo) =>\n item.category &&\n item.key &&\n item.value !== undefined &&\n typeof item.confidence === 'number'\n );\n\n return {\n extracted: validExtracted,\n shouldStore: parsed.shouldStore ?? validExtracted.length > 0,\n };\n } catch {\n return { extracted: [], shouldStore: false };\n }\n};\n\n/**\n * @description 자동 정보 추출 훅\n */\nexport function useInfoExtraction(options: UseInfoExtractionOptions): UseInfoExtractionReturn {\n const [isExtracting, setIsExtracting] = useState(false);\n const [lastExtraction, setLastExtraction] = useState<ExtractedInfo[] | null>(null);\n\n const { apiEndpoint, model, minConfidence = 0.8, globalMemory, onCallLLM } = options;\n\n /**\n * @description 대화에서 정보 추출\n * @Todo vibecode - onCallLLM 제공 시 호스트 콜백 재활용 (onSendMessage 모드 지원)\n */\n const extractInfo = useCallback(\n async (messages: Array<{ role: string; content: string }>): Promise<ExtractedInfo[]> => {\n if (messages.length === 0) {\n return [];\n }\n\n setIsExtracting(true);\n\n try {\n const prompt = buildExtractionPrompt(messages);\n let fullResponse: string;\n\n if (onCallLLM) {\n /** @Todo vibecode - onSendMessage 모드: callInternalLLM 재활용 */\n fullResponse = await onCallLLM(prompt, model || 'default');\n } else {\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [{ role: 'user', content: prompt }],\n model: model || 'default',\n }),\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n return [];\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n fullResponse = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n try {\n const parsed = JSON.parse(data);\n const chunk = parsed.content ?? parsed.text ?? '';\n if (chunk) fullResponse += chunk;\n } catch {\n // Ignore parse errors\n }\n }\n }\n }\n }\n\n // 결과 파싱\n const result = parseExtractionResult(fullResponse);\n const extracted = result.extracted.filter(\n (item) => item.confidence >= minConfidence\n );\n\n // 글로벌 메모리에 저장\n if (result.shouldStore && globalMemory) {\n for (const item of extracted) {\n await globalMemory.set(`${item.category}.${item.key}`, item.value, {\n category: item.category,\n confidence: item.confidence,\n source: item.source,\n });\n }\n }\n\n setLastExtraction(extracted);\n return extracted;\n } catch (error) {\n console.error('[useInfoExtraction] Failed to extract:', error);\n return [];\n } finally {\n setIsExtracting(false);\n }\n },\n [apiEndpoint, model, minConfidence, globalMemory, onCallLLM]\n );\n\n return {\n extractInfo,\n isExtracting,\n lastExtraction,\n };\n}\n\nexport default useInfoExtraction;\n","/**\n * @description 스킬 관리 훅\n * @Todo vibecode - 시스템 프롬프트 생성, auto 스킬 실행, manual 스킬 관리\n *\n * useChatUI에서 호출하여 스킬 관련 로직을 분리합니다.\n */\n\nimport { useState, useCallback, useMemo, useRef } from 'react';\nimport type {\n SkillConfig,\n SkillExecution,\n SkillExecutionResult,\n SkillProgress,\n SkillExecuteCallbacks,\n ManualSkillItem,\n DeepResearchCallbacks,\n} from '../types';\nimport { parseSkillCallFromContent } from '../utils/skillParser';\nimport type { ParsedSkillCall } from '../utils/skillParser';\nimport { createDeepResearchSkill } from '../utils/deepResearchAdapter';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface UseSkillsOptions {\n /** 사용자 등록 스킬 */\n skills?: Record<string, SkillConfig>;\n /** @deprecated 하위 호환용 deepResearch */\n deepResearch?: DeepResearchCallbacks;\n}\n\nexport interface UseSkillsReturn {\n /** 시스템 프롬프트에 추가할 스킬 가이드 텍스트 */\n buildSkillsPrompt: () => string;\n /**\n * @description 스트리밍 완료 후 skill_use 태그 감지 및 실행\n * @Todo vibecode - callbacks로 진행 상태/스트리밍/중단 시그널 전달\n * @returns skillCall이 있으면 실행하고 결과 반환, 없으면 null\n */\n handleSkillCall: (\n content: string,\n callbacks?: SkillExecuteCallbacks\n ) => Promise<{\n skillCall: ParsedSkillCall | null;\n cleanContent: string;\n result: SkillExecutionResult | null;\n }>;\n /** manual 스킬 목록 (UI 표시용) */\n manualSkills: ManualSkillItem[];\n /** manual 스킬 직접 실행 */\n executeManualSkill: (\n skillName: string,\n params?: Record<string, unknown>,\n callbacks?: SkillExecuteCallbacks\n ) => Promise<SkillExecutionResult | null>;\n /** 현재 실행 중인 스킬 */\n activeSkillExecution: SkillExecution | null;\n /** 통합된 스킬 맵 (deepResearch 포함) */\n resolvedSkills: Record<string, SkillConfig>;\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport const useSkills = (options: UseSkillsOptions): UseSkillsReturn => {\n const [activeSkillExecution, setActiveSkillExecution] = useState<SkillExecution | null>(null);\n const executionAbortRef = useRef<AbortController | null>(null);\n\n /**\n * @description 통합 스킬 맵 생성\n * @Todo vibecode - deepResearch prop이 존재하면 내장 스킬로 자동 변환 (하위 호환)\n */\n const resolvedSkills = useMemo((): Record<string, SkillConfig> => {\n const skills: Record<string, SkillConfig> = { ...(options.skills || {}) };\n\n if (options.deepResearch?.onWebSearch && !skills.deepResearch) {\n skills.deepResearch = createDeepResearchSkill(options.deepResearch);\n }\n\n return skills;\n }, [options.skills, options.deepResearch]);\n\n /**\n * @description manual/both 트리거 스킬 목록 (UI 메뉴 표시용)\n */\n const manualSkills = useMemo((): ManualSkillItem[] => {\n return Object.entries(resolvedSkills)\n .filter(([, config]) => config.trigger === 'manual' || config.trigger === 'both')\n .map(([name, config]) => ({\n name,\n label: config.label,\n icon: config.icon,\n description: config.description,\n disabled: config.disabled,\n }));\n }, [resolvedSkills]);\n\n /**\n * @description auto/both 스킬을 시스템 프롬프트 텍스트로 변환\n * @Todo vibecode - AI가 필요시 <skill_use> 태그로 호출할 수 있도록 가이드\n * enum, required/optional, 예시 포함하여 AI가 도구를 확실히 호출하도록 강화\n */\n const buildSkillsPrompt = useCallback((): string => {\n const autoSkills = Object.entries(resolvedSkills).filter(\n ([, config]) => config.trigger === 'auto' || config.trigger === 'both'\n );\n\n if (autoSkills.length === 0) return '';\n\n const skillDescriptions = autoSkills\n .map(([name, config]) => {\n let desc = `### ${name}\\n${config.description}`;\n\n if (config.parameters?.properties) {\n desc += '\\n파라미터:';\n const props = config.parameters.properties;\n const requiredList = config.parameters.required || [];\n\n Object.entries(props).forEach(([key, prop]) => {\n const isRequired = requiredList.includes(key);\n const tag = isRequired ? '(필수)' : '(선택)';\n let line = `\\n- ${key} ${tag}: ${prop.description || prop.type}`;\n if (prop.enum) {\n line += ` [가능한 값: ${prop.enum.join(', ')}]`;\n }\n desc += line;\n });\n\n /** @Todo vibecode - 각 스킬별 호출 예시 자동 생성 */\n const exampleParams: Record<string, string> = {};\n Object.entries(props).forEach(([key, prop]) => {\n if (prop.enum) {\n exampleParams[key] = prop.enum[0];\n } else if (prop.description) {\n exampleParams[key] = `${prop.description}`;\n } else {\n exampleParams[key] = key;\n }\n });\n desc += `\\n예시: <skill_use name=\"${name}\">${JSON.stringify(exampleParams)}</skill_use>`;\n }\n\n return desc;\n })\n .join('\\n\\n');\n\n return `## 사용 가능한 도구\n\n아래 도구를 적극적으로 사용하세요. 사용자의 요청에 맞는 도구가 있으면 반드시 호출해야 합니다.\n\n호출 형식:\n<skill_use name=\"도구이름\">{\"파라미터\": \"값\"}</skill_use>\n\n${skillDescriptions}\n\n**규칙:**\n- 이미지 생성/그림/일러스트 요청 → 반드시 generate_image 도구 호출\n- 최신 정보/검색/뉴스 요청 → 반드시 web_search 도구 호출\n- 도구 호출 시 짧은 안내 메시지를 먼저 작성하고, 그 뒤에 skill_use 태그를 포함하세요\n- 한 번에 하나의 도구만 호출하세요\n- 도구 없이 텍스트로만 답변하지 마세요 (해당 도구가 있는 경우)\n- 도구가 실행되면 결과가 자동으로 전달됩니다`;\n }, [resolvedSkills]);\n\n /**\n * @description 스트리밍 완료 후 <skill_use> 태그 감지 및 실행\n * @Todo vibecode - 태그 파싱 → 스킬 execute 호출 → 결과 반환\n * callbacks로 진행 상태(onProgress), 스트리밍(onStream), 중단(signal) 전달\n */\n const handleSkillCall = useCallback(\n async (\n content: string,\n callbacks?: SkillExecuteCallbacks\n ): Promise<{\n skillCall: ParsedSkillCall | null;\n cleanContent: string;\n result: SkillExecutionResult | null;\n }> => {\n const { skillCall, cleanContent } = parseSkillCallFromContent(content);\n\n if (!skillCall) {\n return { skillCall: null, cleanContent: content, result: null };\n }\n\n const skill = resolvedSkills[skillCall.name];\n if (!skill) {\n console.warn(`[useSkills] 등록되지 않은 스킬: ${skillCall.name}`);\n return { skillCall, cleanContent, result: null };\n }\n\n /** @Todo vibecode - 스킬 실행 상태 추적 시작 */\n setActiveSkillExecution({\n skillName: skillCall.name,\n params: skillCall.params,\n status: 'executing',\n });\n\n const abortController = new AbortController();\n executionAbortRef.current = abortController;\n\n try {\n /** @Todo vibecode - 콜백 머지: 내부 상태 업데이트 + 외부 콜백 전달 */\n const mergedCallbacks: SkillExecuteCallbacks = {\n onProgress: (progress) => {\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, progress } : null\n );\n callbacks?.onProgress?.(progress);\n },\n onStream: callbacks?.onStream,\n signal: callbacks?.signal || abortController.signal,\n };\n\n const result = await skill.execute(skillCall.params, mergedCallbacks);\n\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, status: 'done', result } : null\n );\n\n return { skillCall, cleanContent, result };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, status: 'error', error: errorMsg } : null\n );\n\n return {\n skillCall,\n cleanContent,\n result: { content: `스킬 실행 오류: ${errorMsg}` },\n };\n } finally {\n executionAbortRef.current = null;\n }\n },\n [resolvedSkills]\n );\n\n /**\n * @description manual 스킬 직접 실행\n * @Todo vibecode - 사용자가 UI에서 스킬 선택 시 호출\n * callbacks로 진행 상태/스트리밍/중단 시그널 전달\n */\n const executeManualSkill = useCallback(\n async (\n skillName: string,\n params?: Record<string, unknown>,\n callbacks?: SkillExecuteCallbacks\n ): Promise<SkillExecutionResult | null> => {\n const skill = resolvedSkills[skillName];\n if (!skill) return null;\n\n setActiveSkillExecution({\n skillName,\n params: params || {},\n status: 'executing',\n });\n\n const abortController = new AbortController();\n executionAbortRef.current = abortController;\n\n try {\n /** @Todo vibecode - 콜백 머지: 내부 상태 업데이트 + 외부 콜백 전달 */\n const mergedCallbacks: SkillExecuteCallbacks = {\n onProgress: (progress) => {\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, progress } : null\n );\n callbacks?.onProgress?.(progress);\n },\n onStream: callbacks?.onStream,\n signal: callbacks?.signal || abortController.signal,\n };\n\n const result = await skill.execute(params || {}, mergedCallbacks);\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, status: 'done', result } : null\n );\n return result;\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n setActiveSkillExecution((prev) =>\n prev ? { ...prev, status: 'error', error: errorMsg } : null\n );\n return null;\n } finally {\n executionAbortRef.current = null;\n }\n },\n [resolvedSkills]\n );\n\n return {\n buildSkillsPrompt,\n handleSkillCall,\n manualSkills,\n executeManualSkill,\n activeSkillExecution,\n resolvedSkills,\n };\n};\n\nexport default useSkills;\n","/**\n * @description Skill 파싱 유틸리티\n * @Todo vibecode - AI 응답에서 <skill_use> 태그 파싱\n *\n * 형식:\n * <skill_use name=\"deepResearch\">{\"query\":\"검색어\"}</skill_use>\n */\n\n/**\n * @description 파싱된 스킬 호출 정보\n */\nexport interface ParsedSkillCall {\n /** 스킬 이름 */\n name: string;\n /** 실행 파라미터 */\n params: Record<string, unknown>;\n /** 원본 매칭 문자열 */\n rawMatch: string;\n}\n\n/**\n * @description AI 응답에서 <skill_use> 태그 파싱\n * @Todo vibecode - 첫 번째 매칭만 처리 (스킬은 한번에 하나씩)\n */\nexport const parseSkillCallFromContent = (\n content: string\n): { skillCall: ParsedSkillCall | null; cleanContent: string } => {\n const skillRegex = /<skill_use\\s+name=[\"']([^\"']+)[\"']>([\\s\\S]*?)<\\/skill_use>/i;\n const match = skillRegex.exec(content);\n\n if (!match) {\n return { skillCall: null, cleanContent: content };\n }\n\n const name = match[1];\n let params: Record<string, unknown> = {};\n try {\n params = JSON.parse(match[2].trim());\n } catch {\n /** @Todo vibecode - JSON 파싱 실패 시 텍스트를 query 파라미터로 사용 */\n params = { query: match[2].trim() };\n }\n\n const cleanContent = content.replace(match[0], '').trim();\n return {\n skillCall: { name, params, rawMatch: match[0] },\n cleanContent,\n };\n};\n\nexport default parseSkillCallFromContent;\n","/**\n * @description 고급 딥리서치 스킬 생성기\n * @Todo vibecode - useDeepResearch 4단계 파이프라인을 SkillConfig으로 통합\n *\n * 4단계 아키텍처:\n * 1. 쿼리 분석 - LLM이 서브토픽 + 검색 쿼리 분해\n * 2. 병렬 검색 - 토픽별 병렬 서브에이전트\n * 3. 충분성 평가 - 소스 부족 시 추가 검색\n * 4. 보고서 생성 - LLM 스트리밍 보고서 + 인라인 인용\n */\n\nimport type {\n SkillConfig,\n SkillExecutionResult,\n SkillExecuteCallbacks,\n SkillProgress,\n SearchResult,\n SourceItem,\n SubAgentProgress,\n DeepResearchCallbacks,\n} from '../types';\n\n// ============================================================================\n// 옵션 타입\n// ============================================================================\n\n/**\n * @description 고급 딥리서치 스킬 옵션\n * @Todo vibecode - 라이브러리 사용자가 제공하는 검색 API + LLM 엔드포인트\n */\nexport interface AdvancedResearchOptions {\n /** 웹 검색 API 호출 (필수) */\n onWebSearch: (query: string) => Promise<SearchResult[]>;\n /** 페이지 본문 추출 (선택) */\n onExtractContent?: (url: string) => Promise<string>;\n /** LLM API 엔드포인트 */\n apiEndpoint: string;\n /** API 키 */\n apiKey?: string;\n /** 사용할 모델 */\n model: string;\n /** 프로바이더 */\n provider: string;\n}\n\n// ============================================================================\n// 프롬프트 템플릿\n// ============================================================================\n\n/** @Todo vibecode - 1단계: 쿼리 분석 프롬프트 */\nconst QUERY_ANALYSIS_PROMPT = `사용자 질문을 분석하여 심층연구를 위한 검색 계획을 수립하세요.\n\n<user_question>\n{question}\n</user_question>\n\n응답은 반드시 다음 JSON 형식으로만 작성하세요:\n{\n \"questionType\": \"factCheck\" | \"comparison\" | \"comprehensive\",\n \"topics\": [\"서브토픽1\", \"서브토픽2\", \"서브토픽3\"],\n \"searchQueries\": [\"검색어1\", \"검색어2\", \"검색어3\", \"검색어4\", \"검색어5\"]\n}\n\n규칙:\n- topics: 3-5개의 핵심 서브토픽\n- searchQueries: 5-8개의 다양한 검색 쿼리 (한국어/영어 혼합)\n- JSON 외 다른 텍스트 출력 금지`;\n\n/** @Todo vibecode - 4단계: 보고서 생성 프롬프트 */\nconst REPORT_GENERATION_PROMPT = `당신은 리서치 보고서 작성 전문가입니다.\n\n<collected_sources>\n{sources_json}\n</collected_sources>\n\n<user_question>\n{question}\n</user_question>\n\n<format_rules>\n1. 핵심 요약 2-3문장으로 시작 (헤더 없이)\n2. ## 헤더로 섹션 구분\n3. 문장 끝에 인라인 인용 [1][2] 형태로 출처 표시\n4. 종합 결론으로 마무리\n5. 이모지 사용 금지\n</format_rules>\n\n<structure>\n[요약 2-3문장]\n\n## 상세 분석\n깊이 있는 분석 [1][2]\n\n## 주요 발견\n- 핵심 포인트 1 [3]\n- 핵심 포인트 2 [4]\n\n## 결론\n종합적인 결론\n</structure>`;\n\n// ============================================================================\n// 내부 타입\n// ============================================================================\n\ninterface ResearchPlan {\n questionType: 'factCheck' | 'comparison' | 'comprehensive';\n topics: string[];\n searchQueries: string[];\n}\n\ninterface SubAgentResult {\n topic: string;\n sources: SearchResult[];\n}\n\n// ============================================================================\n// 순수 함수: LLM 호출\n// ============================================================================\n\n/**\n * @description LLM API 비스트리밍 호출\n * @Todo vibecode - useDeepResearch.callLLM 순수 함수 버전\n */\nconst callLLM = async (\n prompt: string,\n opts: { apiEndpoint: string; apiKey?: string; model: string; provider: string; signal?: AbortSignal }\n): Promise<string> => {\n const response = await fetch(opts.apiEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(opts.apiKey && { Authorization: `Bearer ${opts.apiKey}` }),\n },\n body: JSON.stringify({\n model: opts.model,\n provider: opts.provider,\n messages: [{ role: 'user', content: prompt }],\n stream: false,\n }),\n signal: opts.signal,\n });\n\n if (!response.ok) throw new Error(`API 오류: ${response.status}`);\n const data = await response.json();\n return data.choices?.[0]?.message?.content || data.content || '';\n};\n\n/**\n * @description LLM API 스트리밍 호출\n * @Todo vibecode - 보고서 생성 시 실시간 청크 전달\n */\nconst callLLMStream = async (\n prompt: string,\n opts: { apiEndpoint: string; apiKey?: string; model: string; provider: string; signal?: AbortSignal },\n onChunk: (chunk: string) => void\n): Promise<string> => {\n const response = await fetch(opts.apiEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(opts.apiKey && { Authorization: `Bearer ${opts.apiKey}` }),\n },\n body: JSON.stringify({\n model: opts.model,\n provider: opts.provider,\n messages: [{ role: 'user', content: prompt }],\n stream: true,\n }),\n signal: opts.signal,\n });\n\n if (!response.ok) throw new Error(`API 오류: ${response.status}`);\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader');\n\n const decoder = new TextDecoder();\n let fullContent = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n const lines = chunk.split('\\n');\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n\n try {\n const parsed = JSON.parse(data);\n const content = parsed.choices?.[0]?.delta?.content || parsed.delta?.content || parsed.message?.content || parsed.content || parsed.text || '';\n if (content) {\n fullContent += content;\n onChunk(content);\n }\n } catch {\n /** @Todo vibecode - JSON 파싱 실패 시 무시 */\n }\n }\n }\n }\n\n return fullContent;\n};\n\n// ============================================================================\n// 순수 함수: 4단계 파이프라인\n// ============================================================================\n\n/**\n * @description 1단계: 쿼리 분석 - LLM이 서브토픽과 검색 쿼리 분해\n * @Todo vibecode - useDeepResearch.analyzeQuery 순수 함수 버전\n */\nconst analyzeQuery = async (\n query: string,\n llmOpts: { apiEndpoint: string; apiKey?: string; model: string; provider: string; signal?: AbortSignal }\n): Promise<ResearchPlan> => {\n const prompt = QUERY_ANALYSIS_PROMPT.replace('{question}', query);\n const response = await callLLM(prompt, llmOpts);\n\n try {\n const jsonMatch = response.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n return JSON.parse(jsonMatch[0]) as ResearchPlan;\n }\n } catch {\n /** @Todo vibecode - JSON 파싱 실패 시 기본 플랜 */\n }\n\n return {\n questionType: 'comprehensive',\n topics: [query],\n searchQueries: [query, `${query} 최신`, `${query} 상세`],\n };\n};\n\n/**\n * @description 2단계: 서브에이전트 실행 - 토픽별 병렬 검색\n * @Todo vibecode - useDeepResearch.runSubAgent 순수 함수 버전\n */\nconst runSubAgent = async (\n topic: string,\n queries: string[],\n onWebSearch: (query: string) => Promise<SearchResult[]>,\n onExtractContent: ((url: string) => Promise<string>) | undefined,\n updateProgress: (update: Partial<SubAgentProgress>) => void\n): Promise<SubAgentResult> => {\n updateProgress({ status: 'searching', searchCount: 0, resultsCount: 0 });\n\n const allResults: SearchResult[] = [];\n let searchCount = 0;\n\n for (const query of queries.slice(0, 3)) {\n try {\n searchCount++;\n updateProgress({ searchCount });\n\n const results = await onWebSearch(query);\n allResults.push(...results);\n updateProgress({ resultsCount: allResults.length });\n\n if (allResults.length >= 10) break;\n } catch (error) {\n /** @Todo vibecode - 개별 검색 실패 시 무시하고 계속 */\n console.error(`검색 오류 (${query}):`, error);\n }\n }\n\n /** @Todo vibecode - 본문 추출 (선택) */\n if (onExtractContent && allResults.length > 0) {\n updateProgress({ status: 'extracting' });\n\n const topResults = allResults.slice(0, 5);\n await Promise.all(\n topResults.map(async (result) => {\n try {\n const content = await onExtractContent(result.url);\n result.content = content.slice(0, 2000);\n } catch {\n /** @Todo vibecode - 추출 실패 시 스니펫 사용 */\n }\n })\n );\n }\n\n updateProgress({ status: 'done' });\n return { topic, sources: allResults };\n};\n\n/**\n * @description 4단계: 보고서 생성 - LLM 스트리밍\n * @Todo vibecode - useDeepResearch.generateReport 순수 함수 버전\n */\nconst generateReport = async (\n query: string,\n results: SubAgentResult[],\n llmOpts: { apiEndpoint: string; apiKey?: string; model: string; provider: string; signal?: AbortSignal },\n onChunk: (chunk: string) => void\n): Promise<{ content: string; sources: SourceItem[] }> => {\n const allSources: SourceItem[] = [];\n const sourcesForPrompt: { index: number; title: string; url: string; snippet: string }[] = [];\n\n results.forEach((result) => {\n result.sources.forEach((source) => {\n const index = allSources.length + 1;\n allSources.push({\n id: `source-${index}`,\n title: source.title,\n url: source.url,\n snippet: source.snippet,\n });\n sourcesForPrompt.push({\n index,\n title: source.title,\n url: source.url,\n snippet: source.content || source.snippet,\n });\n });\n });\n\n const prompt = REPORT_GENERATION_PROMPT\n .replace('{sources_json}', JSON.stringify(sourcesForPrompt, null, 2))\n .replace('{question}', query);\n\n const content = await callLLMStream(prompt, llmOpts, onChunk);\n return { content, sources: allSources };\n};\n\n// ============================================================================\n// 공개 API\n// ============================================================================\n\n/**\n * @description 고급 딥리서치 SkillConfig 생성\n * @Todo vibecode - 4단계 파이프라인을 SkillConfig으로 래핑\n *\n * @example\n * ```tsx\n * skills={{\n * deepResearch: createAdvancedResearchSkill({\n * onWebSearch: mySearchAPI,\n * apiEndpoint: '/api/chat',\n * model: 'gpt-4o-mini',\n * provider: 'devdive',\n * })\n * }}\n * ```\n */\nexport const createAdvancedResearchSkill = (\n options: AdvancedResearchOptions\n): SkillConfig => {\n const { onWebSearch, onExtractContent, apiEndpoint, apiKey, model, provider } = options;\n\n return {\n description: '심층 리서치 수행 - 웹 검색을 통해 여러 소스를 조사하고 종합 보고서를 생성합니다',\n trigger: 'both',\n execute: async (params, callbacks?): Promise<SkillExecutionResult> => {\n const query = (params as { query: string }).query;\n if (!query) {\n return { content: '검색어가 필요합니다.' };\n }\n\n const llmOpts = { apiEndpoint, apiKey, model, provider, signal: callbacks?.signal };\n const subAgentStates = new Map<string, SubAgentProgress>();\n\n /** @Todo vibecode - 서브에이전트 진행 상태를 통합하여 onProgress 호출 */\n const emitProgress = (phase: string, phaseLabel: string) => {\n callbacks?.onProgress?.({\n phase,\n phaseLabel,\n subAgents: Array.from(subAgentStates.values()),\n totalSources: Array.from(subAgentStates.values()).reduce(\n (sum, a) => sum + a.resultsCount, 0\n ),\n });\n };\n\n const updateSubAgent = (id: string, update: Partial<SubAgentProgress>) => {\n const current = subAgentStates.get(id) || {\n id, topic: '', status: 'pending' as const, searchCount: 0, resultsCount: 0,\n };\n subAgentStates.set(id, { ...current, ...update });\n emitProgress('researching', '정보 수집 중...');\n };\n\n // ── 1단계: 쿼리 분석 ──\n callbacks?.onProgress?.({\n phase: 'analyzing',\n phaseLabel: '질문 분석 중...',\n subAgents: [],\n totalSources: 0,\n });\n\n const plan = await analyzeQuery(query, llmOpts);\n\n // ── 2단계: 병렬 서브에이전트 실행 ──\n plan.topics.forEach((topic, index) => {\n subAgentStates.set(`agent-${index}`, {\n id: `agent-${index}`,\n topic,\n status: 'pending',\n searchCount: 0,\n resultsCount: 0,\n });\n });\n emitProgress('researching', '정보 수집 중...');\n\n const results = await Promise.all(\n plan.topics.map((topic, index) => {\n const agentId = `agent-${index}`;\n const relatedQueries = plan.searchQueries.filter(\n (q) =>\n q.toLowerCase().includes(topic.toLowerCase()) ||\n topic.toLowerCase().includes(q.toLowerCase().split(' ')[0])\n );\n const queries = relatedQueries.length > 0\n ? relatedQueries\n : [topic, ...plan.searchQueries.slice(0, 2)];\n\n return runSubAgent(\n topic,\n queries,\n onWebSearch,\n onExtractContent,\n (update) => updateSubAgent(agentId, { ...update, topic })\n );\n })\n );\n\n // ── 3단계: 충분성 평가 ──\n callbacks?.onProgress?.({\n phase: 'evaluating',\n phaseLabel: '결과 평가 중...',\n subAgents: Array.from(subAgentStates.values()),\n totalSources: results.reduce((sum, r) => sum + r.sources.length, 0),\n });\n\n const totalSources = results.reduce((sum, r) => sum + r.sources.length, 0);\n\n /** @Todo vibecode - 소스 부족 시 추가 검색 */\n if (totalSources < 5) {\n const additionalId = 'agent-additional';\n subAgentStates.set(additionalId, {\n id: additionalId,\n topic: query,\n status: 'pending',\n searchCount: 0,\n resultsCount: 0,\n });\n emitProgress('researching', '추가 검색 중...');\n\n const additionalResult = await runSubAgent(\n query,\n [query, `${query} 정보`, `${query} 최신 뉴스`],\n onWebSearch,\n onExtractContent,\n (update) => updateSubAgent(additionalId, { ...update, topic: query })\n );\n results.push(additionalResult);\n }\n\n // ── 4단계: 보고서 생성 ──\n callbacks?.onProgress?.({\n phase: 'generating',\n phaseLabel: '보고서 작성 중...',\n subAgents: Array.from(subAgentStates.values()),\n totalSources: results.reduce((sum, r) => sum + r.sources.length, 0),\n });\n\n const report = await generateReport(\n query,\n results,\n llmOpts,\n (chunk) => callbacks?.onStream?.(chunk)\n );\n\n callbacks?.onProgress?.({\n phase: 'done',\n phaseLabel: '완료',\n subAgents: Array.from(subAgentStates.values()),\n totalSources: report.sources.length,\n });\n\n return {\n content: report.content,\n sources: report.sources,\n };\n },\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string', description: '검색할 질문' },\n },\n required: ['query'],\n },\n icon: 'search',\n label: '심층연구',\n };\n};\n\n/**\n * @description 하위 호환용 단순 딥리서치 스킬 생성 (기존 DeepResearchCallbacks 래핑)\n * @deprecated createAdvancedResearchSkill 사용 권장\n * @Todo vibecode - 기존 deepResearch prop 사용자를 위한 하위 호환\n */\nexport const createDeepResearchSkill = (\n callbacks: DeepResearchCallbacks\n): SkillConfig => {\n return {\n description: '심층 리서치 수행 - 웹 검색을 통해 여러 소스를 조사하고 종합 보고서를 생성합니다',\n trigger: 'both',\n execute: async (params, skillCallbacks?): Promise<SkillExecutionResult> => {\n const query = (params as { query: string }).query;\n if (!query) {\n return { content: '검색어가 필요합니다.' };\n }\n\n const allSources: SourceItem[] = [];\n const searchQueries = [query, `${query} 최신`, `${query} 상세`];\n\n skillCallbacks?.onProgress?.({\n phase: 'researching',\n phaseLabel: '정보 수집 중...',\n subAgents: searchQueries.map((q, i) => ({\n id: `agent-${i}`,\n topic: q,\n status: 'searching' as const,\n searchCount: 0,\n resultsCount: 0,\n })),\n totalSources: 0,\n });\n\n for (const q of searchQueries) {\n try {\n const results = await callbacks.onWebSearch(q);\n results.forEach((r) => {\n allSources.push({\n id: `source-${allSources.length + 1}`,\n title: r.title,\n url: r.url,\n snippet: r.snippet,\n });\n });\n } catch {\n /** @Todo vibecode - 개별 검색 실패 시 무시하고 계속 */\n }\n }\n\n skillCallbacks?.onProgress?.({\n phase: 'done',\n phaseLabel: '완료',\n subAgents: [],\n totalSources: allSources.length,\n });\n\n const sourceSummary = allSources\n .slice(0, 15)\n .map((s, i) => `[${i + 1}] ${s.title}\\n${s.snippet}\\nURL: ${s.url}`)\n .join('\\n\\n');\n\n return {\n content: sourceSummary || '검색 결과가 없습니다.',\n sources: allSources.slice(0, 15),\n };\n },\n parameters: {\n type: 'object',\n properties: {\n query: { type: 'string', description: '검색할 질문' },\n },\n required: ['query'],\n },\n icon: 'search',\n label: '심층연구',\n };\n};\n\nexport default createAdvancedResearchSkill;\n","/**\n * @description 프로젝트 관리 훅 - CRUD, lazy loading, 기본 프로젝트 관리\n * @Todo vibecode - useChatUI의 세션 관리 패턴을 따름\n */\n\nimport { useState, useCallback, useEffect, useRef } from 'react';\nimport type { ChatProject, ProjectFile } from '../types';\nimport { DEFAULT_PROJECT_ID, createDefaultProject } from '../utils/projectMigration';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface UseProjectOptions {\n /** @Todo vibecode - false이면 Hook 내부 로직 비활성 (Hook 규칙 준수용) */\n enabled?: boolean;\n /** 외부 스토리지 사용 여부 */\n useExternalStorage?: boolean;\n /** 스토리지 키 (localStorage 사용 시) */\n storageKey?: string;\n /** @Todo vibecode - 외부 스토리지 콜백들 */\n onLoadProjects?: () => Promise<{ id: string; title: string }[]>;\n onCreateProject?: (data: Partial<ChatProject>) => Promise<{ id: string; title: string }>;\n onLoadProject?: (projectId: string) => Promise<ChatProject>;\n onUpdateProject?: (projectId: string, data: Partial<ChatProject>) => Promise<void>;\n onDeleteProject?: (projectId: string) => Promise<void>;\n onAddProjectFile?: (projectId: string, file: File) => Promise<ProjectFile>;\n onDeleteProjectFile?: (projectId: string, fileId: string) => Promise<void>;\n onError?: (error: Error) => void;\n}\n\nexport interface UseProjectReturn {\n projects: ChatProject[];\n currentProjectId: string | null;\n currentProject: ChatProject | null;\n isProjectsLoading: boolean;\n createProject: (data: { title: string; description?: string; instructions?: string }) => Promise<string>;\n selectProject: (projectId: string) => Promise<void>;\n updateProject: (projectId: string, data: Partial<ChatProject>) => Promise<void>;\n deleteProject: (projectId: string) => Promise<void>;\n addFile: (projectId: string, file: File) => Promise<void>;\n deleteFile: (projectId: string, fileId: string) => Promise<void>;\n}\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\nconst generateId = (prefix: string): string =>\n `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport const useProject = (options: UseProjectOptions): UseProjectReturn => {\n const {\n enabled = true,\n useExternalStorage,\n storageKey = 'chatllm_sessions_projects',\n onLoadProjects,\n onCreateProject,\n onLoadProject,\n onUpdateProject,\n onDeleteProject,\n onAddProjectFile,\n onDeleteProjectFile,\n onError,\n } = options;\n\n const [projects, setProjects] = useState<ChatProject[]>([]);\n const [currentProjectId, setCurrentProjectId] = useState<string | null>(null);\n const [isProjectsLoading, setIsProjectsLoading] = useState(false);\n const initializedRef = useRef(false);\n\n // ============================================================================\n // Derived state\n // ============================================================================\n\n const currentProject = projects.find((p) => p.id === currentProjectId) || null;\n\n // ============================================================================\n // localStorage 저장\n // ============================================================================\n\n /** @Todo vibecode - localStorage 모드에서 프로젝트 상태 자동 저장 */\n useEffect(() => {\n if (!enabled || useExternalStorage || !initializedRef.current) return;\n if (projects.length > 0 && typeof window !== 'undefined') {\n localStorage.setItem(storageKey, JSON.stringify(projects));\n }\n }, [enabled, projects, storageKey, useExternalStorage]);\n\n // ============================================================================\n // 초기 로드\n // ============================================================================\n\n useEffect(() => {\n if (!enabled || initializedRef.current) return;\n initializedRef.current = true;\n\n const loadProjects = async () => {\n if (useExternalStorage && onLoadProjects) {\n /** @Todo vibecode - 외부 스토리지에서 프로젝트 목록 로드 */\n setIsProjectsLoading(true);\n try {\n const projectList = await onLoadProjects();\n const loadedProjects: ChatProject[] = projectList.map((p) => ({\n id: p.id,\n title: p.title,\n files: [],\n createdAt: Date.now(),\n updatedAt: Date.now(),\n }));\n\n /** @Todo vibecode - 기본 프로젝트 없으면 추가 */\n if (!loadedProjects.find((p) => p.id === DEFAULT_PROJECT_ID)) {\n loadedProjects.unshift(createDefaultProject());\n }\n\n setProjects(loadedProjects);\n setCurrentProjectId(loadedProjects[0]?.id || DEFAULT_PROJECT_ID);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n /** @Todo vibecode - 로드 실패 시 기본 프로젝트만 생성 */\n const fallback = [createDefaultProject()];\n setProjects(fallback);\n setCurrentProjectId(DEFAULT_PROJECT_ID);\n } finally {\n setIsProjectsLoading(false);\n }\n } else {\n /** @Todo vibecode - localStorage에서 프로젝트 로드 */\n try {\n const saved = typeof window !== 'undefined' ? localStorage.getItem(storageKey) : null;\n if (saved) {\n const parsed: ChatProject[] = JSON.parse(saved);\n if (!parsed.find((p) => p.id === DEFAULT_PROJECT_ID)) {\n parsed.unshift(createDefaultProject());\n }\n setProjects(parsed);\n setCurrentProjectId(parsed[0]?.id || DEFAULT_PROJECT_ID);\n } else {\n /** @Todo vibecode - 최초 사용 시 기본 프로젝트 생성 */\n const initial = [createDefaultProject()];\n setProjects(initial);\n setCurrentProjectId(DEFAULT_PROJECT_ID);\n }\n } catch {\n const initial = [createDefaultProject()];\n setProjects(initial);\n setCurrentProjectId(DEFAULT_PROJECT_ID);\n }\n }\n };\n\n loadProjects();\n }, [useExternalStorage, onLoadProjects, onError, storageKey]);\n\n // ============================================================================\n // Actions\n // ============================================================================\n\n /** @Todo vibecode - 프로젝트 생성 */\n const createProject = useCallback(\n async (data: { title: string; description?: string; instructions?: string }): Promise<string> => {\n const now = Date.now();\n\n if (useExternalStorage && onCreateProject) {\n try {\n const created = await onCreateProject(data);\n const newProject: ChatProject = {\n id: created.id,\n title: created.title,\n description: data.description,\n instructions: data.instructions,\n files: [],\n createdAt: now,\n updatedAt: now,\n };\n setProjects((prev) => [newProject, ...prev]);\n setCurrentProjectId(newProject.id);\n return newProject.id;\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n throw err;\n }\n }\n\n /** @Todo vibecode - localStorage 모드 로컬 생성 */\n const newProject: ChatProject = {\n id: generateId('project'),\n title: data.title,\n description: data.description,\n instructions: data.instructions,\n files: [],\n createdAt: now,\n updatedAt: now,\n };\n setProjects((prev) => [newProject, ...prev]);\n setCurrentProjectId(newProject.id);\n return newProject.id;\n },\n [useExternalStorage, onCreateProject, onError]\n );\n\n /** @Todo vibecode - 프로젝트 선택 (lazy loading) */\n const selectProject = useCallback(\n async (projectId: string) => {\n setCurrentProjectId(projectId);\n\n /** @Todo vibecode - 외부 스토리지 시 상세 정보 로드 */\n if (useExternalStorage && onLoadProject) {\n try {\n const detail = await onLoadProject(projectId);\n setProjects((prev) =>\n prev.map((p) =>\n p.id === projectId\n ? { ...p, ...detail, updatedAt: Date.now() }\n : p\n )\n );\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n }\n },\n [useExternalStorage, onLoadProject, onError]\n );\n\n /** @Todo vibecode - 프로젝트 수정 */\n const updateProject = useCallback(\n async (projectId: string, data: Partial<ChatProject>) => {\n setProjects((prev) =>\n prev.map((p) =>\n p.id === projectId\n ? { ...p, ...data, updatedAt: Date.now() }\n : p\n )\n );\n\n if (useExternalStorage && onUpdateProject) {\n try {\n await onUpdateProject(projectId, data);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n }\n },\n [useExternalStorage, onUpdateProject, onError]\n );\n\n /** @Todo vibecode - 프로젝트 삭제 (기본 프로젝트 삭제 불가) */\n const deleteProject = useCallback(\n async (projectId: string) => {\n if (projectId === DEFAULT_PROJECT_ID) return;\n\n setProjects((prev) => prev.filter((p) => p.id !== projectId));\n\n /** @Todo vibecode - 삭제된 프로젝트가 현재 프로젝트면 기본으로 전환 */\n setCurrentProjectId((prev) =>\n prev === projectId ? DEFAULT_PROJECT_ID : prev\n );\n\n if (useExternalStorage && onDeleteProject) {\n try {\n await onDeleteProject(projectId);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n }\n },\n [useExternalStorage, onDeleteProject, onError]\n );\n\n /** @Todo vibecode - 프로젝트 파일 추가 */\n const addFile = useCallback(\n async (projectId: string, file: File) => {\n if (useExternalStorage && onAddProjectFile) {\n try {\n const fileMeta = await onAddProjectFile(projectId, file);\n setProjects((prev) =>\n prev.map((p) =>\n p.id === projectId\n ? { ...p, files: [...p.files, fileMeta], updatedAt: Date.now() }\n : p\n )\n );\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n return;\n }\n\n /** @Todo vibecode - localStorage 모드 메타데이터만 저장 */\n const fileMeta: ProjectFile = {\n id: generateId('file'),\n name: file.name,\n type: file.type.startsWith('image/') ? 'image'\n : file.type === 'application/pdf' ? 'pdf'\n : file.type.startsWith('text/') ? 'text'\n : 'other',\n url: URL.createObjectURL(file),\n size: file.size,\n mimeType: file.type,\n uploadedAt: Date.now(),\n };\n setProjects((prev) =>\n prev.map((p) =>\n p.id === projectId\n ? { ...p, files: [...p.files, fileMeta], updatedAt: Date.now() }\n : p\n )\n );\n },\n [useExternalStorage, onAddProjectFile, onError]\n );\n\n /** @Todo vibecode - 프로젝트 파일 삭제 */\n const deleteFile = useCallback(\n async (projectId: string, fileId: string) => {\n setProjects((prev) =>\n prev.map((p) =>\n p.id === projectId\n ? { ...p, files: p.files.filter((f) => f.id !== fileId), updatedAt: Date.now() }\n : p\n )\n );\n\n if (useExternalStorage && onDeleteProjectFile) {\n try {\n await onDeleteProjectFile(projectId, fileId);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n }\n },\n [useExternalStorage, onDeleteProjectFile, onError]\n );\n\n return {\n projects,\n currentProjectId,\n currentProject,\n isProjectsLoading,\n createProject,\n selectProject,\n updateProject,\n deleteProject,\n addFile,\n deleteFile,\n };\n};\n","/**\n * @description localStorage 세션을 프로젝트 구조로 마이그레이션\n * @Todo vibecode - enableProjects 활성화 시 기존 세션에 projectId 할당\n */\n\nimport type { ChatProject, ChatSession } from '../types';\n\n/** @Todo vibecode - 기본 프로젝트 ID 상수 */\nexport const DEFAULT_PROJECT_ID = 'default';\n\n/** @Todo vibecode - 기본 프로젝트 제목 */\nexport const DEFAULT_PROJECT_TITLE = '기본 프로젝트';\n\n/**\n * @description 기본 프로젝트 객체 생성\n * @Todo vibecode - 프로젝트 초기화 시 사용\n */\nexport const createDefaultProject = (): ChatProject => ({\n id: DEFAULT_PROJECT_ID,\n title: DEFAULT_PROJECT_TITLE,\n description: '기존 대화를 포함하는 기본 프로젝트',\n instructions: '',\n files: [],\n createdAt: Date.now(),\n updatedAt: Date.now(),\n});\n\n/**\n * @description localStorage 세션 데이터를 프로젝트 구조로 마이그레이션\n * @Todo vibecode - 기존 세션에 projectId: 'default' 할당, 기본 프로젝트 생성\n */\nexport const migrateSessionsToProjects = (storageKey: string): void => {\n if (typeof window === 'undefined') return;\n\n const migratedFlag = `${storageKey}_project_migrated`;\n\n /** @Todo vibecode - 이미 마이그레이션 완료된 경우 스킵 */\n if (localStorage.getItem(migratedFlag)) return;\n\n const sessionsJson = localStorage.getItem(storageKey);\n if (!sessionsJson) {\n localStorage.setItem(migratedFlag, 'true');\n return;\n }\n\n try {\n const sessions: ChatSession[] = JSON.parse(sessionsJson);\n\n /** @Todo vibecode - 기존 세션에 projectId 할당 */\n const migratedSessions = sessions.map((session) => ({\n ...session,\n projectId: session.projectId || DEFAULT_PROJECT_ID,\n }));\n\n /** @Todo vibecode - 기본 프로젝트 생성 (없는 경우) */\n const projectsKey = `${storageKey}_projects`;\n const projectsJson = localStorage.getItem(projectsKey);\n let projects: ChatProject[] = projectsJson ? JSON.parse(projectsJson) : [];\n\n if (!projects.find((p) => p.id === DEFAULT_PROJECT_ID)) {\n projects = [createDefaultProject(), ...projects];\n }\n\n localStorage.setItem(storageKey, JSON.stringify(migratedSessions));\n localStorage.setItem(projectsKey, JSON.stringify(projects));\n localStorage.setItem(migratedFlag, 'true');\n } catch {\n /** @Todo vibecode - 파싱 실패 시 마이그레이션 스킵 */\n localStorage.setItem(migratedFlag, 'true');\n }\n};\n","/**\n * @description Poll 파싱 유틸리티\n * @Todo vibecode - AI 응답에서 <poll> 태그 파싱\n */\n\nimport type { PollBlock, PollQuestion, PollOption } from '../types';\n\n/**\n * @description 고유 ID 생성\n * @Todo vibecode - Poll 요소 식별용\n */\nconst generateId = (): string => {\n return Math.random().toString(36).substring(2, 11);\n};\n\n/**\n * @description 마크다운 인라인 서식 제거 (bold, italic, code, strikethrough)\n * @Todo vibecode - AI에게 전달하는 응답 텍스트에서만 사용 (formatPollResponse)\n * 파싱 단계에서는 마크다운 보존 → PollCard의 renderInlineMarkdown이 렌더 시 처리\n */\nconst stripInlineMarkdown = (text: string): string =>\n text\n .replace(/\\*\\*(.+?)\\*\\*/g, '$1')\n .replace(/__(.+?)__/g, '$1')\n .replace(/\\*(.+?)\\*/g, '$1')\n .replace(/_(.+?)_/g, '$1')\n .replace(/`(.+?)`/g, '$1')\n .replace(/~~(.+?)~~/g, '$1');\n\n/**\n * @description AI 응답에서 <poll> 태그 파싱\n * @Todo vibecode - 지원 형식:\n *\n * 단순 형식:\n * <poll question=\"질문 내용\" multiSelect=\"true\">\n * - 옵션1\n * - 옵션2\n * </poll>\n *\n * 복잡 형식:\n * <poll>\n * <question multiSelect=\"true\">질문 내용</question>\n * <option>옵션1</option>\n * <option>옵션2</option>\n * </poll>\n */\nexport const parsePollFromContent = (\n content: string\n): { pollBlock: PollBlock | null; cleanContent: string } => {\n // <poll> 태그 매칭\n const pollRegex = /<poll([^>]*)>([\\s\\S]*?)<\\/poll>/gi;\n const polls: PollQuestion[] = [];\n let cleanContent = content;\n\n let match;\n while ((match = pollRegex.exec(content)) !== null) {\n const attributes = match[1];\n const innerContent = match[2].trim();\n\n // 속성에서 question 추출 (단순 형식)\n const questionAttrMatch = attributes.match(/question=[\"']([^\"']+)[\"']/i);\n const multiSelectAttrMatch = attributes.match(/multiSelect=[\"']?(true|false)[\"']?/i);\n const allowOtherAttrMatch = attributes.match(/allowOther=[\"']?(true|false)[\"']?/i);\n\n let questionText = questionAttrMatch?.[1] || '';\n let multiSelect = multiSelectAttrMatch?.[1]?.toLowerCase() === 'true';\n let allowOther = allowOtherAttrMatch?.[1]?.toLowerCase() !== 'false'; // 기본 true\n\n // <question> 태그 확인 (복잡 형식)\n const questionTagMatch = innerContent.match(\n /<question([^>]*)>([^<]+)<\\/question>/i\n );\n if (questionTagMatch) {\n const qAttrs = questionTagMatch[1];\n questionText = questionTagMatch[2].trim();\n\n const qMultiSelect = qAttrs.match(/multiSelect=[\"']?(true|false)[\"']?/i);\n const qAllowOther = qAttrs.match(/allowOther=[\"']?(true|false)[\"']?/i);\n\n if (qMultiSelect) {\n multiSelect = qMultiSelect[1].toLowerCase() === 'true';\n }\n if (qAllowOther) {\n allowOther = qAllowOther[1].toLowerCase() !== 'false';\n }\n }\n\n // 옵션 파싱\n const options: PollOption[] = [];\n\n // <option> 태그 형식\n const optionTagRegex = /<option([^>]*)>([^<]+)<\\/option>/gi;\n let optionMatch;\n while ((optionMatch = optionTagRegex.exec(innerContent)) !== null) {\n const optionAttrs = optionMatch[1];\n /** @Todo vibecode - 마크다운 보존: PollCard renderInlineMarkdown이 렌더 시 처리 */\n const optionLabel = optionMatch[2].trim();\n const descMatch = optionAttrs.match(/description=[\"']([^\"']+)[\"']/i);\n\n options.push({\n id: generateId(),\n label: optionLabel,\n description: descMatch?.[1] || undefined,\n });\n }\n\n // - 또는 * 리스트 형식 (옵션 태그가 없을 때)\n // 지원 형식: \"- 옵션\" 또는 \"- 옵션: 설명\"\n if (options.length === 0) {\n const listRegex = /^[-*]\\s+(.+)$/gm;\n let listMatch;\n while ((listMatch = listRegex.exec(innerContent)) !== null) {\n const fullText = listMatch[1].trim();\n /** @Todo vibecode - \"옵션: 설명\" 형식 파싱 (마크다운 보존) */\n const colonIndex = fullText.indexOf(':');\n if (colonIndex > 0) {\n const label = fullText.substring(0, colonIndex).trim();\n const description = fullText.substring(colonIndex + 1).trim();\n options.push({\n id: generateId(),\n label,\n description: description || undefined,\n });\n } else {\n options.push({\n id: generateId(),\n label: fullText,\n });\n }\n }\n }\n\n // 숫자 리스트 형식 (1. 2. 3.)\n if (options.length === 0) {\n const numberedRegex = /^\\d+[.)]\\s+(.+)$/gm;\n let numMatch;\n while ((numMatch = numberedRegex.exec(innerContent)) !== null) {\n options.push({\n id: generateId(),\n label: numMatch[1].trim(),\n });\n }\n }\n\n // 최소 2개 옵션이 있어야 유효한 poll\n if (questionText && options.length >= 2) {\n const pollQuestion = {\n id: generateId(),\n question: questionText,\n options,\n multiSelect,\n allowOther,\n required: false,\n };\n console.log('[pollParser] Parsed poll:', {\n question: pollQuestion.question,\n optionsCount: pollQuestion.options.length,\n options: pollQuestion.options.map(o => o.label),\n });\n polls.push(pollQuestion);\n }\n\n /**\n * @description 원본 콘텐츠에서 poll 태그 제거 + 빈 줄 정리\n * @Todo vibecode - 태그 제거 후 연속 빈 줄이 남아 공백 영역이 생기는 문제 수정\n */\n cleanContent = cleanContent.replace(match[0], '');\n }\n\n if (polls.length === 0) {\n return { pollBlock: null, cleanContent: content };\n }\n\n console.log('[pollParser] Total polls parsed:', polls.length, polls.map(p => p.question));\n\n /** @Todo vibecode - 3줄 이상 연속 개행을 2줄로 축소하여 빈 공백 제거 */\n cleanContent = cleanContent.replace(/\\n{3,}/g, '\\n\\n');\n\n return {\n pollBlock: {\n id: generateId(),\n questions: polls,\n currentIndex: 0,\n },\n cleanContent: cleanContent.trim(),\n };\n};\n\n/**\n * @description Poll 응답을 사용자 메시지 형식으로 변환\n * @Todo vibecode - AI에게 전달할 선택 결과 포맷팅 (명확한 답변 형태)\n */\nexport const formatPollResponse = (\n question: PollQuestion,\n selectedOptions: string[],\n otherText?: string\n): string => {\n /** @Todo vibecode - AI에 전달할 텍스트는 마크다운 제거 (plain text) */\n const selectedLabels = question.options\n .filter((opt) => selectedOptions.includes(opt.id))\n .map((opt) => stripInlineMarkdown(opt.label));\n\n if (otherText) {\n selectedLabels.push(otherText);\n }\n\n if (selectedLabels.length === 0) {\n return `건너뛰기를 선택했습니다. 다른 질문이 있으면 알려주세요.`;\n }\n\n // 더 자연스러운 답변 형태로 변환\n return `${selectedLabels.join(', ')}을(를) 선택했습니다. 이 선택을 바탕으로 진행해주세요.`;\n};\n\nexport default parsePollFromContent;\n","/**\n * @description Tool → Skill 변환 어댑터\n * @Todo vibecode - ChatToolDefinition을 SkillConfig로 변환하여 기존 Skills 인프라 재사용\n */\n\nimport type {\n ChatToolDefinition,\n ToolCallResult,\n SkillConfig,\n SkillExecutionResult,\n} from '../types';\n\n/**\n * @description 도구 정의 배열을 스킬 레코드로 변환\n * @Todo vibecode - 각 tool을 trigger: 'both' SkillConfig로 변환\n *\n * 변환 규칙:\n * - skill name = tool.name (접두사 없음)\n * - trigger: 'both' (AI 자동 호출 + '+' 메뉴에서 수동 선택)\n * - execute: onToolCall 호출 → SkillExecutionResult 반환\n * - metadata.__toolResult__: true (도구 결과 식별용)\n */\nexport const convertToolsToSkills = (\n tools: ChatToolDefinition[],\n onToolCall: (name: string, params: Record<string, unknown>) => Promise<ToolCallResult>,\n): Record<string, SkillConfig> => {\n const skillMap: Record<string, SkillConfig> = {};\n\n for (const tool of tools) {\n skillMap[tool.name] = {\n description: tool.description,\n /** @Todo vibecode - tool.trigger 지원 (기본 'both', 'attachment' 가능) */\n trigger: tool.trigger || 'both',\n label: tool.label || tool.name,\n icon: tool.icon,\n acceptedTypes: tool.acceptedTypes,\n autoConvertBase64: tool.autoConvertBase64,\n parameters: {\n type: 'object',\n properties: Object.fromEntries(\n Object.entries(tool.parameters).map(([key, param]) => [\n key,\n {\n type: param.type,\n description: param.description,\n enum: param.enum,\n },\n ]),\n ),\n required: Object.entries(tool.parameters)\n .filter(([, param]) => param.required)\n .map(([key]) => key),\n },\n execute: async (params: Record<string, unknown>): Promise<SkillExecutionResult> => {\n const result = await onToolCall(tool.name, params);\n return {\n content: result.content,\n /** @Todo vibecode - 도구 결과의 sources를 SkillExecutionResult로 전달 */\n sources: result.sources,\n metadata: {\n __toolResult__: true,\n resultType: result.type,\n toolName: tool.name,\n toolLabel: tool.label,\n toolIcon: tool.icon,\n ...result.metadata,\n },\n };\n },\n };\n }\n\n return skillMap;\n};\n\nexport default convertToolsToSkills;\n","/**\n * @description localStorage fallback cache for external storage mode\n * @Todo vibecode - useExternalStorage 모드에서 per-session 캐시 읽기/쓰기/삭제\n * onLoadSession 빈 응답/에러 시 fallback 복원용\n */\n\nimport type { ChatSession } from '../types';\n\n/**\n * @description 캐시 키 생성\n * @Todo vibecode - 세션별 개별 키로 5MB 제한 분산 + 개별 삭제 가능\n */\nconst buildCacheKey = (storageKey: string, sessionId: string): string =>\n `${storageKey}_cache_${sessionId}`;\n\n/**\n * @description 세션을 localStorage 캐시에 저장\n * @Todo vibecode - best-effort, 실패 시 무시 (quota exceeded 등)\n */\nexport const writeSessionCache = (\n storageKey: string,\n session: ChatSession\n): void => {\n if (typeof window === 'undefined') return;\n try {\n const key = buildCacheKey(storageKey, session.id);\n localStorage.setItem(key, JSON.stringify(session));\n } catch (error) {\n console.warn('[sessionCache] Failed to write cache:', error);\n }\n};\n\n/**\n * @description localStorage 캐시에서 세션 읽기\n * @Todo vibecode - 없거나 파싱 에러 시 null 반환\n */\nexport const readSessionCache = (\n storageKey: string,\n sessionId: string\n): ChatSession | null => {\n if (typeof window === 'undefined') return null;\n try {\n const key = buildCacheKey(storageKey, sessionId);\n const data = localStorage.getItem(key);\n if (!data) return null;\n return JSON.parse(data) as ChatSession;\n } catch {\n return null;\n }\n};\n\n/**\n * @description localStorage 캐시에서 세션 삭제\n * @Todo vibecode - 세션 삭제 시 캐시도 정리\n */\nexport const removeSessionCache = (\n storageKey: string,\n sessionId: string\n): void => {\n if (typeof window === 'undefined') return;\n try {\n const key = buildCacheKey(storageKey, sessionId);\n localStorage.removeItem(key);\n } catch {\n // Ignore errors on removal\n }\n};\n","/**\n * @description 채팅 사이드바 컴포넌트 - Modern Canvas 디자인\n * @Todo vibecode - v0.11.0 새 디자인 시스템 적용\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { IconSvg } from './Icon';\nimport { ProjectSelector } from './ProjectSelector';\nimport type { SidebarProps, ChatSession } from '../types';\n\nconst formatDate = (timestamp: number): string => {\n const date = new Date(timestamp);\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n const days = Math.floor(diff / (1000 * 60 * 60 * 24));\n\n if (days === 0) return '오늘';\n if (days === 1) return '어제';\n if (days < 7) return `${days}일 전`;\n return date.toLocaleDateString('ko-KR');\n};\n\nexport const ChatSidebar: React.FC<SidebarProps> = ({\n sessions,\n currentSessionId,\n onSelectSession,\n onNewSession,\n onDeleteSession,\n onRenameSession,\n isOpen,\n onToggle,\n width: widthProp,\n theme,\n projects,\n currentProjectId,\n onSelectProject,\n onNewProject,\n onProjectSettings,\n renderAfterHeader,\n renderFooter,\n isLoading = false,\n}) => {\n /** @Todo vibecode - 사이드바 너비 커스터마이징 (기본: 288px) */\n const sidebarWidth = typeof widthProp === 'number' ? `${widthProp}px` : (widthProp || '288px');\n\n const [editingId, setEditingId] = useState<string | null>(null);\n const [editingTitle, setEditingTitle] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (editingId && inputRef.current) {\n inputRef.current.focus();\n inputRef.current.select();\n }\n }, [editingId]);\n\n const handleStartEdit = (session: ChatSession, e: React.MouseEvent) => {\n e.stopPropagation();\n setEditingId(session.id);\n setEditingTitle(session.title);\n };\n\n const handleSaveEdit = () => {\n if (editingId && editingTitle.trim() && onRenameSession) {\n onRenameSession(editingId, editingTitle.trim());\n }\n setEditingId(null);\n setEditingTitle('');\n };\n\n const handleCancelEdit = () => {\n setEditingId(null);\n setEditingTitle('');\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleSaveEdit();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n handleCancelEdit();\n }\n };\n\n /** @Todo vibecode - theme prop으로 chatllm-root 밖에서도 CSS 변수 적용 */\n const themeClass = theme === 'dark' ? 'chatllm-dark' : '';\n\n return (\n <aside\n className={`chatllm-sidebar chatllm-sidebar-transition ${theme ? `chatllm-root ${themeClass}` : ''}`}\n style={{\n width: isOpen ? sidebarWidth : '0',\n height: '100%',\n flexShrink: 0,\n backgroundColor: 'var(--chatllm-sidebar-bg)',\n borderRight: isOpen ? '1px solid var(--chatllm-border)' : 'none',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n zIndex: 20,\n }}\n >\n <div\n style={{\n width: sidebarWidth,\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n padding: '24px',\n }}\n >\n {/* Header */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: '40px',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>\n <div\n style={{\n width: '28px',\n height: '28px',\n borderRadius: '6px',\n backgroundColor: 'var(--chatllm-primary)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 1px 2px rgba(0,0,0,0.05)',\n }}\n >\n <IconSvg name=\"chat-1-line\" size={16} color=\"#ffffff\" />\n </div>\n <span\n style={{\n fontSize: '14px',\n fontWeight: 700,\n letterSpacing: '-0.01em',\n color: 'var(--chatllm-text)',\n }}\n >\n AI 채팅\n </span>\n </div>\n </div>\n\n {/* Project Selector */}\n {projects && projects.length > 0 && onSelectProject && onNewProject && onProjectSettings && (\n <ProjectSelector\n projects={projects}\n currentProjectId={currentProjectId || null}\n onSelectProject={onSelectProject}\n onNewProject={onNewProject}\n onProjectSettings={onProjectSettings}\n />\n )}\n\n {/* New Chat Button */}\n <button\n onClick={onNewSession}\n className=\"chatllm-btn-primary\"\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '12px',\n padding: '12px 16px',\n marginBottom: '32px',\n borderRadius: '12px',\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n <IconSvg name=\"add-line\" size={20} color=\"#ffffff\" />\n <span>새 대화</span>\n </button>\n\n {/* Custom slot: after header */}\n {renderAfterHeader && renderAfterHeader()}\n\n {/* Sessions List */}\n <div\n className=\"chatllm-scrollbar\"\n style={{\n flex: 1,\n overflow: 'auto',\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n {isLoading ? (\n /* Skeleton Loading State */\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', padding: '0 4px' }}>\n {/** @Todo vibecode - 세션 목록 로딩 스켈레톤 (4개 바) */}\n {[1, 2, 3, 4].map((i) => (\n <div\n key={i}\n className=\"chatllm-skeleton-pulse\"\n style={{\n height: '48px',\n borderRadius: '8px',\n backgroundColor: 'var(--chatllm-bg-tertiary)',\n opacity: 1 - (i - 1) * 0.15,\n }}\n />\n ))}\n </div>\n ) : sessions.length === 0 ? (\n /* Empty State */\n <div\n style={{\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n textAlign: 'center',\n padding: '16px',\n }}\n >\n <div\n style={{\n width: '64px',\n height: '64px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-bg-tertiary)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginBottom: '16px',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n <IconSvg name=\"history-line\" size={32} />\n </div>\n <p\n style={{\n fontSize: '14px',\n fontWeight: 600,\n color: 'var(--chatllm-text-secondary)',\n marginBottom: '4px',\n }}\n >\n No history yet\n </p>\n <p\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n Your recent conversations will appear here.\n </p>\n </div>\n ) : (\n <>\n <div\n style={{\n fontSize: '11px',\n fontWeight: 700,\n color: 'var(--chatllm-text-muted)',\n textTransform: 'uppercase',\n letterSpacing: '0.1em',\n marginBottom: '12px',\n padding: '0 8px',\n }}\n >\n Recent activity\n </div>\n <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>\n {sessions.map((session) => {\n const isSelected = session.id === currentSessionId;\n return (\n <div\n key={session.id}\n onClick={() => onSelectSession(session.id)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '10px 12px',\n borderRadius: '8px',\n backgroundColor: isSelected\n ? 'var(--chatllm-bg-active)'\n : 'transparent',\n border: isSelected\n ? '1px solid var(--chatllm-border-light)'\n : '1px solid transparent',\n cursor: 'pointer',\n transition: 'all 0.2s',\n }}\n onMouseOver={(e) => {\n if (!isSelected) {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }\n }}\n onMouseOut={(e) => {\n if (!isSelected) {\n e.currentTarget.style.backgroundColor = 'transparent';\n }\n }}\n >\n <IconSvg\n name=\"chat-1-line\"\n size={18}\n color=\"var(--chatllm-text-muted)\"\n />\n <div style={{ flex: 1, minWidth: 0 }}>\n {editingId === session.id ? (\n <input\n ref={inputRef}\n type=\"text\"\n value={editingTitle}\n onChange={(e) => setEditingTitle(e.target.value)}\n onKeyDown={handleKeyDown}\n onBlur={handleSaveEdit}\n onClick={(e) => e.stopPropagation()}\n aria-label=\"세션 제목 편집\"\n style={{\n width: '100%',\n padding: '2px 6px',\n fontSize: '14px',\n fontWeight: 500,\n color: 'var(--chatllm-text)',\n backgroundColor: 'var(--chatllm-content-bg)',\n border: '1px solid var(--chatllm-primary)',\n borderRadius: '4px',\n outline: 'none',\n }}\n />\n ) : (\n <p\n style={{\n fontSize: '14px',\n fontWeight: 500,\n color: isSelected\n ? 'var(--chatllm-text)'\n : 'var(--chatllm-text-secondary)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n margin: 0,\n }}\n >\n {session.title}\n </p>\n )}\n </div>\n {/* Action Buttons - show on hover or when selected */}\n <div\n style={{\n display: 'flex',\n gap: '2px',\n opacity: isSelected ? 1 : 0,\n pointerEvents: isSelected ? 'auto' : 'none',\n transition: 'opacity 0.2s',\n }}\n className=\"session-actions\"\n >\n {onRenameSession && editingId !== session.id && (\n <button\n onClick={(e) => handleStartEdit(session, e)}\n aria-label=\"제목 편집\"\n style={{\n padding: '4px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n <IconSvg name=\"pencil-line\" size={14} />\n </button>\n )}\n <button\n onClick={(e) => {\n e.stopPropagation();\n onDeleteSession(session.id);\n }}\n aria-label=\"세션 삭제\"\n style={{\n padding: '4px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n <IconSvg name=\"delete-bin-line\" size={14} />\n </button>\n </div>\n </div>\n );\n })}\n </div>\n </>\n )}\n </div>\n\n {/* Custom slot: footer */}\n {renderFooter && renderFooter()}\n </div>\n </aside>\n );\n};\n\nexport default ChatSidebar;\n","/**\n * @description Remix Icons wrapper component\n * @see https://remixicon.com/\n * Using Remix Icons 4.6.0 via CDN or npm package\n */\n\nimport React from 'react';\n\nexport type IconName =\n // Navigation & UI\n | 'menu-line'\n | 'close-line'\n | 'arrow-left-line'\n | 'arrow-right-line'\n | 'arrow-down-s-line'\n | 'arrow-up-s-line'\n | 'more-line'\n | 'more-2-line'\n | 'settings-3-line'\n | 'settings-4-line'\n // Chat & Communication\n | 'chat-1-line'\n | 'chat-3-line'\n | 'chat-new-line'\n | 'message-2-line'\n | 'send-plane-line'\n | 'send-plane-fill'\n | 'question-answer-line'\n // Actions\n | 'add-line'\n | 'add-circle-line'\n | 'delete-bin-line'\n | 'delete-bin-6-line'\n | 'edit-line'\n | 'edit-2-line'\n | 'pencil-line'\n | 'check-line'\n | 'close-circle-line'\n | 'refresh-line'\n | 'loop-left-line'\n | 'stop-line'\n | 'stop-circle-line'\n | 'play-line'\n | 'pause-line'\n // Content\n | 'file-copy-line'\n | 'clipboard-line'\n | 'quote-text'\n | 'double-quotes-l'\n | 'double-quotes-r'\n // Search & Find\n | 'search-line'\n | 'search-2-line'\n | 'search-eye-line'\n | 'global-line'\n // Media\n | 'image-line'\n | 'image-add-line'\n | 'gallery-line'\n | 'video-line'\n | 'mic-line'\n // Code & Development\n | 'code-line'\n | 'code-s-slash-line'\n | 'terminal-box-line'\n | 'bug-line'\n | 'git-branch-line'\n // Document\n | 'file-text-line'\n | 'file-list-line'\n | 'article-line'\n | 'draft-line'\n | 'book-2-line'\n // AI & Magic\n | 'magic-line'\n | 'sparkling-line'\n | 'sparkling-2-line'\n | 'robot-line'\n | 'brain-line'\n // User\n | 'user-line'\n | 'user-3-line'\n | 'user-settings-line'\n | 'account-circle-line'\n // System\n | 'sun-line'\n | 'moon-line'\n | 'computer-line'\n | 'information-line'\n | 'error-warning-line'\n | 'checkbox-circle-line'\n | 'loader-4-line'\n // Misc\n | 'translate-2'\n | 'time-line'\n | 'history-line'\n | 'star-line'\n | 'star-fill'\n | 'heart-line'\n | 'thumb-up-line'\n | 'thumb-down-line'\n | 'attachment-line'\n | 'link'\n | 'links-line'\n | 'external-link-line'\n | 'download-line'\n | 'upload-line'\n | 'folder-line'\n | 'home-line'\n | 'dashboard-line'\n | 'list-check'\n | 'list-unordered'\n | 'key-line'\n | 'lock-line'\n | 'eye-line'\n | 'eye-off-line';\n\nexport interface IconProps {\n /** Icon name from Remix Icons */\n name: IconName;\n /** Size in pixels or CSS value */\n size?: number | string;\n /** CSS color value */\n color?: string;\n /** Additional CSS classes */\n className?: string;\n /** Additional inline styles */\n style?: React.CSSProperties;\n /** Click handler */\n onClick?: () => void;\n /** Accessibility label */\n 'aria-label'?: string;\n}\n\n/**\n * Remix Icons component\n * Uses CSS class-based icons (requires remixicon CSS)\n */\nexport const Icon: React.FC<IconProps> = ({\n name,\n size = 20,\n color,\n className = '',\n onClick,\n 'aria-label': ariaLabel,\n}) => {\n const sizeValue = typeof size === 'number' ? `${size}px` : size;\n\n return (\n <i\n className={`ri-${name} ${className}`}\n style={{\n fontSize: sizeValue,\n color,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n lineHeight: 1,\n }}\n onClick={onClick}\n aria-label={ariaLabel}\n role={onClick ? 'button' : undefined}\n tabIndex={onClick ? 0 : undefined}\n />\n );\n};\n\n/**\n * SVG-based Icon component (no external CSS required)\n * Icons are rendered inline as SVG\n */\nexport const IconSvg: React.FC<IconProps> = ({\n name,\n size = 20,\n color = 'currentColor',\n className = '',\n style,\n onClick,\n 'aria-label': ariaLabel,\n}) => {\n const sizeValue = typeof size === 'number' ? size : parseInt(size, 10) || 20;\n\n // Common SVG icons inline\n const icons: Partial<Record<IconName, React.ReactNode>> = {\n 'menu-line': (\n <path d=\"M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z\" />\n ),\n 'close-line': (\n <path d=\"M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z\" />\n ),\n 'add-line': (\n <path d=\"M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z\" />\n ),\n 'chat-1-line': (\n <path d=\"M10 3h4a8 8 0 1 1 0 16v3.5c-5-2-12-5-12-11.5a8 8 0 0 1 8-8zm2 14h2a6 6 0 0 0 0-12h-4a6 6 0 0 0-6 6c0 3.61 2.462 5.966 8 8.48V17z\" />\n ),\n 'send-plane-fill': (\n <path d=\"M1.946 9.315c-.522-.174-.527-.455.01-.634l19.087-6.362c.529-.176.832.12.684.638l-5.454 19.086c-.15.529-.455.547-.679.045L12 14l6-8-8 6-8.054-2.685z\" />\n ),\n 'send-plane-line': (\n <path d=\"M1.923 9.37c-.51-.205-.504-.51.034-.689l19.086-6.362c.529-.176.832.12.684.638l-5.454 19.086c-.15.529-.475.553-.717.07L12 14 3 10.5l8-4.25-9.077 3.12zM5.5 10.5l5.25 2.75 2.25 5.5 4-14-11.5 5.75z\" />\n ),\n 'search-line': (\n <path d=\"M18.031 16.617l4.283 4.282-1.415 1.415-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9 9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617zm-2.006-.742A6.977 6.977 0 0 0 18 11c0-3.868-3.133-7-7-7-3.868 0-7 3.132-7 7 0 3.867 3.132 7 7 7a6.977 6.977 0 0 0 4.875-1.975l.15-.15z\" />\n ),\n 'search-eye-line': (\n <path d=\"M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm0 2a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-12C5.373 4 0 12 0 12s5.373 8 12 8 12-8 12-8-5.373-8-12-8zm0 14c-4.418 0-8.268-3.582-9.538-6C3.732 9.582 7.582 6 12 6s8.268 3.582 9.538 6c-1.27 2.418-5.12 6-9.538 6z\" />\n ),\n 'image-line': (\n <path d=\"M4.828 21l-.02.02-.021-.02H2.992A.993.993 0 0 1 2 20.007V3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H4.828zM20 15V5H4v14L14 9l6 6zm0 2.828l-6-6L6.828 19H20v-1.172zM8 11a2 2 0 1 1 0-4 2 2 0 0 1 0 4z\" />\n ),\n 'code-s-slash-line': (\n <path d=\"M24 12l-5.657 5.657-1.414-1.414L21.172 12l-4.243-4.243 1.414-1.414L24 12zM2.828 12l4.243 4.243-1.414 1.414L0 12l5.657-5.657L7.07 7.757 2.828 12zm6.96 9H7.66l6.552-18h2.128L9.788 21z\" />\n ),\n 'file-text-line': (\n <path d=\"M21 8v12.993A1 1 0 0 1 20.007 22H3.993A.993.993 0 0 1 3 21.008V2.992C3 2.455 3.449 2 4.002 2h10.995L21 8zm-2 1h-5V4H5v16h14V9zM8 7h3v2H8V7zm0 4h8v2H8v-2zm0 4h8v2H8v-2z\" />\n ),\n 'delete-bin-line': (\n <path d=\"M17 6h5v2h-2v13a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V8H2V6h5V3a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v3zm1 2H6v12h12V8zm-9 3h2v6H9v-6zm4 0h2v6h-2v-6zM9 4v2h6V4H9z\" />\n ),\n 'edit-line': (\n <path d=\"M6.414 16L16.556 5.858l-1.414-1.414L5 14.586V16h1.414zm.829 2H3v-4.243L14.435 2.322a1 1 0 0 1 1.414 0l2.829 2.829a1 1 0 0 1 0 1.414L7.243 18zM3 20h18v2H3v-2z\" />\n ),\n 'check-line': (\n <path d=\"M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414z\" />\n ),\n 'file-copy-line': (\n <path d=\"M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1.001 1.001 0 0 1 3 20l.003-14c0-.552.45-1 1.007-1H7zM5.003 8L5 20h10V8H5.003zM9 6h8v10h2V4H9v2z\" />\n ),\n 'refresh-line': (\n <path d=\"M5.463 4.433A9.961 9.961 0 0 1 12 2c5.523 0 10 4.477 10 10 0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 0 0-2.46-5.772A7.96 7.96 0 0 0 12 4a7.96 7.96 0 0 0-5.54 2.228l1.414 1.414A5.972 5.972 0 0 1 12 6a5.99 5.99 0 0 1 3.88 1.42l-1.42 1.42A4 4 0 0 0 8.54 12H6V7l.002-.002 1.461 1.435zM18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12c0-2.136.67-4.116 1.81-5.74L7 12H4a8 8 0 0 0 2.46 5.772A7.96 7.96 0 0 0 12 20a7.96 7.96 0 0 0 5.54-2.228l-1.414-1.414A5.972 5.972 0 0 1 12 18a5.99 5.99 0 0 1-3.88-1.42l1.42-1.42A4 4 0 0 0 15.46 12H18v5l-.002.002-1.461-1.435z\" />\n ),\n 'stop-circle-line': (\n <path d=\"M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM9 9h6v6H9V9z\" />\n ),\n 'settings-3-line': (\n <path d=\"M3.34 17a10.018 10.018 0 0 1-.978-2.326 3 3 0 0 0 .002-5.347A9.99 9.99 0 0 1 4.865 4.99a3 3 0 0 0 4.631-2.674 9.99 9.99 0 0 1 5.007.002 3 3 0 0 0 4.632 2.672 10.018 10.018 0 0 1 2.525 4.337 3 3 0 0 0-.002 5.347 9.99 9.99 0 0 1-2.525 4.337 3 3 0 0 0-4.631 2.674 9.99 9.99 0 0 1-5.007-.002 3 3 0 0 0-4.632-2.672A10.018 10.018 0 0 1 3.34 17zm5.66.196a4.993 4.993 0 0 1 2.25 2.77c.499.047 1 .048 1.499.001A4.993 4.993 0 0 1 15 17.197a4.993 4.993 0 0 1 3.525-.565c.29-.408.54-.843.748-1.298A4.993 4.993 0 0 1 18 12c0-1.26.47-2.437 1.273-3.334a8.126 8.126 0 0 0-.75-1.298A4.993 4.993 0 0 1 15 6.804a4.993 4.993 0 0 1-2.25-2.77c-.499-.047-1-.048-1.499-.001A4.993 4.993 0 0 1 9 6.804a4.993 4.993 0 0 1-3.525.565 7.99 7.99 0 0 0-.748 1.298A4.993 4.993 0 0 1 6 12c0 1.26-.47 2.437-1.273 3.334a8.126 8.126 0 0 0 .75 1.298A4.993 4.993 0 0 1 9 17.196zM12 15a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z\" />\n ),\n 'loader-4-line': (\n <path d=\"M12 3a9 9 0 0 1 9 9h-2a7 7 0 0 0-7-7V3z\" />\n ),\n 'sparkling-line': (\n <path d=\"M14 4.438A2 2 0 0 1 15.438 3l4.62.764a2 2 0 0 1 1.112.529l.152.152a2 2 0 0 1 .529 1.112L22.5 10a2 2 0 0 1-.436 1.559l-.095.11L21 10.5l-3.3-3.3L14 4.438zm-3 1.124l5.5 5.5-9.086 9.086a2 2 0 0 1-2.828 0l-.172-.172a2 2 0 0 1 0-2.828L13.5 8.062 11 5.562zm-8.657 14.95a1 1 0 0 0 1.414 0l9.9-9.9-1.414-1.413-9.9 9.9a1 1 0 0 0 0 1.414z\" />\n ),\n 'arrow-down-s-line': (\n <path d=\"M12 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z\" />\n ),\n 'arrow-up-s-line': (\n <path d=\"M12 10.828l-4.95 4.95-1.414-1.414L12 8l6.364 6.364-1.414 1.414z\" />\n ),\n 'double-quotes-l': (\n <path d=\"M4.583 17.321C3.553 16.227 3 15 3 13.011c0-3.5 2.457-6.637 6.03-8.188l.893 1.378c-3.335 1.804-3.987 4.145-4.247 5.621.537-.278 1.24-.375 1.929-.311 1.804.167 3.226 1.648 3.226 3.489a3.5 3.5 0 0 1-3.5 3.5c-1.073 0-2.099-.49-2.748-1.179zm10 0C13.553 16.227 13 15 13 13.011c0-3.5 2.457-6.637 6.03-8.188l.893 1.378c-3.335 1.804-3.987 4.145-4.247 5.621.537-.278 1.24-.375 1.929-.311 1.804.167 3.226 1.648 3.226 3.489a3.5 3.5 0 0 1-3.5 3.5c-1.073 0-2.099-.49-2.748-1.179z\" />\n ),\n 'robot-line': (\n <path d=\"M13 4.055c4.5.497 8 4.312 8 8.945v9H3v-9c0-4.633 3.5-8.448 8-8.945V1h2v3.055zM5 20h14v-7a7 7 0 1 0-14 0v7zm2-7a5 5 0 0 1 10 0v4H7v-4zm2 0v2h2v-2H9zm4 0v2h2v-2h-2z\" />\n ),\n 'user-3-line': (\n <path d=\"M20 22h-2v-2a3 3 0 0 0-3-3H9a3 3 0 0 0-3 3v2H4v-2a5 5 0 0 1 5-5h6a5 5 0 0 1 5 5v2zm-8-9a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8z\" />\n ),\n 'sun-line': (\n <path d=\"M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z\" />\n ),\n 'moon-line': (\n <path d=\"M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z\" />\n ),\n 'key-line': (\n <path d=\"M12.917 13A6.002 6.002 0 0 1 1 12a6 6 0 0 1 11.917-1H23v6h-2v-4h-2v4h-2v-4h-4.083zM7 10a2 2 0 1 0 0 4 2 2 0 0 0 0-4z\" />\n ),\n 'links-line': (\n <path d=\"M17.657 14.828l-1.414-1.414L17.657 12A4 4 0 1 0 12 6.343l-1.414 1.414-1.414-1.414 1.414-1.414a6 6 0 0 1 8.485 8.485l-1.414 1.414zm-2.829 2.829l-1.414 1.414a6 6 0 1 1-8.485-8.485l1.414-1.414 1.414 1.414L6.343 12A4 4 0 1 0 12 17.657l1.414-1.414 1.414 1.414zm0-9.9l1.415 1.415-7.071 7.07-1.415-1.414 7.071-7.07z\" />\n ),\n 'external-link-line': (\n <path d=\"M10 6v2H5v11h11v-5h2v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h6zm11-3v8h-2V6.413l-7.793 7.794-1.414-1.414L17.585 5H13V3h8z\" />\n ),\n 'arrow-left-line': (\n <path d=\"M7.828 11H20v2H7.828l5.364 5.364-1.414 1.414L4 12l7.778-7.778 1.414 1.414z\" />\n ),\n 'arrow-right-line': (\n <path d=\"M16.172 11l-5.364-5.364 1.414-1.414L20 12l-7.778 7.778-1.414-1.414L16.172 13H4v-2z\" />\n ),\n 'magic-line': (\n <path d=\"M15.224 15.508l-2.213 4.65a.6.6 0 0 1-.542.342.6.6 0 0 1-.543-.342l-2.213-4.65-4.65-2.213a.6.6 0 0 1 0-1.086l4.65-2.213 2.213-4.65a.6.6 0 0 1 1.086 0l2.213 4.65 4.65 2.213a.6.6 0 0 1 0 1.086l-4.651 2.213zM6.5 19l1.18-2.478L10.158 17.5l-2.478-1.18L6.5 14l-1.18 2.32L2.842 17.5l2.478 1.022L6.5 19zM6.5 8l1.18-2.478L10.158 6.5l-2.478-1.18L6.5 3l-1.18 2.32L2.842 6.5l2.478 1.022L6.5 8z\" />\n ),\n 'attachment-line': (\n <path d=\"M14.828 7.757l-5.656 5.657a1 1 0 1 0 1.414 1.414l5.657-5.656A3 3 0 1 0 12 4.929l-5.657 5.657a5 5 0 1 0 7.071 7.07L19.071 12l1.414 1.414-5.657 5.657a7 7 0 1 1-9.9-9.9l5.658-5.656a5 5 0 0 1 7.07 7.07L12 16.244A3 3 0 1 1 7.757 12l5.657-5.657 1.414 1.414z\" />\n ),\n 'history-line': (\n <path d=\"M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12h2a8 8 0 1 0 .677-3.213l2.03.669A6 6 0 1 1 6 12H4a8 8 0 0 1 8-8zm1 5v4.585l3.243 3.243-1.414 1.414L11 12.415V7h2z\" />\n ),\n 'pencil-line': (\n <path d=\"M15.728 9.686l-1.414-1.414L5 17.586V19h1.414l9.314-9.314zm1.414-1.414l1.414-1.414-1.414-1.414-1.414 1.414 1.414 1.414zM7.242 21H3v-4.243L16.435 3.322a1 1 0 0 1 1.414 0l2.829 2.829a1 1 0 0 1 0 1.414L7.243 21z\" />\n ),\n };\n\n const iconPath = icons[name];\n\n return (\n <svg\n className={className}\n width={sizeValue}\n height={sizeValue}\n viewBox=\"0 0 24 24\"\n fill={color}\n onClick={onClick}\n aria-label={ariaLabel}\n role={onClick ? 'button' : 'img'}\n tabIndex={onClick ? 0 : undefined}\n style={{ display: 'inline-block', verticalAlign: 'middle', ...style }}\n >\n {iconPath || <path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z\" />}\n </svg>\n );\n};\n\nexport default Icon;\n","/**\n * @description 프로젝트 선택 드롭다운 - 사이드바 상단에 배치\n * @Todo vibecode - 프로젝트 전환, 생성, 설정 접근\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { IconSvg } from './Icon';\nimport type { ChatProject } from '../types';\n\nexport interface ProjectSelectorProps {\n projects: ChatProject[];\n currentProjectId: string | null;\n onSelectProject: (id: string) => void;\n onNewProject: () => void;\n onProjectSettings: (id: string) => void;\n}\n\nexport const ProjectSelector: React.FC<ProjectSelectorProps> = ({\n projects,\n currentProjectId,\n onSelectProject,\n onNewProject,\n onProjectSettings,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const currentProject = projects.find((p) => p.id === currentProjectId);\n\n /** @Todo vibecode - 외부 클릭 시 드롭다운 닫기 */\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) {\n setIsOpen(false);\n }\n };\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [isOpen]);\n\n return (\n <div ref={dropdownRef} style={{ position: 'relative', marginBottom: '12px' }}>\n {/* 드롭다운 트리거 버튼 */}\n <button\n onClick={() => setIsOpen(!isOpen)}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 12px',\n borderRadius: '8px',\n backgroundColor: 'var(--chatllm-bg-tertiary, #f5f5f5)',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n cursor: 'pointer',\n transition: 'background-color 0.15s',\n fontFamily: 'inherit',\n }}\n aria-expanded={isOpen}\n aria-haspopup='listbox'\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', overflow: 'hidden' }}>\n <div\n style={{\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: currentProject?.color || 'var(--chatllm-primary, #2563eb)',\n flexShrink: 0,\n }}\n />\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-text, #1a1a1a)',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {currentProject?.title || '기본 프로젝트'}\n </span>\n </div>\n <IconSvg\n name='arrow-down-s-line'\n size={16}\n color='var(--chatllm-text-muted, #999)'\n />\n </button>\n\n {/* 드롭다운 메뉴 */}\n {isOpen && (\n <div\n role='listbox'\n style={{\n position: 'absolute',\n top: 'calc(100% + 4px)',\n left: 0,\n right: 0,\n backgroundColor: 'var(--chatllm-content-bg, #fff)',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n borderRadius: '8px',\n boxShadow: '0 4px 12px rgba(0,0,0,0.1)',\n zIndex: 50,\n maxHeight: '280px',\n overflowY: 'auto',\n }}\n >\n {/* 프로젝트 목록 */}\n {projects.map((project) => (\n <div\n key={project.id}\n role='option'\n aria-selected={project.id === currentProjectId}\n onClick={() => {\n onSelectProject(project.id);\n setIsOpen(false);\n }}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 12px',\n cursor: 'pointer',\n backgroundColor: project.id === currentProjectId\n ? 'var(--chatllm-bg-hover, #f0f0f0)'\n : 'transparent',\n transition: 'background-color 0.1s',\n }}\n onMouseEnter={(e) => {\n if (project.id !== currentProjectId) {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--chatllm-bg-hover, #f0f0f0)';\n }\n }}\n onMouseLeave={(e) => {\n if (project.id !== currentProjectId) {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent';\n }\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', overflow: 'hidden' }}>\n <div\n style={{\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: project.color || 'var(--chatllm-primary, #2563eb)',\n flexShrink: 0,\n }}\n />\n <span\n style={{\n fontSize: '13px',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n >\n {project.title}\n </span>\n </div>\n {/* 설정 아이콘 */}\n <button\n onClick={(e) => {\n e.stopPropagation();\n onProjectSettings(project.id);\n setIsOpen(false);\n }}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '2px',\n opacity: 0.5,\n transition: 'opacity 0.1s',\n display: 'flex',\n alignItems: 'center',\n }}\n onMouseEnter={(e) => { (e.currentTarget as HTMLElement).style.opacity = '1'; }}\n onMouseLeave={(e) => { (e.currentTarget as HTMLElement).style.opacity = '0.5'; }}\n aria-label={`${project.title} 프로젝트 설정`}\n >\n <IconSvg name='settings-3-line' size={14} color='var(--chatllm-text-muted, #999)' />\n </button>\n </div>\n ))}\n\n {/* 구분선 */}\n <div style={{ height: '1px', backgroundColor: 'var(--chatllm-border, #e0e0e0)', margin: '4px 0' }} />\n\n {/* 새 프로젝트 버튼 */}\n <div\n onClick={() => {\n onNewProject();\n setIsOpen(false);\n }}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '10px 12px',\n cursor: 'pointer',\n transition: 'background-color 0.1s',\n }}\n onMouseEnter={(e) => { (e.currentTarget as HTMLElement).style.backgroundColor = 'var(--chatllm-bg-hover, #f0f0f0)'; }}\n onMouseLeave={(e) => { (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent'; }}\n >\n <IconSvg name='add-line' size={16} color='var(--chatllm-primary, #2563eb)' />\n <span style={{ fontSize: '13px', fontWeight: 500, color: 'var(--chatllm-primary, #2563eb)' }}>\n 새 프로젝트\n </span>\n </div>\n </div>\n )}\n </div>\n );\n};\n","/**\n * @description 채팅 헤더 컴포넌트\n * 모델 선택, 설정 버튼\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\nimport type { HeaderProps } from '../types';\n\nexport const ChatHeader: React.FC<HeaderProps> = ({\n title,\n model,\n models,\n onModelChange,\n onSettingsOpen,\n onSidebarToggle,\n sidebarOpen,\n showModelSelector = true,\n showSettings = true,\n}) => {\n const [modelDropdownOpen, setModelDropdownOpen] = useState(false);\n\n const currentModel = models.find((m) => m.id === model);\n\n return (\n <header\n className=\"chatllm-header\"\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 24px',\n borderBottom: '1px solid var(--chatllm-border, #e5e7eb)',\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n }}\n >\n {/* Left: Sidebar Toggle & Title */}\n <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>\n <button\n onClick={onSidebarToggle}\n style={{\n width: '36px',\n height: '36px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover, #f3f4f6)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <IconSvg name=\"menu-line\" size={20} color=\"var(--chatllm-text, #1f2937)\" />\n </button>\n <h1\n style={{\n fontSize: '16px',\n fontWeight: 500,\n color: 'var(--chatllm-text, #1f2937)',\n margin: 0,\n }}\n >\n {title}\n </h1>\n </div>\n\n {/* Right: Model Selector & Settings */}\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n {/* Model Selector */}\n {showModelSelector && (\n <div style={{ position: 'relative' }}>\n <button\n onClick={() => setModelDropdownOpen(!modelDropdownOpen)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n cursor: 'pointer',\n transition: 'all 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.borderColor = 'var(--chatllm-primary, #3b82f6)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.borderColor = 'var(--chatllm-border, #e5e7eb)';\n }}\n >\n <IconSvg name=\"robot-line\" size={16} color=\"var(--chatllm-primary, #3b82f6)\" />\n <span style={{ fontSize: '14px', fontWeight: 500, color: 'var(--chatllm-text, #1f2937)' }}>\n {currentModel?.name || model}\n </span>\n <IconSvg\n name={modelDropdownOpen ? 'arrow-up-s-line' : 'arrow-down-s-line'}\n size={16}\n color=\"var(--chatllm-text-muted, #9ca3af)\"\n />\n </button>\n\n {/* Model Dropdown */}\n {modelDropdownOpen && (\n <>\n {/* Backdrop */}\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 99,\n }}\n onClick={() => setModelDropdownOpen(false)}\n />\n <div\n style={{\n position: 'absolute',\n top: '100%',\n right: 0,\n marginTop: '8px',\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n borderRadius: '12px',\n boxShadow: '0 4px 24px rgba(0, 0, 0, 0.12)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n padding: '8px',\n minWidth: '220px',\n zIndex: 100,\n }}\n >\n {/* Group by provider */}\n {Array.from(new Set(models.map((m) => m.provider))).map((provider) => (\n <div key={provider}>\n <div\n style={{\n padding: '8px 12px',\n fontSize: '11px',\n fontWeight: 600,\n color: 'var(--chatllm-text-muted, #9ca3af)',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n }}\n >\n {provider}\n </div>\n {models\n .filter((m) => m.provider === provider)\n .map((m) => (\n <button\n key={m.id}\n onClick={() => {\n onModelChange(m.id);\n setModelDropdownOpen(false);\n }}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 12px',\n backgroundColor: m.id === model ? 'var(--chatllm-bg-active, #eff6ff)' : 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n if (m.id !== model) {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover, #f9fafb)';\n }\n }}\n onMouseOut={(e) => {\n if (m.id !== model) {\n e.currentTarget.style.backgroundColor = 'transparent';\n }\n }}\n >\n <div\n style={{\n width: '28px',\n height: '28px',\n borderRadius: '6px',\n backgroundColor: m.id === model\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-bg-secondary, #f3f4f6)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg\n name=\"robot-line\"\n size={14}\n color={m.id === model ? '#ffffff' : 'var(--chatllm-text-muted, #9ca3af)'}\n />\n </div>\n <div>\n <div\n style={{\n fontSize: '14px',\n fontWeight: m.id === model ? 500 : 400,\n color: 'var(--chatllm-text, #1f2937)',\n }}\n >\n {m.name}\n </div>\n {m.description && (\n <div style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #9ca3af)' }}>\n {m.description}\n </div>\n )}\n </div>\n {m.id === model && (\n <IconSvg\n name=\"check-line\"\n size={16}\n color=\"var(--chatllm-primary, #3b82f6)\"\n className=\"ml-auto\"\n />\n )}\n </button>\n ))}\n </div>\n ))}\n </div>\n </>\n )}\n </div>\n )}\n\n {/* Settings Button */}\n {showSettings && (\n <button\n onClick={onSettingsOpen}\n style={{\n width: '36px',\n height: '36px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover, #f3f4f6)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <IconSvg name=\"settings-3-line\" size={20} color=\"var(--chatllm-text-muted, #6b7280)\" />\n </button>\n )}\n </div>\n </header>\n );\n};\n\nexport default ChatHeader;\n","/**\n * @description 채팅 입력창 컴포넌트 - Modern Canvas 디자인\n * @Todo vibecode - v0.11.0 새 디자인 시스템 적용 (플로팅 스타일)\n */\n\nimport React, { useRef, useEffect, useState } from 'react';\nimport { IconSvg } from './Icon';\nimport type { IconName } from './Icon';\nimport type { InputProps, ActionItem, ManualSkillItem, SkillExecution, ChatAttachment } from '../types';\n\nexport const ChatInput: React.FC<InputProps> = ({\n value,\n onChange,\n onSubmit,\n onStop,\n isLoading,\n placeholder = 'Message or ask a question...',\n quotedText,\n onClearQuote,\n selectedAction,\n onClearAction,\n onActionSelect,\n actions = [],\n onDeepResearch,\n isDeepResearchMode,\n deepResearchEnabled,\n manualSkills = [],\n onSkillSelect,\n activeSkillExecution,\n attachments = [],\n onFileAttach,\n onRemoveAttachment,\n acceptedFileTypes,\n onDisclaimerClick,\n inline = false,\n}) => {\n const [mainMenuOpen, setMainMenuOpen] = React.useState(false);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [actionMenuOpen, setActionMenuOpen] = useState(false);\n const [isDragOver, setIsDragOver] = useState(false);\n const mainMenuRef = useRef<HTMLDivElement>(null);\n const actionMenuRef = useRef<HTMLDivElement>(null);\n\n // Auto-resize textarea\n useEffect(() => {\n if (textareaRef.current) {\n textareaRef.current.style.height = 'auto';\n textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 200)}px`;\n }\n }, [value]);\n\n // Close menus on outside click\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (mainMenuRef.current && !mainMenuRef.current.contains(event.target as Node)) {\n setMainMenuOpen(false);\n }\n if (actionMenuRef.current && !actionMenuRef.current.contains(event.target as Node)) {\n setActionMenuOpen(false);\n }\n };\n\n if (mainMenuOpen || actionMenuOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [mainMenuOpen, actionMenuOpen]);\n\n /**\n * @description 클립보드 붙여넣기로 파일 첨부\n * @Todo vibecode - Ctrl+V로 이미지 붙여넣기 지원\n */\n const handlePaste = (e: React.ClipboardEvent) => {\n const files = Array.from(e.clipboardData.files);\n if (files.length > 0 && onFileAttach) {\n e.preventDefault();\n onFileAttach(files);\n }\n };\n\n /**\n * @description 드래그앤드롭 파일 첨부\n * @Todo vibecode - 파일 드롭 시 첨부\n */\n const handleDrop = (e: React.DragEvent) => {\n e.preventDefault();\n setIsDragOver(false);\n const files = Array.from(e.dataTransfer.files);\n if (files.length > 0 && onFileAttach) {\n onFileAttach(files);\n }\n };\n\n const handleDragOver = (e: React.DragEvent) => {\n e.preventDefault();\n setIsDragOver(true);\n };\n\n const handleDragLeave = (e: React.DragEvent) => {\n e.preventDefault();\n setIsDragOver(false);\n };\n\n /**\n * @description 파일 선택 다이얼로그에서 파일 첨부\n * @Todo vibecode - \"+\" 메뉴 → \"파일 또는 사진 추가\" 클릭 시\n */\n const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(e.target.files || []);\n if (files.length > 0 && onFileAttach) {\n onFileAttach(files);\n }\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n };\n\n /** @Todo vibecode - 한글 IME 조합 중 Enter 방지 (isComposing 체크) */\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.nativeEvent.isComposing || e.keyCode === 229) return;\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n onSubmit();\n }\n };\n\n const handleActionSelect = (action: ActionItem) => {\n onActionSelect?.(action);\n setActionMenuOpen(false);\n };\n\n /**\n * @description 스킬 아이콘 매핑\n * @Todo vibecode - 스킬 icon 문자열 → IconSvg name 변환\n */\n const mapSkillIcon = (icon?: string): IconName => {\n const iconMap: Record<string, IconName> = {\n search: 'search-eye-line',\n image: 'image-line',\n code: 'code-s-slash-line',\n file: 'file-text-line',\n document: 'file-text-line',\n };\n return icon ? iconMap[icon] || 'sparkling-line' : 'sparkling-line';\n };\n\n return (\n <footer\n className=\"chatllm-input-footer\"\n style={{\n position: inline ? 'relative' : 'absolute',\n bottom: inline ? undefined : 0,\n left: inline ? undefined : 0,\n right: inline ? undefined : 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n paddingBottom: inline ? '0px' : '16px',\n paddingTop: inline ? '0px' : '64px',\n background: inline ? 'transparent' : 'linear-gradient(to top, var(--chatllm-bg) 60%, transparent)',\n pointerEvents: inline ? undefined : 'none',\n }}\n >\n <div\n style={{\n width: '100%',\n maxWidth: '820px',\n padding: '0 24px',\n pointerEvents: 'auto',\n }}\n >\n {/* Skill Execution Chip */}\n {activeSkillExecution && activeSkillExecution.status === 'executing' && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 14px',\n marginBottom: '12px',\n backgroundColor: 'var(--chatllm-primary-light)',\n borderRadius: '9999px',\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-primary)',\n }}\n >\n <span\n className=\"chatllm-skeleton-pulse\"\n style={{\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-primary)',\n }}\n />\n {activeSkillExecution.skillName} 실행 중...\n </div>\n )}\n\n {/* Quote & Action Chips */}\n {(quotedText || selectedAction) && (\n <div style={{ display: 'flex', gap: '8px', marginBottom: '12px', flexWrap: 'wrap' }}>\n {/* Quote Chip */}\n {quotedText && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 12px',\n backgroundColor: 'var(--chatllm-content-bg)',\n borderRadius: '12px',\n border: '1px solid var(--chatllm-border)',\n maxWidth: '100%',\n }}\n >\n <IconSvg name=\"double-quotes-l\" size={14} color=\"var(--chatllm-primary)\" />\n <span\n style={{\n fontSize: '13px',\n color: 'var(--chatllm-text)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n maxWidth: '300px',\n }}\n >\n {quotedText}\n </span>\n <button\n onClick={onClearQuote}\n style={{\n padding: '2px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg name=\"close-line\" size={14} color=\"var(--chatllm-text-muted)\" />\n </button>\n </div>\n )}\n\n {/* Action Chip */}\n {selectedAction && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n padding: '8px 14px',\n backgroundColor: 'var(--chatllm-primary-light)',\n borderRadius: '9999px',\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-primary)',\n }}\n >\n <IconSvg name=\"sparkling-line\" size={14} color=\"var(--chatllm-primary)\" />\n {selectedAction.label}\n <button\n onClick={onClearAction}\n style={{\n padding: '2px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg name=\"close-line\" size={14} color=\"var(--chatllm-primary)\" />\n </button>\n </div>\n )}\n </div>\n )}\n\n {/* Hidden File Input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n accept={acceptedFileTypes?.join(',') || undefined}\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n />\n\n {/* Input Container */}\n <div\n className=\"chatllm-input-container\"\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n style={isDragOver ? { outline: '2px dashed var(--chatllm-primary)', outlineOffset: '-2px' } : undefined}\n >\n {/* Attachment Preview */}\n {attachments.length > 0 && (\n <div\n style={{\n display: 'flex',\n gap: '8px',\n padding: '12px 24px 0 24px',\n flexWrap: 'wrap',\n }}\n >\n {attachments.map((att) => (\n <div\n key={att.id}\n style={{\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: att.type === 'image' ? '0' : '8px 12px',\n backgroundColor: 'var(--chatllm-content-bg)',\n borderRadius: '12px',\n border: '1px solid var(--chatllm-border)',\n overflow: 'hidden',\n }}\n >\n {att.type === 'image' && att.previewUrl ? (\n <img\n src={att.previewUrl}\n alt={att.name}\n style={{\n width: '64px',\n height: '64px',\n objectFit: 'cover',\n borderRadius: '12px',\n }}\n />\n ) : (\n <>\n <IconSvg name=\"file-text-line\" size={16} color=\"var(--chatllm-text-muted)\" />\n <span style={{ fontSize: '13px', color: 'var(--chatllm-text)', maxWidth: '120px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {att.name}\n </span>\n </>\n )}\n {/* Remove Button */}\n <button\n onClick={() => onRemoveAttachment?.(att.id)}\n style={{\n position: 'absolute',\n top: '2px',\n right: '2px',\n width: '20px',\n height: '20px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'rgba(0,0,0,0.5)',\n border: 'none',\n borderRadius: '50%',\n cursor: 'pointer',\n padding: 0,\n }}\n >\n <IconSvg name=\"close-line\" size={12} color=\"#fff\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* Textarea */}\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n placeholder={placeholder}\n rows={1}\n style={{\n width: '100%',\n minHeight: '60px',\n maxHeight: '200px',\n padding: '24px 32px 8px 32px',\n backgroundColor: 'transparent',\n border: 'none',\n outline: 'none',\n fontSize: '16px',\n lineHeight: '1.5',\n resize: 'none',\n color: 'var(--chatllm-text)',\n }}\n />\n\n {/* Bottom Actions */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '0 24px 20px 24px',\n }}\n >\n {/* Left Actions */}\n <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>\n {/* Add Menu Button */}\n {actions.length > 0 && (\n <div ref={actionMenuRef} style={{ position: 'relative' }}>\n <button\n onClick={() => setActionMenuOpen(!actionMenuOpen)}\n style={iconButtonStyle}\n title=\"기능 추가\"\n >\n <IconSvg name=\"add-line\" size={22} color=\"var(--chatllm-text-muted)\" />\n </button>\n\n {/* Action Menu Dropdown */}\n {actionMenuOpen && (\n <div\n style={{\n position: 'absolute',\n bottom: '100%',\n left: 0,\n marginBottom: '8px',\n backgroundColor: 'var(--chatllm-content-bg)',\n borderRadius: '16px',\n boxShadow: 'var(--chatllm-shadow-sheet)',\n border: '1px solid var(--chatllm-border)',\n padding: '8px',\n minWidth: '220px',\n zIndex: 100,\n }}\n >\n {actions.map((action) => (\n <button\n key={action.id}\n onClick={() => handleActionSelect(action)}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '12px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <div\n style={{\n width: '36px',\n height: '36px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'var(--chatllm-primary-light)',\n borderRadius: '10px',\n }}\n >\n <IconSvg\n name={\n action.icon === 'search'\n ? 'search-line'\n : action.icon === 'image'\n ? 'image-line'\n : action.icon === 'code'\n ? 'code-s-slash-line'\n : 'file-text-line'\n }\n size={20}\n color=\"var(--chatllm-primary)\"\n />\n </div>\n <div>\n <div style={{ fontSize: '14px', fontWeight: 600, color: 'var(--chatllm-text)' }}>\n {action.label}\n </div>\n <div style={{ fontSize: '12px', color: 'var(--chatllm-text-muted)' }}>\n {action.description}\n </div>\n </div>\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n\n {/** @Todo vibecode - 파일 업로드 바로가기 버튼 (+ 메뉴 옆 배치) */}\n <button\n onClick={() => fileInputRef.current?.click()}\n style={iconButtonStyle}\n title=\"파일 첨부\"\n aria-label=\"파일 첨부\"\n >\n <IconSvg name=\"attachment-line\" size={22} color=\"var(--chatllm-text-muted)\" />\n </button>\n\n {/* Main Menu Button */}\n <div ref={mainMenuRef} style={{ position: 'relative' }}>\n <button\n onClick={() => setMainMenuOpen(!mainMenuOpen)}\n style={{\n ...iconButtonStyle,\n backgroundColor: mainMenuOpen ? 'var(--chatllm-bg-hover)' : 'transparent',\n }}\n title=\"메뉴\"\n >\n <IconSvg name=\"add-line\" size={22} color=\"var(--chatllm-text-muted)\" />\n </button>\n\n {/* Main Menu Dropdown */}\n {mainMenuOpen && (\n <div\n style={{\n position: 'absolute',\n bottom: '100%',\n left: 0,\n marginBottom: '8px',\n backgroundColor: 'var(--chatllm-content-bg)',\n borderRadius: '16px',\n boxShadow: 'var(--chatllm-shadow-sheet)',\n border: '1px solid var(--chatllm-border)',\n padding: '8px',\n minWidth: '240px',\n zIndex: 100,\n }}\n >\n {/* File Upload */}\n <button\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '12px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n onClick={() => {\n fileInputRef.current?.click();\n setMainMenuOpen(false);\n }}\n >\n <IconSvg name=\"attachment-line\" size={20} color=\"var(--chatllm-text-secondary)\" />\n <span style={{ fontSize: '14px', color: 'var(--chatllm-text)' }}>\n 파일 또는 사진 추가\n </span>\n </button>\n\n {/* Deep Research */}\n {/* Deep Research (하위 호환) */}\n {deepResearchEnabled && (\n <button\n onClick={() => {\n onDeepResearch?.();\n setMainMenuOpen(false);\n }}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '12px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <IconSvg\n name=\"search-eye-line\"\n size={20}\n color={isDeepResearchMode ? 'var(--chatllm-primary)' : 'var(--chatllm-text-secondary)'}\n />\n <span\n style={{\n flex: 1,\n fontSize: '14px',\n color: isDeepResearchMode ? 'var(--chatllm-primary)' : 'var(--chatllm-text)',\n }}\n >\n 연구\n </span>\n {isDeepResearchMode && (\n <IconSvg name=\"check-line\" size={16} color=\"var(--chatllm-primary)\" />\n )}\n </button>\n )}\n\n {/* Manual Skills */}\n {manualSkills.map((skill) => (\n <button\n key={skill.name}\n onClick={() => {\n onSkillSelect?.(skill.name);\n setMainMenuOpen(false);\n }}\n disabled={skill.disabled}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '12px',\n cursor: skill.disabled ? 'not-allowed' : 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s',\n opacity: skill.disabled ? 0.5 : 1,\n }}\n onMouseOver={(e) => {\n if (!skill.disabled) {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <div\n style={{\n width: '36px',\n height: '36px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'var(--chatllm-primary-light)',\n borderRadius: '10px',\n }}\n >\n <IconSvg\n name={mapSkillIcon(skill.icon)}\n size={20}\n color=\"var(--chatllm-primary)\"\n />\n </div>\n <div>\n <div style={{ fontSize: '14px', fontWeight: 600, color: 'var(--chatllm-text)' }}>\n {skill.label}\n </div>\n <div style={{ fontSize: '12px', color: 'var(--chatllm-text-muted)', maxWidth: '180px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {skill.description}\n </div>\n </div>\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* Send / Stop Button */}\n {isLoading ? (\n <button\n onClick={onStop}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '48px',\n padding: '0 32px',\n backgroundColor: 'var(--chatllm-bg-tertiary)',\n border: '1px solid var(--chatllm-border)',\n borderRadius: '12px',\n cursor: 'pointer',\n transition: 'all 0.2s',\n gap: '8px',\n }}\n >\n <span\n style={{\n fontSize: '14px',\n fontWeight: 700,\n color: 'var(--chatllm-text-secondary)',\n textTransform: 'uppercase',\n letterSpacing: '0.02em',\n }}\n >\n 중지\n </span>\n <IconSvg name=\"stop-circle-line\" size={18} color=\"var(--chatllm-text-secondary)\" />\n </button>\n ) : (\n <button\n onClick={onSubmit}\n disabled={!value.trim() && attachments.length === 0}\n className=\"chatllm-btn-primary\"\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '48px',\n padding: '0 32px',\n borderRadius: '12px',\n cursor: (value.trim() || attachments.length > 0) ? 'pointer' : 'not-allowed',\n opacity: (value.trim() || attachments.length > 0) ? 1 : 0.5,\n gap: '8px',\n }}\n >\n <span\n style={{\n fontSize: '14px',\n fontWeight: 700,\n letterSpacing: '0.02em',\n }}\n >\n 보내기\n </span>\n <IconSvg name=\"arrow-up-s-line\" size={20} color=\"#ffffff\" />\n </button>\n )}\n </div>\n </div>\n\n {/** @Todo vibecode - AI 면책조항 텍스트 (하단 중앙, 클릭 시 모달). inline 모드에서는 숨김 */}\n {!inline && (\n <p\n onClick={onDisclaimerClick}\n role={onDisclaimerClick ? 'button' : undefined}\n tabIndex={onDisclaimerClick ? 0 : undefined}\n style={{\n textAlign: 'center',\n marginTop: '10px',\n marginBottom: 0,\n cursor: onDisclaimerClick ? 'pointer' : 'default',\n fontSize: '12px',\n color: '#94a3b8',\n lineHeight: 1.4,\n }}\n >\n AI인 저도 실수를 할 수 있어요 🥹\n </p>\n )}\n </div>\n </footer>\n );\n};\n\nconst iconButtonStyle: React.CSSProperties = {\n padding: '10px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '12px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'background-color 0.2s, color 0.2s',\n};\n\nexport default ChatInput;\n","/**\n * @description 메시지 목록 컴포넌트\n */\n\nimport React, { useRef, useEffect, useCallback, useState } from 'react';\nimport { MessageBubble } from './MessageBubble';\nimport { IconSvg } from './Icon';\nimport type { MessageListProps } from '../types';\n\nexport const MessageList: React.FC<MessageListProps> = ({\n messages,\n isLoading,\n onCopy,\n onEdit,\n onRegenerate,\n onQuote,\n onAskOtherModel,\n onSetActiveAlternative,\n activeAlternatives = {},\n models,\n copiedId,\n editingId,\n onChoiceClick,\n showThinking = true,\n thinkingDefaultOpen = false,\n loadingAlternativeFor,\n onPollSubmit,\n}) => {\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const [selectedText, setSelectedText] = useState('');\n const [selectionPosition, setSelectionPosition] = useState<{ x: number; y: number } | null>(null);\n\n /** @Todo vibecode - 스크롤 위치 기반 자동스크롤 잠금 */\n const [showScrollButton, setShowScrollButton] = useState(false);\n const isUserScrolledUpRef = useRef(false);\n const SCROLL_THRESHOLD = 100;\n\n /** @Todo vibecode - 스크롤 이벤트 핸들러: 하단 근접 여부 판단 */\n const handleScroll = useCallback(() => {\n if (!containerRef.current) return;\n const { scrollTop, scrollHeight, clientHeight } = containerRef.current;\n const distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n const isNearBottom = distanceFromBottom < SCROLL_THRESHOLD;\n\n isUserScrolledUpRef.current = !isNearBottom;\n setShowScrollButton(!isNearBottom);\n }, []);\n\n /** @Todo vibecode - 조건부 auto-scroll: 사용자가 위로 스크롤한 상태면 스킵 */\n useEffect(() => {\n if (isUserScrolledUpRef.current) return;\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages]);\n\n /** @Todo vibecode - 맨 아래로 스크롤 + 자동스크롤 재개 */\n const scrollToBottom = useCallback(() => {\n isUserScrolledUpRef.current = false;\n setShowScrollButton(false);\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, []);\n\n // Handle text selection\n const handleMouseUp = useCallback(() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n const selection = typeof window !== 'undefined' ? window.getSelection() : null;\n const text = selection?.toString().trim();\n\n if (text && text.length > 0) {\n const range = selection?.getRangeAt(0);\n const rect = range?.getBoundingClientRect();\n if (rect && containerRef.current) {\n const containerRect = containerRef.current.getBoundingClientRect();\n const scrollTop = containerRef.current.scrollTop;\n setSelectedText(text);\n setSelectionPosition({\n x: rect.left - containerRect.left + rect.width / 2,\n y: rect.top - containerRect.top + scrollTop - 10,\n });\n }\n } else {\n setTimeout(() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n const currentSelection = typeof window !== 'undefined' ? window.getSelection()?.toString().trim() : undefined;\n if (!currentSelection) {\n setSelectionPosition(null);\n }\n }, 100);\n }\n }, []);\n\n // Handle quote\n const handleQuote = () => {\n if (selectedText && onQuote) {\n onQuote(selectedText);\n setSelectionPosition(null);\n setSelectedText('');\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n if (typeof window !== 'undefined') {\n window.getSelection()?.removeAllRanges();\n }\n }\n };\n\n return (\n <div\n ref={containerRef}\n className=\"chatllm-message-list chatllm-scrollbar\"\n style={{\n flex: 1,\n overflow: 'auto',\n position: 'relative',\n }}\n onScroll={handleScroll}\n onMouseUp={handleMouseUp}\n >\n {/* Messages Container with max-width */}\n <div\n style={{\n maxWidth: '860px',\n margin: '0 auto',\n paddingTop: '32px',\n paddingBottom: '240px', // Space for floating input\n }}\n >\n {messages.map((message, index) => {\n // For user messages, find the next assistant message\n const nextAssistant =\n message.role === 'user' && index + 1 < messages.length\n ? messages[index + 1]\n : null;\n const assistantForAlts =\n nextAssistant?.role === 'assistant' ? nextAssistant : null;\n\n // Get active alternative index for the assistant message\n const activeAltIndex = assistantForAlts\n ? activeAlternatives[assistantForAlts.id] ?? 0\n : 0;\n\n return (\n <MessageBubble\n key={message.id}\n message={message}\n isLoading={isLoading && index === messages.length - 1 && message.role === 'assistant'}\n isCopied={copiedId === message.id}\n isEditing={editingId === message.id}\n onCopy={() => onCopy(message.content, message.id)}\n onEdit={() => onEdit(message)}\n onRegenerate={message.role === 'assistant' ? () => onRegenerate(message.id) : undefined}\n onQuote={onQuote}\n // User messages: pass next assistant message for controls\n nextAssistantMessage={assistantForAlts}\n activeAlternativeIndex={message.role === 'user' ? activeAltIndex : activeAlternatives[message.id] ?? 0}\n onAskOtherModel={\n message.role === 'user' && assistantForAlts && onAskOtherModel\n ? (targetModel) => onAskOtherModel(message.id, assistantForAlts.id, targetModel)\n : message.role === 'assistant' && onAskOtherModel\n ? (targetModel) => {\n // assistant 메시지의 경우 이전 user 메시지를 찾아서 전달\n const prevUserMsg = messages[index - 1];\n if (prevUserMsg?.role === 'user') {\n onAskOtherModel(prevUserMsg.id, message.id, targetModel);\n }\n }\n : undefined\n }\n onAlternativeChange={\n message.role === 'user' && assistantForAlts && onSetActiveAlternative\n ? (idx) => onSetActiveAlternative(assistantForAlts.id, idx)\n : message.role === 'assistant' && onSetActiveAlternative\n ? (idx) => onSetActiveAlternative(message.id, idx)\n : undefined\n }\n models={models}\n alternatives={message.role === 'assistant' ? message.alternatives : assistantForAlts?.alternatives}\n onChoiceClick={message.role === 'assistant' ? onChoiceClick : undefined}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n isLoadingAlternative={loadingAlternativeFor === message.id}\n onPollSubmit={\n message.role === 'assistant' && onPollSubmit\n ? (response) => onPollSubmit(message.id, response)\n : undefined\n }\n />\n );\n })}\n\n <div ref={messagesEndRef} />\n </div>\n\n {/** @Todo vibecode - 맨 아래로 스크롤 FAB 버튼 (position: sticky) */}\n {showScrollButton && (\n <button\n onClick={scrollToBottom}\n aria-label=\"맨 아래로 스크롤\"\n style={{\n position: 'sticky',\n bottom: '260px',\n left: '50%',\n transform: 'translateX(-50%)',\n width: '40px',\n height: '40px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-content-bg)',\n border: '1px solid var(--chatllm-border)',\n boxShadow: '0 2px 8px rgba(0,0,0,0.15)',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 10,\n transition: 'opacity 0.2s',\n }}\n >\n <IconSvg name=\"arrow-down-s-line\" size={24} color=\"var(--chatllm-text-secondary)\" />\n </button>\n )}\n\n {/* Selection Popup */}\n {selectionPosition && (\n <div\n style={{\n position: 'absolute',\n left: selectionPosition.x,\n top: selectionPosition.y,\n transform: 'translate(-50%, -100%)',\n zIndex: 9999,\n pointerEvents: 'auto',\n }}\n >\n <button\n onClick={handleQuote}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n padding: '10px 16px',\n backgroundColor: '#1f2937',\n color: '#ffffff',\n border: 'none',\n borderRadius: '10px',\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n boxShadow: '0 4px 16px rgba(0, 0, 0, 0.2)',\n whiteSpace: 'nowrap',\n }}\n >\n <IconSvg name=\"double-quotes-l\" size={16} color=\"#ffffff\" />\n 인용하기\n </button>\n {/* Arrow */}\n <div\n style={{\n position: 'absolute',\n left: '50%',\n bottom: '-6px',\n transform: 'translateX(-50%)',\n width: 0,\n height: 0,\n borderLeft: '6px solid transparent',\n borderRight: '6px solid transparent',\n borderTop: '6px solid #1f2937',\n }}\n />\n </div>\n )}\n </div>\n );\n};\n\nexport default MessageList;\n","/**\n * @description 메시지 버블 컴포넌트 - Modern Canvas 디자인\n * @Todo vibecode - v0.11.0 새 디자인 시스템 적용\n */\n\nimport React, { useState, useCallback } from 'react';\nimport { IconSvg } from './Icon';\nimport { MarkdownRenderer } from './MarkdownRenderer';\nimport { LinkChip } from './LinkChip';\nimport { DeepResearchProgressUI } from './DeepResearchProgressUI';\nimport { PollCard } from './PollCard';\nimport { SkillProgressUI } from './SkillProgressUI';\nimport { ContentPartRenderer } from './ContentPartRenderer';\nimport type { MessageBubbleProps, PollResponse, DeepResearchProgress } from '../types';\n\nexport const MessageBubble: React.FC<MessageBubbleProps> = ({\n message,\n isLoading,\n isCopied,\n isEditing,\n onCopy,\n onEdit,\n onRegenerate,\n onQuote,\n onAskOtherModel,\n models,\n alternatives,\n activeAlternativeIndex = 0,\n onAlternativeChange,\n nextAssistantMessage,\n onChoiceClick,\n showThinking = true,\n thinkingDefaultOpen = false,\n isLoadingAlternative = false,\n onPollSubmit,\n}) => {\n const [showActions, setShowActions] = useState(false);\n const [showModelMenu, setShowModelMenu] = useState(false);\n const isUser = message.role === 'user';\n const isAssistant = message.role === 'assistant';\n\n const relevantAlternatives = isUser ? alternatives : message.alternatives;\n const relevantActiveIndex = activeAlternativeIndex;\n\n const currentAssistantModel = isUser ? nextAssistantMessage?.model : message.model;\n const otherModels = models?.filter((m) => m.id !== currentAssistantModel) || [];\n\n const displayContent =\n isAssistant && relevantAlternatives && relevantAlternatives.length > 0 && relevantActiveIndex > 0\n ? relevantAlternatives[relevantActiveIndex - 1]?.content || message.content\n : message.content;\n\n const displayModel =\n isAssistant && relevantAlternatives && relevantAlternatives.length > 0 && relevantActiveIndex > 0\n ? relevantAlternatives[relevantActiveIndex - 1]?.model\n : message.model;\n\n const displaySources =\n isAssistant && relevantAlternatives && relevantAlternatives.length > 0 && relevantActiveIndex > 0\n ? relevantAlternatives[relevantActiveIndex - 1]?.sources\n : message.sources;\n\n const handleMouseUp = () => {\n if (!onQuote) return;\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n const selection = typeof window !== 'undefined' ? window.getSelection() : null;\n const text = selection?.toString().trim();\n if (text && text.length > 0) {\n // Will be handled by parent component\n }\n };\n\n // User Message - 오른쪽 정렬, 회색 버블\n if (isUser) {\n return (\n <div\n className=\"chatllm-message chatllm-message--user\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-end',\n padding: '4px 24px',\n }}\n onMouseEnter={() => setShowActions(true)}\n onMouseLeave={() => setShowActions(false)}\n onMouseUp={handleMouseUp}\n >\n {/* 버블 */}\n <div\n style={{\n maxWidth: '70%',\n backgroundColor: 'var(--chatllm-user-bubble)',\n padding: '10px 14px',\n borderRadius: '16px',\n borderTopRightRadius: '4px',\n }}\n >\n {/* @Todo vibecode - user 메시지 contentParts 렌더링 (이미지/파일 첨부) */}\n {message.contentParts?.length ? (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {message.contentParts.map((part, idx) => {\n if (part.type === 'text') {\n return (\n <div\n key={idx}\n style={{\n fontSize: '14px',\n lineHeight: '1.5',\n color: 'var(--chatllm-text)',\n whiteSpace: 'pre-wrap',\n }}\n >\n {part.content}\n </div>\n );\n }\n if (part.type === 'image') {\n return (\n <img\n key={idx}\n src={part.url}\n alt={part.alt || '첨부 이미지'}\n style={{\n maxWidth: '100%',\n maxHeight: '300px',\n borderRadius: '8px',\n objectFit: 'contain',\n }}\n />\n );\n }\n if (part.type === 'file') {\n return (\n <div\n key={idx}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 12px',\n backgroundColor: 'rgba(0,0,0,0.05)',\n borderRadius: '8px',\n fontSize: '13px',\n color: 'var(--chatllm-text)',\n }}\n >\n <IconSvg name=\"file-text-line\" size={16} color=\"var(--chatllm-text-muted)\" />\n <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {part.name}\n </span>\n </div>\n );\n }\n return null;\n })}\n </div>\n ) : (\n <div\n style={{\n fontSize: '14px',\n lineHeight: '1.5',\n color: 'var(--chatllm-text)',\n whiteSpace: 'pre-wrap',\n }}\n >\n {displayContent}\n </div>\n )}\n </div>\n\n {/* Action Buttons - 버블 아래에 표시 */}\n {!isLoading && (\n <div\n style={{\n display: 'flex',\n gap: '2px',\n marginTop: '4px',\n height: '24px',\n opacity: showActions ? 1 : 0,\n transition: 'opacity 0.15s ease',\n }}\n >\n <button onClick={onCopy} style={actionButtonSmallStyle} title=\"복사\">\n <IconSvg\n name={isCopied ? 'check-line' : 'file-copy-line'}\n size={12}\n color={isCopied ? 'var(--chatllm-success)' : 'var(--chatllm-text-muted)'}\n />\n </button>\n <button onClick={onEdit} style={actionButtonSmallStyle} title=\"수정\">\n <IconSvg name=\"edit-line\" size={12} color=\"var(--chatllm-text-muted)\" />\n </button>\n </div>\n )}\n </div>\n );\n }\n\n // Assistant Message - 왼쪽 정렬, 흰색 카드\n return (\n <div\n className=\"chatllm-message chatllm-message--assistant\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-start',\n padding: '4px 24px',\n }}\n onMouseEnter={() => setShowActions(true)}\n onMouseLeave={() => setShowActions(false)}\n onMouseUp={handleMouseUp}\n >\n <div\n className=\"chatllm-sheet\"\n style={{\n width: '100%',\n padding: '16px',\n display: 'flex',\n gap: '12px',\n }}\n >\n {/* AI Icon */}\n <div style={{ flexShrink: 0 }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '10px',\n backgroundColor: 'var(--chatllm-primary-light)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'var(--chatllm-primary)',\n }}\n >\n <IconSvg name=\"magic-line\" size={20} />\n </div>\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, minWidth: 0 }}>\n {/* Model Badge */}\n {displayModel && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginBottom: '8px',\n }}\n >\n <span\n style={{\n fontSize: '12px',\n fontWeight: 600,\n color: 'var(--chatllm-text-muted)',\n textTransform: 'uppercase',\n letterSpacing: '0.02em',\n }}\n >\n {displayModel}\n </span>\n </div>\n )}\n\n {/* Deep Research Progress */}\n {message.isDeepResearch && message.researchProgress && message.researchProgress.phase !== 'done' && (\n <DeepResearchProgressUI progress={message.researchProgress} />\n )}\n\n {/* Skill Execution Progress - 딥리서치면 상세 카드, 아니면 간단 UI */}\n {message.skillExecution && message.skillExecution.status !== 'done' && (\n message.skillExecution.progress?.subAgents\n ? <DeepResearchProgressUI progress={message.skillExecution.progress as DeepResearchProgress} />\n : <SkillProgressUI execution={message.skillExecution} />\n )}\n\n {/* Deep Research Result Header */}\n {message.isDeepResearch && displayContent && (\n <div\n className=\"chatllm-deep-research__header\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginBottom: '16px',\n paddingBottom: '12px',\n borderBottom: '1px solid var(--chatllm-border-light)',\n }}\n >\n <IconSvg name=\"search-eye-line\" size={18} color=\"var(--chatllm-primary)\" />\n <span\n style={{\n fontSize: '14px',\n fontWeight: 600,\n color: 'var(--chatllm-text)',\n }}\n >\n 심층연구\n </span>\n {displaySources && displaySources.length > 0 && (\n <span\n className=\"chatllm-deep-research__source-count\"\n style={{\n marginLeft: 'auto',\n fontSize: '12px',\n fontWeight: 500,\n color: 'var(--chatllm-text-muted)',\n padding: '4px 10px',\n backgroundColor: 'var(--chatllm-bg-secondary)',\n borderRadius: '12px',\n }}\n >\n {displaySources.length}개 출처\n </span>\n )}\n </div>\n )}\n\n {/** @Todo vibecode - contentParts 우선 렌더링 (tool result 카드가 로딩 위에 표시) */}\n {message.contentParts?.length && (\n <div style={{ wordBreak: 'break-word' }}>\n <ContentPartRenderer\n parts={message.contentParts}\n onChoiceClick={onChoiceClick}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n />\n </div>\n )}\n\n {/** @Todo vibecode - Loading State: contentParts 유무에 따라 스켈레톤/간소화 분기 */}\n {isLoading && !displayContent && !message.isDeepResearch && (\n message.contentParts?.length ? (\n /* contentParts 있을 때: 간소화된 AI 응답 대기 표시 */\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '4px' }}>\n <div style={{ display: 'flex', gap: '4px', alignItems: 'center' }}>\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n </div>\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n fontStyle: 'italic',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n 답변 생성 중...\n </span>\n </div>\n ) : (\n /* contentParts 없을 때: 풀 스켈레톤 */\n <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>\n <div style={{ display: 'flex', gap: '4px', alignItems: 'center' }}>\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n </div>\n <span\n style={{\n fontSize: '14px',\n fontWeight: 600,\n fontStyle: 'italic',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n 생각 중...\n </span>\n </div>\n <div className=\"chatllm-skeleton-pulse\" style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>\n <div style={{ height: '32px', width: '75%', backgroundColor: 'var(--chatllm-bg-tertiary)', borderRadius: '8px' }} />\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n <div style={{ height: '16px', width: '100%', backgroundColor: 'var(--chatllm-bg-secondary)', borderRadius: '4px' }} />\n <div style={{ height: '16px', width: '85%', backgroundColor: 'var(--chatllm-bg-secondary)', borderRadius: '4px' }} />\n <div style={{ height: '16px', width: '65%', backgroundColor: 'var(--chatllm-bg-secondary)', borderRadius: '4px' }} />\n </div>\n </div>\n </div>\n )\n )}\n\n {displayContent ? (\n <div style={{ wordBreak: 'break-word' }}>\n <MarkdownRenderer\n content={displayContent}\n onChoiceClick={onChoiceClick}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n />\n </div>\n ) : null}\n\n {/* Poll Card (AI-driven choices) - 탭 UI */}\n {message.pollBlock && message.pollBlock.questions.length > 0 && (\n <PollCard\n questions={message.pollBlock.questions}\n onSubmit={(responses: PollResponse[]) => {\n onPollSubmit?.(responses);\n }}\n onSkip={() => {\n onPollSubmit?.([]);\n }}\n />\n )}\n\n {/* Empty Response Error State */}\n {!isLoading && !displayContent && !message.pollBlock && !message.contentParts?.length && (\n <div\n style={{\n padding: '16px',\n backgroundColor: 'var(--chatllm-bg-secondary)',\n borderRadius: '8px',\n color: 'var(--chatllm-text-muted)',\n fontSize: '14px',\n }}\n >\n 응답을 생성하지 못했습니다. 다시 시도해 주세요.\n </div>\n )}\n\n {/* Sources */}\n {displaySources && displaySources.length > 0 && (\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '8px',\n marginTop: '16px',\n paddingTop: '16px',\n borderTop: '1px solid var(--chatllm-border-light)',\n }}\n >\n <span\n style={{\n fontSize: '12px',\n fontWeight: 500,\n color: 'var(--chatllm-text-muted)',\n marginRight: '4px',\n }}\n >\n 출처:\n </span>\n {displaySources.map((source, index) => (\n <LinkChip\n key={source.id}\n text={source.title}\n url={source.url}\n index={index + 1}\n showFavicon\n />\n ))}\n </div>\n )}\n\n {/* Alternatives Navigation - 다른 모델 답변 탐색 */}\n {relevantAlternatives && relevantAlternatives.length > 0 && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginTop: '12px',\n padding: '8px 12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '8px',\n fontSize: '12px',\n }}\n >\n <span style={{ color: 'var(--chatllm-text-muted)', marginRight: '4px' }}>\n {displayModel || '모델'}\n </span>\n <button\n onClick={() => onAlternativeChange?.(Math.max(0, relevantActiveIndex - 1))}\n disabled={relevantActiveIndex === 0}\n style={{\n ...navButtonStyle,\n opacity: relevantActiveIndex === 0 ? 0.5 : 1,\n cursor: relevantActiveIndex === 0 ? 'not-allowed' : 'pointer',\n }}\n >\n <IconSvg name=\"arrow-left-line\" size={12} />\n </button>\n <span style={{ color: 'var(--chatllm-text-secondary)' }}>\n {relevantActiveIndex + 1} / {relevantAlternatives.length + 1}\n </span>\n <button\n onClick={() =>\n onAlternativeChange?.(Math.min(relevantAlternatives.length, relevantActiveIndex + 1))\n }\n disabled={relevantActiveIndex === relevantAlternatives.length}\n style={{\n ...navButtonStyle,\n opacity: relevantActiveIndex === relevantAlternatives.length ? 0.5 : 1,\n cursor: relevantActiveIndex === relevantAlternatives.length ? 'not-allowed' : 'pointer',\n }}\n >\n <IconSvg name=\"arrow-right-line\" size={12} />\n </button>\n </div>\n )}\n\n {/* Loading Alternative Indicator - 다른 모델 응답 생성 중 */}\n {isLoadingAlternative && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginTop: '12px',\n padding: '10px 14px',\n backgroundColor: 'var(--chatllm-primary-light, #eff6ff)',\n borderRadius: '8px',\n fontSize: '13px',\n color: 'var(--chatllm-primary, #2563eb)',\n }}\n >\n <div style={{ display: 'flex', gap: '4px', alignItems: 'center' }}>\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n <span className=\"chatllm-dot-bounce\" style={dotStyle} />\n </div>\n <span style={{ fontWeight: 500 }}>다른 모델 응답 생성 중...</span>\n </div>\n )}\n </div>\n </div>\n\n {/* Action Buttons - 카드 아래에 표시 */}\n {!isLoading && (\n <div\n style={{\n display: 'flex',\n gap: '2px',\n marginTop: '4px',\n marginLeft: '44px',\n height: '24px',\n opacity: showActions ? 1 : 0,\n transition: 'opacity 0.15s ease',\n }}\n >\n <button onClick={onCopy} style={actionButtonSmallStyle} title=\"복사\">\n <IconSvg\n name={isCopied ? 'check-line' : 'file-copy-line'}\n size={12}\n color={isCopied ? 'var(--chatllm-success)' : 'var(--chatllm-text-muted)'}\n />\n </button>\n {onRegenerate && (\n <button onClick={onRegenerate} style={actionButtonSmallStyle} title=\"다시 생성\">\n <IconSvg name=\"refresh-line\" size={12} color=\"var(--chatllm-text-muted)\" />\n </button>\n )}\n {onAskOtherModel && otherModels.length > 0 && (\n <div style={{ position: 'relative' }}>\n <button\n onClick={() => setShowModelMenu(!showModelMenu)}\n style={actionButtonSmallStyle}\n title=\"다른 모델에게 질문\"\n >\n <IconSvg name=\"robot-line\" size={12} color=\"var(--chatllm-text-muted)\" />\n </button>\n {showModelMenu && (\n <ModelMenu\n models={otherModels}\n onSelect={(modelId) => {\n onAskOtherModel(modelId);\n setShowModelMenu(false);\n }}\n onClose={() => setShowModelMenu(false)}\n />\n )}\n </div>\n )}\n </div>\n )}\n </div>\n );\n};\n\n/**\n * @description 모델 선택 드롭다운 메뉴\n */\nconst ModelMenu: React.FC<{\n models: Array<{ id: string; name: string; provider?: string }>;\n onSelect: (modelId: string) => void;\n onClose: () => void;\n}> = ({ models, onSelect, onClose }) => (\n <div\n style={{\n position: 'absolute',\n bottom: '100%',\n right: 0,\n marginBottom: '4px',\n backgroundColor: 'var(--chatllm-content-bg)',\n border: '1px solid var(--chatllm-border)',\n borderRadius: '12px',\n boxShadow: 'var(--chatllm-shadow-sheet)',\n minWidth: '180px',\n zIndex: 100,\n overflow: 'hidden',\n }}\n onMouseLeave={onClose}\n >\n <div\n style={{\n padding: '10px 14px',\n fontSize: '11px',\n fontWeight: 700,\n color: 'var(--chatllm-text-muted)',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n borderBottom: '1px solid var(--chatllm-border-light)',\n }}\n >\n 다른 모델에게 질문\n </div>\n {models.map((model) => (\n <button\n key={model.id}\n onClick={() => onSelect(model.id)}\n style={{\n width: '100%',\n padding: '12px 14px',\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: 'pointer',\n fontSize: '13px',\n color: 'var(--chatllm-text)',\n textAlign: 'left',\n transition: 'background-color 0.15s',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--chatllm-bg-hover)';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <IconSvg name=\"robot-line\" size={16} color=\"var(--chatllm-primary)\" />\n <span style={{ flex: 1, fontWeight: 500 }}>{model.name}</span>\n {model.provider && (\n <span\n style={{\n fontSize: '10px',\n padding: '2px 8px',\n backgroundColor: 'var(--chatllm-bg-tertiary)',\n borderRadius: '4px',\n color: 'var(--chatllm-text-muted)',\n }}\n >\n {model.provider}\n </span>\n )}\n </button>\n ))}\n </div>\n);\n\nconst dotStyle: React.CSSProperties = {\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-primary)',\n};\n\nconst actionButtonStyle: React.CSSProperties = {\n padding: '8px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'background-color 0.2s',\n};\n\nconst actionButtonSmallStyle: React.CSSProperties = {\n padding: '4px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'background-color 0.2s',\n};\n\nconst navButtonStyle: React.CSSProperties = {\n width: '24px',\n height: '24px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'var(--chatllm-content-bg)',\n border: '1px solid var(--chatllm-border)',\n borderRadius: '6px',\n};\n\nexport default MessageBubble;\n","/**\n * @description 마크다운 렌더러 컴포넌트\n * 외부 의존성 없이 기본 마크다운 파싱 지원\n */\n\nimport React, { useMemo } from 'react';\nimport { LinkChip } from './LinkChip';\nimport type { SourceItem } from '../types';\n\nexport interface ChoiceOption {\n number: number;\n text: string;\n fullText: string;\n}\n\n/** @description 선택지 블록 (제목 + 선택지 목록) */\nexport interface ChoiceBlock {\n title?: string;\n choices: ChoiceOption[];\n}\n\nexport interface MarkdownRendererProps {\n /** 마크다운 텍스트 */\n content: string;\n /** 커스텀 클래스 */\n className?: string;\n /** 선택지 클릭 핸들러 */\n onChoiceClick?: (choice: ChoiceOption) => void;\n /**\n * @description Thinking 블록 표시 여부\n * @Todo vibecode - AI 추론 과정 표시 (기본: true)\n */\n showThinking?: boolean;\n /**\n * @description Thinking 블록 기본 펼침 상태\n * @Todo vibecode - true면 펼쳐진 상태로 표시 (기본: false)\n */\n thinkingDefaultOpen?: boolean;\n /**\n * @description 인라인 소스 참조용 출처 목록\n * @Todo vibecode - [1], [2] 패턴을 소스 URL 링크로 변환\n */\n sources?: SourceItem[];\n}\n\n// 이미지 정규식 - ![alt](url) 패턴\nconst IMAGE_REGEX = /!\\[([^\\]]*)\\]\\(([^)]+)\\)/g;\n// 링크 정규식 - [text](url) 패턴 (이미지가 아닌 것만)\nconst LINK_REGEX = /(?<!!)\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\n// 출처 링크 패턴 - 연속된 링크들 (예: [`1. brave`](url) [`2. brave`](url))\n// 주의: 이미지 링크(![)가 아닌 것만 매칭\nconst SOURCE_LINKS_REGEX = /(\\*{0,2}출처:?\\*{0,2}\\s*)?((?:(?<!!)\\[`?[^\\]]+`?\\]\\([^)]+\\)\\s*)+)/gi;\n\n// 선택지 패턴 - 번호로 시작하는 선택지 (예: 1. 옵션A, 2. 옵션B)\nconst CHOICE_PATTERN = /^(\\d+)[.)]\\s*(.+)$/;\n// 인라인 선택지 패턴 - [1] 텍스트 형식 (예: [1] 뉴스 문장 [2] 일상대화)\nconst INLINE_CHOICE_PATTERN = /\\[(\\d+)\\]\\s*([^\\[\\n]+?)(?=\\s*\\[\\d+\\]|$)/g;\n// 인라인 선택지 블록 감지 패턴 (2개 이상의 [숫자] 패턴이 있는 줄)\nconst INLINE_CHOICE_LINE_PATTERN = /^(.+?)?\\s*(\\[\\d+\\][^\\[]+(?:\\[\\d+\\][^\\[]+)+)$/;\n// 코드 블록 패턴\nconst CODE_BLOCK_REGEX = /```(\\w*)\\n?([\\s\\S]*?)```/g;\n// Thinking 블록 패턴\n/** @Todo vibecode - <thinking> 태그 패턴 (닫는 태그 필수) */\nconst THINKING_TAG_REGEX = /<thinking>([\\s\\S]*?)<\\/thinking>/gi;\n/** @Todo vibecode - ```thinking 코드블록 패턴 */\nconst THINKING_CODEBLOCK_REGEX = /```thinking\\n?([\\s\\S]*?)```/gi;\n/** @Todo vibecode - \"Thinking:\" 텍스트 패턴 (빈 줄까지) */\nconst THINKING_TEXT_REGEX = /^Thinking:\\s*\\n([\\s\\S]*?)(?=\\n\\n|$)/gim;\n/** @Todo vibecode - 닫히지 않은 <thinking> 태그만 제거 (내용은 유지) */\nconst UNCLOSED_THINKING_TAG_REGEX = /<thinking>(?![\\s\\S]*?<\\/thinking>)/gi;\n/** @Todo vibecode - 닫히지 않은 <poll> 태그 전체 제거 (스트리밍 중) */\nconst UNCLOSED_POLL_TAG_REGEX = /<poll[^>]*>(?![\\s\\S]*?<\\/poll>)[\\s\\S]*$/gi;\n/** @Todo vibecode - 닫히지 않은 <skill_use> 태그 전체 제거 (스트리밍 중) */\nconst UNCLOSED_SKILL_TAG_REGEX = /<skill_use[^>]*>(?![\\s\\S]*?<\\/skill_use>)[\\s\\S]*$/gi;\n// 인라인 코드 패턴\nconst INLINE_CODE_REGEX = /`([^`]+)`/g;\n// 굵게 패턴\nconst BOLD_REGEX = /\\*\\*([^*]+)\\*\\*/g;\n// 기울임 패턴 (굵게가 아닌 경우만)\nconst ITALIC_REGEX = /(?<!\\*)\\*([^*]+)\\*(?!\\*)/g;\n// 헤딩 패턴\nconst HEADING_REGEX = /^(#{1,6})\\s+(.+)$/gm;\n// 리스트 아이템 패턴\nconst LIST_ITEM_REGEX = /^[\\-\\*]\\s+(.+)$/gm;\n// 번호 리스트 패턴\nconst NUMBERED_LIST_REGEX = /^(\\d+)\\.\\s+(.+)$/gm;\n// 인용 패턴\nconst BLOCKQUOTE_REGEX = /^>\\s+(.+)$/gm;\n// 수평선 패턴\nconst HR_REGEX = /^---+$/gm;\n// 테이블 행 패턴\nconst TABLE_ROW_REGEX = /^\\|(.+)\\|$/;\n// 테이블 구분선 패턴\nconst TABLE_SEPARATOR_REGEX = /^\\|[\\s\\-:|]+\\|$/;\n\n/**\n * @description 비표준 테이블(탭/공백 구분)을 마크다운 파이프 테이블로 변환\n * @Todo vibecode - AI가 ```markdown 내 탭/공백 구분 형식으로 표를 작성할 때 처리\n */\nconst convertNonStandardTable = (codeContent: string): string | null => {\n const lines = codeContent.trim().split('\\n');\n const nonEmptyLines = lines.filter((l) => l.trim());\n if (nonEmptyLines.length < 2) return null;\n\n /** @Todo vibecode - separator 행 감지 (--- 또는 === 패턴) */\n const isSeparatorLine = (line: string) =>\n /^[-=\\s\\t|:]+$/.test(line.trim()) && /[-=]{2,}/.test(line);\n\n // Case 1: 탭 구분 테이블\n if (nonEmptyLines[0].includes('\\t')) {\n const dataLines = nonEmptyLines.filter((l) => !isSeparatorLine(l));\n if (dataLines.length < 2) return null;\n if (!dataLines.every((l) => l.includes('\\t'))) return null;\n\n const colCount = dataLines[0].split('\\t').length;\n if (colCount < 2) return null;\n\n const result: string[] = [];\n const headerCells = dataLines[0].split('\\t').map((c) => c.trim());\n result.push('| ' + headerCells.join(' | ') + ' |');\n result.push('| ' + Array(colCount).fill('---').join(' | ') + ' |');\n for (let i = 1; i < dataLines.length; i++) {\n const cells = dataLines[i].split('\\t').map((c) => c.trim());\n while (cells.length < colCount) cells.push('');\n result.push('| ' + cells.join(' | ') + ' |');\n }\n return result.join('\\n');\n }\n\n // Case 2: 2개 이상 공백으로 구분된 테이블\n const dataLines = nonEmptyLines.filter((l) => !isSeparatorLine(l));\n if (dataLines.length < 2) return null;\n\n const spaceParsed = dataLines.map((l) =>\n l\n .split(/\\s{2,}/)\n .map((c) => c.trim())\n .filter(Boolean)\n );\n\n const colCount = spaceParsed[0].length;\n if (colCount < 3) return null; // 3컬럼 이상만 (2컬럼은 오탐 위험)\n\n const consistent = spaceParsed.every(\n (cols) => cols.length >= colCount - 1 && cols.length <= colCount + 1\n );\n if (!consistent) return null;\n\n const result: string[] = [];\n result.push('| ' + spaceParsed[0].join(' | ') + ' |');\n result.push('| ' + Array(colCount).fill('---').join(' | ') + ' |');\n for (let i = 1; i < spaceParsed.length; i++) {\n const cells = [...spaceParsed[i]];\n while (cells.length < colCount) cells.push('');\n result.push('| ' + cells.join(' | ') + ' |');\n }\n return result.join('\\n');\n};\n\ninterface ParsedLink {\n text: string;\n url: string;\n}\n\n/**\n * 출처 링크들을 파싱하여 배열로 반환\n */\nconst parseSourceLinks = (text: string): ParsedLink[] => {\n const links: ParsedLink[] = [];\n let match;\n const linkRegex = /\\[`?([^\\]`]+)`?\\]\\(([^)]+)\\)/g;\n\n while ((match = linkRegex.exec(text)) !== null) {\n links.push({\n text: match[1],\n url: match[2],\n });\n }\n\n return links;\n};\n\n/**\n * @description 인라인 선택지 파싱 ([1] 텍스트 [2] 텍스트 형식)\n * @param text 파싱할 텍스트\n * @returns 선택지 블록 또는 null\n */\nconst parseInlineChoices = (text: string): ChoiceBlock | null => {\n const lineMatch = text.match(INLINE_CHOICE_LINE_PATTERN);\n if (!lineMatch) return null;\n\n const title = lineMatch[1]?.trim();\n const choicesText = lineMatch[2];\n\n const choices: ChoiceOption[] = [];\n let match;\n const regex = new RegExp(INLINE_CHOICE_PATTERN.source, 'g');\n\n while ((match = regex.exec(choicesText)) !== null) {\n const number = parseInt(match[1]);\n const choiceText = match[2].trim();\n if (choiceText) {\n choices.push({\n number,\n text: choiceText,\n fullText: `[${number}] ${choiceText}`,\n });\n }\n }\n\n if (choices.length >= 2) {\n return { title, choices };\n }\n\n return null;\n};\n\n/**\n * @description 텍스트에서 인라인 요소 파싱 (굵게, 기울임, 코드, 링크, 소스 참조)\n * @Todo vibecode - sources 전달 시 [N] 패턴을 소스 URL 상위첨자 링크로 변환\n */\nconst parseInlineElements = (text: string, key: string, sources?: SourceItem[]): React.ReactNode[] => {\n const elements: React.ReactNode[] = [];\n let currentText = text;\n\n /**\n * @Todo vibecode - 인라인 소스 참조 [N] → 상위첨자 링크 변환\n * [N](url) 마크다운 링크와 충돌하지 않도록 (?!\\() 사용\n */\n if (sources && sources.length > 0) {\n currentText = currentText.replace(\n /(?<![!\\[])\\[(\\d+)\\](?!\\()/g,\n (match, numStr) => {\n const num = parseInt(numStr);\n if (num >= 1 && num <= sources.length) {\n return `§SRCREF§${num}§/SRCREF§`;\n }\n return match;\n }\n );\n }\n\n // 인라인 코드 처리\n currentText = currentText.replace(INLINE_CODE_REGEX, '§CODE§$1§/CODE§');\n // 굵게 처리\n currentText = currentText.replace(BOLD_REGEX, '§BOLD§$1§/BOLD§');\n // 기울임 처리\n currentText = currentText.replace(ITALIC_REGEX, '§ITALIC§$1§/ITALIC§');\n // 이미지 처리 (링크보다 먼저 처리해야 함)\n currentText = currentText.replace(IMAGE_REGEX, '§IMAGE§$1§URL§$2§/IMAGE§');\n // 일반 링크 처리 (출처 링크가 아닌 것)\n currentText = currentText.replace(LINK_REGEX, '§LINK§$1§URL§$2§/LINK§');\n\n // 파싱된 마커를 React 요소로 변환\n const parts = currentText.split(/(§CODE§.*?§\\/CODE§|§BOLD§.*?§\\/BOLD§|§ITALIC§.*?§\\/ITALIC§|§IMAGE§.*?§\\/IMAGE§|§LINK§.*?§\\/LINK§|§SRCREF§\\d+§\\/SRCREF§)/);\n\n parts.forEach((part, index) => {\n if (part.startsWith('§CODE§')) {\n const content = part.replace('§CODE§', '').replace('§/CODE§', '');\n elements.push(\n <code\n key={`${key}-code-${index}`}\n style={{\n backgroundColor: 'var(--chatllm-code-bg, #f3f4f6)',\n padding: '2px 6px',\n borderRadius: '4px',\n fontSize: '0.9em',\n fontFamily: 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace',\n color: 'var(--chatllm-code-text, #e11d48)',\n }}\n >\n {content}\n </code>\n );\n } else if (part.startsWith('§BOLD§')) {\n const content = part.replace('§BOLD§', '').replace('§/BOLD§', '');\n elements.push(<strong key={`${key}-bold-${index}`}>{content}</strong>);\n } else if (part.startsWith('§ITALIC§')) {\n const content = part.replace('§ITALIC§', '').replace('§/ITALIC§', '');\n elements.push(<em key={`${key}-italic-${index}`}>{content}</em>);\n } else if (part.startsWith('§IMAGE§')) {\n const match = part.match(/§IMAGE§(.*)§URL§(.+?)§\\/IMAGE§/);\n if (match) {\n elements.push(\n <ImageWithCopyButton\n key={`${key}-image-${index}`}\n src={match[2]}\n alt={match[1] || ''}\n imageKey={`${key}-image-${index}`}\n />\n );\n }\n } else if (part.startsWith('§LINK§')) {\n const match = part.match(/§LINK§(.+?)§URL§(.+?)§\\/LINK§/);\n if (match) {\n elements.push(\n <a\n key={`${key}-link-${index}`}\n href={match[2]}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{\n color: 'var(--chatllm-link, #3b82f6)',\n textDecoration: 'none',\n }}\n >\n {match[1]}\n </a>\n );\n }\n } else if (part.startsWith('§SRCREF§') && sources) {\n /** @Todo vibecode - 소스 참조 상위첨자 렌더링 */\n const num = parseInt(part.replace('§SRCREF§', '').replace('§/SRCREF§', ''));\n const source = sources[num - 1];\n if (source) {\n elements.push(\n <a\n key={`${key}-srcref-${index}`}\n href={source.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n title={source.title}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '18px',\n height: '18px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-primary-light, #dbeafe)',\n color: 'var(--chatllm-primary, #3b82f6)',\n fontSize: '11px',\n fontWeight: 600,\n textDecoration: 'none',\n verticalAlign: 'super',\n marginLeft: '1px',\n marginRight: '1px',\n lineHeight: 1,\n }}\n >\n {num}\n </a>\n );\n }\n } else if (part) {\n elements.push(part);\n }\n });\n\n return elements;\n};\n\n/**\n * 테이블 셀 정렬 파싱\n */\ntype CellAlignment = 'left' | 'center' | 'right';\n\nconst parseTableAlignment = (separatorRow: string): CellAlignment[] => {\n const cells = separatorRow.split('|').filter((cell) => cell.trim() !== '');\n return cells.map((cell) => {\n const trimmed = cell.trim();\n const hasLeftColon = trimmed.startsWith(':');\n const hasRightColon = trimmed.endsWith(':');\n if (hasLeftColon && hasRightColon) return 'center';\n if (hasRightColon) return 'right';\n return 'left';\n });\n};\n\n/**\n * 테이블 행 파싱\n */\nconst parseTableRow = (row: string): string[] => {\n return row\n .split('|')\n .slice(1, -1) // Remove first and last empty strings from split\n .map((cell) => cell.trim());\n};\n\ninterface TableData {\n headers: string[];\n alignments: CellAlignment[];\n rows: string[][];\n}\n\n/**\n * @description 테이블 렌더링 컴포넌트\n * @Todo vibecode - 호버 시 복사 버튼 표시, 탭 구분 텍스트로 복사 (스프레드시트 호환)\n */\nconst MarkdownTable: React.FC<{ data: TableData }> = ({ data }) => {\n const [copied, setCopied] = React.useState(false);\n const [isHovered, setIsHovered] = React.useState(false);\n\n /** @Todo vibecode - 테이블 데이터를 탭 구분 텍스트로 변환 (스프레드시트 붙여넣기 호환) */\n const handleCopy = async () => {\n const headerLine = data.headers.join('\\t');\n const bodyLines = data.rows.map((row) => row.join('\\t'));\n const text = [headerLine, ...bodyLines].join('\\n');\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n console.error('Failed to copy table');\n }\n };\n\n return (\n <div\n style={{ position: 'relative', margin: '12px 0' }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n <table\n className=\"chatllm-table\"\n style={{\n width: '100%',\n borderCollapse: 'collapse',\n fontSize: '14px',\n }}\n >\n <thead>\n <tr>\n {data.headers.map((header, i) => (\n <th\n key={i}\n style={{\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n padding: '10px 12px',\n textAlign: data.alignments[i] || 'left',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n fontWeight: 600,\n color: 'var(--chatllm-text, #374151)',\n }}\n >\n {parseInlineElements(header, `th-${i}`)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.rows.map((row, rowIndex) => (\n <tr key={rowIndex}>\n {row.map((cell, cellIndex) => (\n <td\n key={cellIndex}\n style={{\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n padding: '10px 12px',\n textAlign: data.alignments[cellIndex] || 'left',\n color: 'var(--chatllm-text, #374151)',\n }}\n >\n {parseInlineElements(cell, `td-${rowIndex}-${cellIndex}`)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n {/* 복사 버튼 */}\n <button\n onClick={handleCopy}\n style={{\n position: 'absolute',\n top: '4px',\n right: '4px',\n padding: '4px 8px',\n fontSize: '12px',\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '6px',\n cursor: 'pointer',\n color: copied ? 'var(--chatllm-success, #22c55e)' : 'var(--chatllm-text-muted, #9ca3af)',\n opacity: isHovered || copied ? 1 : 0,\n transition: 'opacity 0.15s',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n boxShadow: '0 1px 3px rgba(0,0,0,0.08)',\n }}\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n {copied ? (\n <polyline points=\"20 6 9 17 4 12\" />\n ) : (\n <>\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </>\n )}\n </svg>\n {copied ? '복사됨' : '복사'}\n </button>\n </div>\n );\n};\n\n/**\n * @description 스피너 컴포넌트\n * @Todo vibecode - Thinking 블록 스트리밍 중 표시\n */\nconst ThinkingSpinner: React.FC = () => (\n <span\n className=\"chatllm-thinking-spinner\"\n style={{\n display: 'inline-block',\n width: '12px',\n height: '12px',\n border: '2px solid var(--chatllm-border, #e5e7eb)',\n borderTopColor: 'var(--chatllm-primary, #3b82f6)',\n borderRadius: '50%',\n animation: 'chatllm-spin 0.8s linear infinite',\n }}\n />\n);\n\n/**\n * @description Thinking 블록 렌더링\n * @Todo vibecode - AI 추론 과정을 접기/펼치기 UI로 표시\n * @Todo vibecode - isStreaming: 스트리밍 중일 때 스피너 표시\n */\nconst ThinkingBlock: React.FC<{\n content: string;\n defaultOpen?: boolean;\n}> = ({ content, defaultOpen = false }) => {\n const [isOpen, setIsOpen] = React.useState(defaultOpen);\n\n /**\n * @description 스트리밍 중 여부 판단\n * @Todo vibecode - 내용이 '...'로 끝나면 스트리밍 중\n */\n const isStreaming = content.trim().endsWith('...');\n\n return (\n <details\n open={isOpen}\n className=\"chatllm-thinking\"\n style={{\n margin: '8px 0',\n borderRadius: '6px',\n border: '1px dashed var(--chatllm-border, #e5e7eb)',\n background: 'transparent',\n overflow: 'hidden',\n }}\n >\n <summary\n onClick={(e) => {\n e.preventDefault();\n setIsOpen(!isOpen);\n }}\n style={{\n padding: '6px 10px',\n cursor: 'pointer',\n fontSize: '11px',\n color: 'var(--chatllm-text-tertiary, #9ca3af)',\n userSelect: 'none',\n listStyle: 'none',\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n }}\n >\n {isStreaming ? (\n <ThinkingSpinner />\n ) : (\n <span style={{ fontSize: '11px', opacity: 0.7 }}>💭</span>\n )}\n <span>{isStreaming ? '추론 중...' : isOpen ? '추론 과정' : '추론 과정 보기'}</span>\n <span\n style={{\n marginLeft: 'auto',\n fontSize: '8px',\n opacity: 0.6,\n transition: 'transform 0.2s',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n }}\n >\n ▼\n </span>\n </summary>\n {isOpen && (\n <div\n className=\"chatllm-thinking-content\"\n style={{\n padding: '8px 10px',\n borderTop: '1px dashed var(--chatllm-border, #e5e7eb)',\n fontSize: '12px',\n color: 'var(--chatllm-text-secondary, #6b7280)',\n whiteSpace: 'pre-wrap',\n lineHeight: '1.6',\n background: 'var(--chatllm-bg-secondary, #f9fafb)',\n maxHeight: '400px',\n overflowY: 'auto',\n }}\n >\n {isStreaming ? content.trim().slice(0, -3) : content.trim()}\n </div>\n )}\n </details>\n );\n};\n\n/**\n * 코드 블록 렌더링\n */\nconst CodeBlock: React.FC<{ language?: string; code: string }> = ({ language, code }) => {\n const [copied, setCopied] = React.useState(false);\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch (e) {\n console.error('Failed to copy');\n }\n };\n\n return (\n <div\n style={{\n position: 'relative',\n margin: '12px 0',\n borderRadius: '8px',\n overflow: 'hidden',\n backgroundColor: 'var(--chatllm-code-block-bg, #1f2937)',\n }}\n >\n {/* Header */}\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: '8px 12px',\n backgroundColor: 'var(--chatllm-code-block-header, #374151)',\n borderBottom: '1px solid var(--chatllm-code-block-border, #4b5563)',\n }}\n >\n <span\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-code-block-lang, #9ca3af)',\n textTransform: 'lowercase',\n }}\n >\n {language || 'code'}\n </span>\n <button\n onClick={handleCopy}\n style={{\n padding: '4px 8px',\n fontSize: '12px',\n backgroundColor: 'transparent',\n border: '1px solid var(--chatllm-code-block-border, #4b5563)',\n borderRadius: '4px',\n color: 'var(--chatllm-code-block-text, #e5e7eb)',\n cursor: 'pointer',\n }}\n >\n {copied ? '복사됨!' : '복사'}\n </button>\n </div>\n {/* Code */}\n <pre\n style={{\n margin: 0,\n padding: '16px',\n overflow: 'auto',\n fontSize: '13px',\n lineHeight: '1.6',\n fontFamily: 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace',\n color: 'var(--chatllm-code-block-text, #e5e7eb)',\n }}\n >\n <code>{code.trim()}</code>\n </pre>\n </div>\n );\n};\n\n/**\n * 이미지 복사 버튼이 있는 이미지 컴포넌트\n */\nconst ImageWithCopyButton: React.FC<{\n src: string;\n alt: string;\n imageKey: string;\n}> = ({ src, alt, imageKey }) => {\n const [isHovered, setIsHovered] = React.useState(false);\n const [copyState, setCopyState] = React.useState<'idle' | 'copying' | 'copied' | 'error'>('idle');\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // 이미지를 Blob으로 가져오는 공통 함수\n const getImageBlob = async (): Promise<Blob | null> => {\n // Method 1: Canvas (same-origin or data URLs)\n const img = imgRef.current;\n if (img && img.complete && img.naturalWidth > 0) {\n try {\n const canvas = document.createElement('canvas');\n canvas.width = img.naturalWidth;\n canvas.height = img.naturalHeight;\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.drawImage(img, 0, 0);\n const blob = await new Promise<Blob | null>((resolve) => {\n canvas.toBlob(resolve, 'image/png');\n });\n if (blob) return blob;\n }\n } catch {\n console.log('Canvas method failed (CORS), trying fetch...');\n }\n }\n\n // Method 2: Fetch (CORS-enabled images)\n if (!src.startsWith('data:')) {\n try {\n const response = await fetch(src, { mode: 'cors' });\n if (response.ok) {\n const blob = await response.blob();\n if (blob.type === 'image/png') return blob;\n\n // Convert to PNG\n const tempImg = new Image();\n const blobUrl = URL.createObjectURL(blob);\n return new Promise<Blob | null>((resolve) => {\n tempImg.onload = () => {\n const canvas = document.createElement('canvas');\n canvas.width = tempImg.naturalWidth;\n canvas.height = tempImg.naturalHeight;\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.drawImage(tempImg, 0, 0);\n canvas.toBlob((pngBlob) => {\n URL.revokeObjectURL(blobUrl);\n resolve(pngBlob);\n }, 'image/png');\n } else {\n URL.revokeObjectURL(blobUrl);\n resolve(null);\n }\n };\n tempImg.onerror = () => {\n URL.revokeObjectURL(blobUrl);\n resolve(null);\n };\n tempImg.src = blobUrl;\n });\n }\n } catch {\n console.log('Fetch method failed');\n }\n }\n return null;\n };\n\n // 복사 핸들러\n const handleCopy = async () => {\n setCopyState('copying');\n try {\n if (!navigator.clipboard?.write) {\n await navigator.clipboard.writeText(src);\n setCopyState('copied');\n setTimeout(() => setCopyState('idle'), 2000);\n return;\n }\n\n const blob = await getImageBlob();\n if (blob) {\n await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })]);\n setCopyState('copied');\n } else {\n await navigator.clipboard.writeText(src);\n setCopyState('copied');\n }\n setTimeout(() => setCopyState('idle'), 2000);\n } catch (error) {\n console.error('Failed to copy image:', error);\n setCopyState('error');\n setTimeout(() => setCopyState('idle'), 2000);\n }\n };\n\n // 다운로드 핸들러\n const handleDownload = async () => {\n try {\n const blob = await getImageBlob();\n const url = blob ? URL.createObjectURL(blob) : src;\n const link = document.createElement('a');\n link.href = url;\n link.download = alt || `image-${Date.now()}.png`;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n if (blob) URL.revokeObjectURL(url);\n } catch (error) {\n console.error('Failed to download image:', error);\n // Fallback: open in new tab\n window.open(src, '_blank');\n }\n };\n\n return (\n <div\n key={imageKey}\n style={{\n position: 'relative',\n display: 'inline-block',\n margin: '8px 0',\n }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n <img\n ref={imgRef}\n src={src}\n alt={alt}\n className=\"chatllm-image\"\n crossOrigin={src.startsWith('data:') ? undefined : 'anonymous'}\n style={{\n maxWidth: '100%',\n borderRadius: '8px',\n display: 'block',\n }}\n loading=\"lazy\"\n />\n {/* Bottom toolbar overlay - dark transparent style */}\n <div\n style={{\n position: 'absolute',\n bottom: '12px',\n left: '12px',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 16px',\n backgroundColor: 'rgba(0, 0, 0, 0.6)',\n backdropFilter: 'blur(12px)',\n borderRadius: '24px',\n opacity: isHovered ? 1 : 0,\n transition: 'opacity 0.2s ease',\n pointerEvents: isHovered ? 'auto' : 'none',\n }}\n >\n {/* Copy button */}\n <button\n onClick={handleCopy}\n disabled={copyState === 'copying'}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '32px',\n height: '32px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '50%',\n cursor: 'pointer',\n color: copyState === 'copied' ? '#22c55e' : copyState === 'error' ? '#ef4444' : 'rgba(255, 255, 255, 0.9)',\n transition: 'background-color 0.2s, color 0.2s',\n }}\n title={copyState === 'copied' ? '복사됨!' : copyState === 'error' ? '복사 실패' : '복사하기'}\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.15)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n {copyState === 'copied' ? (\n <polyline points=\"20 6 9 17 4 12\" />\n ) : (\n <>\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </>\n )}\n </svg>\n </button>\n\n {/* Download button */}\n <button\n onClick={handleDownload}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '32px',\n height: '32px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '50%',\n cursor: 'pointer',\n color: 'rgba(255, 255, 255, 0.9)',\n transition: 'background-color 0.2s, color 0.2s',\n }}\n title=\"저장하기\"\n onMouseOver={(e) => {\n e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.15)';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n </div>\n </div>\n );\n};\n\n/**\n * 선택지 버튼 렌더링 컴포넌트\n */\nconst ChoiceButtons: React.FC<{\n choices: ChoiceOption[];\n title?: string;\n onChoiceClick?: (choice: ChoiceOption) => void;\n}> = ({ choices, title, onChoiceClick }) => {\n const [hoveredIndex, setHoveredIndex] = React.useState<number | null>(null);\n\n return (\n <div\n className=\"chatllm-choices\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n margin: '16px 0',\n padding: '12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '12px',\n border: '1px solid var(--chatllm-border-light, #e5e7eb)',\n }}\n >\n <div\n style={{\n fontSize: title ? '14px' : '12px',\n fontWeight: 600,\n color: title ? 'var(--chatllm-text, #374151)' : 'var(--chatllm-text-muted, #6b7280)',\n marginBottom: '4px',\n textTransform: title ? 'none' : 'uppercase',\n letterSpacing: title ? 'normal' : '0.5px',\n }}\n >\n {title || '선택하세요'}\n </div>\n {choices.map((choice, index) => (\n <button\n key={choice.number}\n onClick={() => onChoiceClick?.(choice)}\n onMouseEnter={() => setHoveredIndex(index)}\n onMouseLeave={() => setHoveredIndex(null)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px 16px',\n backgroundColor: hoveredIndex === index\n ? 'var(--chatllm-primary-light, #dbeafe)'\n : 'var(--chatllm-bg, #ffffff)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'background-color 0.2s ease',\n }}\n >\n <span\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '28px',\n height: '28px',\n borderRadius: '50%',\n backgroundColor: hoveredIndex === index\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-bg-tertiary, #f3f4f6)',\n color: hoveredIndex === index\n ? '#ffffff'\n : 'var(--chatllm-text, #374151)',\n fontSize: '14px',\n fontWeight: 600,\n flexShrink: 0,\n transition: 'all 0.2s ease',\n }}\n >\n {choice.number}\n </span>\n <span\n style={{\n fontSize: '14px',\n color: 'var(--chatllm-text, #374151)',\n lineHeight: '1.5',\n }}\n >\n {choice.text}\n </span>\n </button>\n ))}\n </div>\n );\n};\n\n/**\n * 출처 링크 섹션 렌더링\n */\nconst SourceLinksSection: React.FC<{ links: ParsedLink[]; label?: string }> = ({ links, label }) => {\n return (\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: '8px',\n margin: '12px 0',\n padding: '12px',\n backgroundColor: 'var(--chatllm-source-bg, #f8fafc)',\n borderRadius: '8px',\n border: '1px solid var(--chatllm-border-light, #e2e8f0)',\n }}\n >\n {label && (\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-text-muted, #64748b)',\n marginRight: '4px',\n }}\n >\n {label}\n </span>\n )}\n {links.map((link, index) => (\n <LinkChip key={index} text={link.text} url={link.url} />\n ))}\n </div>\n );\n};\n\nexport const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({\n content,\n className,\n onChoiceClick,\n showThinking = true,\n thinkingDefaultOpen = false,\n sources,\n}) => {\n const rendered = useMemo(() => {\n const elements: React.ReactNode[] = [];\n let processedContent = content;\n\n /**\n * @description Thinking 블록 추출 및 치환\n * @Todo vibecode - 코드 블록 추출 전에 Thinking 먼저 처리\n */\n const thinkingBlocks: string[] = [];\n if (showThinking) {\n // 패턴 1: <thinking>...</thinking> 태그\n processedContent = processedContent.replace(THINKING_TAG_REGEX, (_, thinkContent) => {\n thinkingBlocks.push(thinkContent);\n return `§THINKING§${thinkingBlocks.length - 1}§/THINKING§`;\n });\n // 패턴 2: ```thinking 코드블록\n processedContent = processedContent.replace(THINKING_CODEBLOCK_REGEX, (_, thinkContent) => {\n thinkingBlocks.push(thinkContent);\n return `§THINKING§${thinkingBlocks.length - 1}§/THINKING§`;\n });\n // 패턴 3: \"Thinking:\" 텍스트 패턴\n processedContent = processedContent.replace(THINKING_TEXT_REGEX, (_, thinkContent) => {\n thinkingBlocks.push(thinkContent);\n return `§THINKING§${thinkingBlocks.length - 1}§/THINKING§`;\n });\n } else {\n // showThinking=false일 때는 Thinking 블록 완전히 제거\n processedContent = processedContent.replace(THINKING_TAG_REGEX, '');\n processedContent = processedContent.replace(THINKING_CODEBLOCK_REGEX, '');\n processedContent = processedContent.replace(THINKING_TEXT_REGEX, '');\n }\n\n /**\n * @description 닫히지 않은 <thinking> 태그 처리 (스트리밍 중)\n * @Todo vibecode - 스트리밍 중인 thinking 내용도 ThinkingBlock으로 표시\n */\n if (showThinking) {\n // 스트리밍 중인 thinking 내용을 ThinkingBlock으로 표시\n const unclosedMatch = processedContent.match(/<thinking>([\\s\\S]*)$/i);\n if (unclosedMatch) {\n const streamingThinkContent = unclosedMatch[1];\n thinkingBlocks.push(streamingThinkContent + '...');\n processedContent = processedContent.replace(/<thinking>[\\s\\S]*$/i, `§THINKING§${thinkingBlocks.length - 1}§/THINKING§`);\n }\n } else {\n processedContent = processedContent.replace(UNCLOSED_THINKING_TAG_REGEX, '');\n }\n\n /**\n * @description 완성된 <poll> 태그 제거 (PollCard가 별도 렌더링)\n * @Todo vibecode - 완성/미완성 모두 MarkdownRenderer에서 숨김\n */\n processedContent = processedContent.replace(/<poll[^>]*>[\\s\\S]*?<\\/poll>/gi, '');\n /** @Todo vibecode - 미완성 poll 태그 감지 시 로딩 플레이스홀더 삽입 */\n const hasUnfinishedPoll = UNCLOSED_POLL_TAG_REGEX.test(processedContent);\n UNCLOSED_POLL_TAG_REGEX.lastIndex = 0;\n processedContent = processedContent.replace(UNCLOSED_POLL_TAG_REGEX, '');\n if (hasUnfinishedPoll) {\n processedContent += '\\n§POLL_LOADING§';\n }\n\n /**\n * @description 불완전한 <skill_use> 태그 제거 (스트리밍 중)\n * @Todo vibecode - </skill_use> 없이 끝나는 skill_use 태그 전체 제거\n */\n processedContent = processedContent.replace(UNCLOSED_SKILL_TAG_REGEX, '');\n\n // 1. 코드 블록 추출 및 치환\n const codeBlocks: { language: string; code: string }[] = [];\n processedContent = processedContent.replace(CODE_BLOCK_REGEX, (match, lang, code) => {\n /**\n * @description markdown/md 코드블록 내 테이블 감지 및 변환\n * @Todo vibecode - 파이프, 탭, 공백 구분 테이블 모두 표준 마크다운 테이블로 처리\n */\n if (lang === 'markdown' || lang === 'md') {\n const trimmedCode = code.trim();\n\n // Case 1: 표준 파이프 구분 테이블 → 원문 유지\n if (TABLE_ROW_REGEX.test(trimmedCode.split('\\n')[0])) {\n return '\\n' + trimmedCode + '\\n';\n }\n\n // Case 2: 비표준 테이블(탭/공백) → 파이프 테이블로 변환\n const converted = convertNonStandardTable(trimmedCode);\n if (converted) {\n return '\\n' + converted + '\\n';\n }\n }\n codeBlocks.push({ language: lang || '', code });\n return `§CODEBLOCK§${codeBlocks.length - 1}§/CODEBLOCK§`;\n });\n\n // 2. 출처 링크 섹션 추출 및 치환\n const sourceSections: { label: string; links: ParsedLink[] }[] = [];\n processedContent = processedContent.replace(SOURCE_LINKS_REGEX, (match, label, linksText) => {\n const links = parseSourceLinks(linksText);\n if (links.length > 0) {\n sourceSections.push({ label: label?.replace(/\\*+/g, '').trim() || '출처', links });\n return `§SOURCES§${sourceSections.length - 1}§/SOURCES§`;\n }\n return match;\n });\n\n // 3. 줄 단위로 파싱\n const lines = processedContent.split('\\n');\n let currentList: { type: 'ul' | 'ol'; items: React.ReactNode[] } | null = null;\n let blockquoteLines: string[] = [];\n let tableLines: string[] = [];\n // 선택지 수집용\n let choiceItems: ChoiceOption[] = [];\n\n const flushTable = () => {\n if (tableLines.length >= 2) {\n // Need at least header + separator\n const headerLine = tableLines[0];\n const separatorLine = tableLines[1];\n const dataLines = tableLines.slice(2);\n\n if (TABLE_SEPARATOR_REGEX.test(separatorLine)) {\n const headers = parseTableRow(headerLine);\n const alignments = parseTableAlignment(separatorLine);\n const rows = dataLines.map((line) => parseTableRow(line));\n\n elements.push(\n <MarkdownTable\n key={`table-${elements.length}`}\n data={{ headers, alignments, rows }}\n />\n );\n } else {\n // Not a valid table, render as regular lines\n tableLines.forEach((line, i) => {\n elements.push(\n <p key={`p-table-fallback-${elements.length}-${i}`} style={{ margin: '4px 0' }}>\n {parseInlineElements(line, `p-table-fallback-${i}`, sources)}\n </p>\n );\n });\n }\n }\n tableLines = [];\n };\n\n const flushChoices = () => {\n if (choiceItems.length >= 2 && onChoiceClick) {\n // 선택지가 2개 이상이고 콜백이 있으면 버튼으로 렌더링\n elements.push(\n <ChoiceButtons\n key={`choices-${elements.length}`}\n choices={choiceItems}\n onChoiceClick={onChoiceClick}\n />\n );\n choiceItems = [];\n return true;\n }\n choiceItems = [];\n return false;\n };\n\n const flushList = () => {\n if (currentList) {\n if (currentList.type === 'ul') {\n elements.push(\n <ul key={`ul-${elements.length}`} style={{ margin: '8px 0', paddingLeft: '24px' }}>\n {currentList.items}\n </ul>\n );\n } else {\n // 순서 리스트: 선택지로 변환 시도\n if (!flushChoices()) {\n // 선택지로 변환되지 않으면 일반 리스트로 렌더링\n elements.push(\n <ol key={`ol-${elements.length}`} style={{ margin: '8px 0', paddingLeft: '24px' }}>\n {currentList.items}\n </ol>\n );\n }\n }\n currentList = null;\n }\n };\n\n const flushBlockquote = () => {\n if (blockquoteLines.length > 0) {\n elements.push(\n <blockquote\n key={`bq-${elements.length}`}\n style={{\n margin: '12px 0',\n padding: '12px 16px',\n borderLeft: '4px solid var(--chatllm-primary, #3b82f6)',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '0 8px 8px 0',\n color: 'var(--chatllm-text, #374151)',\n }}\n >\n {blockquoteLines.map((line, i) => (\n <React.Fragment key={i}>\n {parseInlineElements(line, `bq-line-${i}`, sources)}\n {i < blockquoteLines.length - 1 && <br />}\n </React.Fragment>\n ))}\n </blockquote>\n );\n blockquoteLines = [];\n }\n };\n\n lines.forEach((line, lineIndex) => {\n /**\n * @description Thinking 블록 마커 처리\n * @Todo vibecode - ThinkingBlock 컴포넌트로 렌더링\n */\n const thinkingMatch = line.match(/§THINKING§(\\d+)§\\/THINKING§/);\n if (thinkingMatch) {\n flushList();\n flushBlockquote();\n const index = parseInt(thinkingMatch[1]);\n elements.push(\n <ThinkingBlock\n key={`thinking-${lineIndex}`}\n content={thinkingBlocks[index]}\n defaultOpen={thinkingDefaultOpen}\n />\n );\n return;\n }\n\n /** @Todo vibecode - Poll 로딩 플레이스홀더 처리 (스트리밍 중 선택지 준비 표시) */\n if (line.trim() === '§POLL_LOADING§') {\n flushList();\n flushBlockquote();\n elements.push(\n <div\n key={`poll-loading-${lineIndex}`}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '14px 16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '10px',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n marginTop: '12px',\n animation: 'chatllm-pulse 1.5s ease-in-out infinite',\n }}\n >\n <div\n style={{\n width: '18px',\n height: '18px',\n borderRadius: '50%',\n border: '2px solid var(--chatllm-primary, #4A90E2)',\n borderTopColor: 'transparent',\n animation: 'chatllm-spin 0.8s linear infinite',\n }}\n />\n <span style={{ fontSize: '13px', color: 'var(--chatllm-text-muted, #64748b)' }}>\n 선택지를 준비하고 있어요...\n </span>\n </div>\n );\n return;\n }\n\n // 코드 블록 마커 처리\n const codeBlockMatch = line.match(/§CODEBLOCK§(\\d+)§\\/CODEBLOCK§/);\n if (codeBlockMatch) {\n flushList();\n flushBlockquote();\n const index = parseInt(codeBlockMatch[1]);\n elements.push(\n <CodeBlock key={`codeblock-${lineIndex}`} {...codeBlocks[index]} />\n );\n return;\n }\n\n // 출처 링크 마커 처리\n const sourcesMatch = line.match(/§SOURCES§(\\d+)§\\/SOURCES§/);\n if (sourcesMatch) {\n flushList();\n flushBlockquote();\n const index = parseInt(sourcesMatch[1]);\n elements.push(\n <SourceLinksSection key={`sources-${lineIndex}`} {...sourceSections[index]} />\n );\n return;\n }\n\n // 테이블 행 감지\n if (TABLE_ROW_REGEX.test(line)) {\n flushList();\n flushBlockquote();\n tableLines.push(line);\n return;\n } else if (tableLines.length > 0) {\n // 테이블이 끝났음\n flushTable();\n }\n\n // 수평선\n if (HR_REGEX.test(line)) {\n flushList();\n flushBlockquote();\n elements.push(\n <hr\n key={`hr-${lineIndex}`}\n style={{\n margin: '16px 0',\n border: 'none',\n borderTop: '1px solid var(--chatllm-border, #e5e7eb)',\n }}\n />\n );\n return;\n }\n\n // 헤딩\n const headingMatch = line.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n flushList();\n flushBlockquote();\n const level = headingMatch[1].length;\n const text = headingMatch[2];\n const HeadingTag = `h${level}` as keyof JSX.IntrinsicElements;\n const sizes: Record<number, string> = {\n 1: '1.5em',\n 2: '1.3em',\n 3: '1.15em',\n 4: '1.05em',\n 5: '1em',\n 6: '0.95em',\n };\n elements.push(\n <HeadingTag\n key={`heading-${lineIndex}`}\n style={{\n fontSize: sizes[level],\n fontWeight: level <= 2 ? 600 : 500,\n margin: '16px 0 8px',\n color: 'var(--chatllm-text, #1f2937)',\n }}\n >\n {parseInlineElements(text, `heading-${lineIndex}`, sources)}\n </HeadingTag>\n );\n return;\n }\n\n // 인용문\n const blockquoteMatch = line.match(/^>\\s*(.*)$/);\n if (blockquoteMatch) {\n flushList();\n blockquoteLines.push(blockquoteMatch[1]);\n return;\n } else {\n flushBlockquote();\n }\n\n // 비순서 리스트\n const ulMatch = line.match(/^[\\-\\*]\\s+(.+)$/);\n if (ulMatch) {\n flushBlockquote();\n if (!currentList || currentList.type !== 'ul') {\n flushList();\n currentList = { type: 'ul', items: [] };\n }\n currentList.items.push(\n <li key={`li-${lineIndex}`} style={{ margin: '4px 0' }}>\n {parseInlineElements(ulMatch[1], `li-${lineIndex}`, sources)}\n </li>\n );\n return;\n }\n\n // 순서 리스트 (선택지 후보 수집 포함)\n const olMatch = line.match(/^(\\d+)[.)]\\s+(.+)$/);\n if (olMatch) {\n flushBlockquote();\n if (!currentList || currentList.type !== 'ol') {\n flushList();\n currentList = { type: 'ol', items: [] };\n }\n\n const itemNumber = parseInt(olMatch[1]);\n const itemText = olMatch[2];\n\n // 선택지 후보로도 수집 (짧은 텍스트만, 100자 이하)\n if (itemText.length <= 100) {\n choiceItems.push({\n number: itemNumber,\n text: itemText,\n fullText: line,\n });\n }\n\n currentList.items.push(\n <li key={`li-${lineIndex}`} style={{ margin: '4px 0' }}>\n {parseInlineElements(itemText, `li-${lineIndex}`, sources)}\n </li>\n );\n return;\n }\n\n // 리스트 종료\n flushList();\n\n // 빈 줄\n if (!line.trim()) {\n elements.push(<br key={`br-${lineIndex}`} />);\n return;\n }\n\n // 인라인 선택지 체크 ([1] 텍스트 [2] 텍스트 형식)\n if (onChoiceClick) {\n const choiceBlock = parseInlineChoices(line);\n if (choiceBlock) {\n elements.push(\n <ChoiceButtons\n key={`inline-choices-${lineIndex}`}\n choices={choiceBlock.choices}\n title={choiceBlock.title}\n onChoiceClick={onChoiceClick}\n />\n );\n return;\n }\n }\n\n /**\n * @description 일반 텍스트 렌더링\n * @Todo vibecode - 이미지 포함 시 <div> 사용 (HTML 규칙: <p> 안에 <div> 불가)\n */\n const hasImage = IMAGE_REGEX.test(line);\n // 이미지가 있으면 div 사용, 없으면 p 사용\n if (hasImage) {\n elements.push(\n <div key={`p-${lineIndex}`} style={{ margin: '4px 0' }}>\n {parseInlineElements(line, `p-${lineIndex}`, sources)}\n </div>\n );\n } else {\n elements.push(\n <p key={`p-${lineIndex}`} style={{ margin: '4px 0' }}>\n {parseInlineElements(line, `p-${lineIndex}`, sources)}\n </p>\n );\n }\n });\n\n // 남은 리스트/인용문/테이블 처리\n flushList();\n flushBlockquote();\n flushTable();\n\n return elements;\n }, [content, onChoiceClick, sources]);\n\n return (\n <div\n className={`chatllm-markdown ${className || ''}`}\n style={{\n fontSize: '15px',\n lineHeight: '1.7',\n color: 'var(--chatllm-text, #374151)',\n }}\n >\n {rendered}\n </div>\n );\n};\n\nexport default MarkdownRenderer;\n","/**\n * @description 링크 칩 컴포넌트\n * 출처 링크를 칩 형태로 표시\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\n\nexport interface LinkChipProps {\n /** 링크 텍스트 */\n text: string;\n /** 링크 URL */\n url: string;\n /** 파비콘 표시 여부 */\n showFavicon?: boolean;\n /** 번호 표시 */\n index?: number;\n /** 커스텀 스타일 */\n style?: React.CSSProperties;\n}\n\n/**\n * URL에서 도메인 추출\n */\nconst getDomain = (url: string): string => {\n try {\n const urlObj = new URL(url);\n return urlObj.hostname.replace('www.', '');\n } catch {\n return url;\n }\n};\n\n/**\n * 도메인에서 짧은 이름 추출\n */\nconst getShortName = (domain: string): string => {\n const parts = domain.split('.');\n if (parts.length >= 2) {\n return parts[parts.length - 2];\n }\n return domain;\n};\n\n/**\n * 도메인별 색상 매핑\n */\nconst getDomainColor = (domain: string): string => {\n const lowerDomain = domain.toLowerCase();\n\n // 주요 사이트 색상\n const colorMap: Record<string, string> = {\n 'google': '#4285f4',\n 'wikipedia': '#000000',\n 'github': '#24292e',\n 'stackoverflow': '#f48024',\n 'medium': '#00ab6c',\n 'youtube': '#ff0000',\n 'twitter': '#1da1f2',\n 'naver': '#03c75a',\n 'namu': '#00a495',\n 'tistory': '#eb531f',\n 'velog': '#20c997',\n 'brave': '#fb542b',\n 'mk': '#0066cc',\n 'ko': '#3366cc',\n };\n\n for (const [key, color] of Object.entries(colorMap)) {\n if (lowerDomain.includes(key)) {\n return color;\n }\n }\n\n // 기본 색상 (해시 기반)\n let hash = 0;\n for (let i = 0; i < domain.length; i++) {\n hash = domain.charCodeAt(i) + ((hash << 5) - hash);\n }\n const hue = hash % 360;\n return `hsl(${hue}, 60%, 45%)`;\n};\n\nexport const LinkChip: React.FC<LinkChipProps> = ({\n text,\n url,\n showFavicon = true,\n index,\n style,\n}) => {\n const [isHovered, setIsHovered] = useState(false);\n const domain = getDomain(url);\n const shortName = getShortName(domain);\n const domainColor = getDomainColor(domain);\n\n // 텍스트에서 번호 추출 (예: \"1. brave\" -> { number: 1, label: \"brave\" })\n const parseText = (t: string): { number?: string; label: string } => {\n const match = t.match(/^(\\d+)\\.\\s*(.+)$/);\n if (match) {\n return { number: match[1], label: match[2] };\n }\n return { label: t };\n };\n\n const parsed = parseText(text);\n const displayNumber = index !== undefined ? String(index + 1) : parsed.number;\n const displayLabel = parsed.label;\n\n return (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '6px',\n padding: '4px 10px',\n backgroundColor: isHovered\n ? 'var(--chatllm-chip-bg-hover, #e2e8f0)'\n : 'var(--chatllm-chip-bg, #f1f5f9)',\n border: '1px solid var(--chatllm-chip-border, #e2e8f0)',\n borderRadius: '16px',\n textDecoration: 'none',\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-chip-text, #475569)',\n transition: 'all 0.15s ease',\n cursor: 'pointer',\n maxWidth: '180px',\n ...style,\n }}\n title={`${displayLabel} - ${domain}`}\n >\n {/* 번호 배지 */}\n {displayNumber && (\n <span\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '18px',\n height: '18px',\n borderRadius: '50%',\n backgroundColor: domainColor,\n color: '#ffffff',\n fontSize: '11px',\n fontWeight: 600,\n flexShrink: 0,\n }}\n >\n {displayNumber}\n </span>\n )}\n\n {/* 파비콘 또는 링크 아이콘 */}\n {showFavicon && !displayNumber && (\n <span\n style={{\n width: '16px',\n height: '16px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n >\n <IconSvg\n name=\"links-line\"\n size={14}\n color={domainColor}\n />\n </span>\n )}\n\n {/* 텍스트 */}\n <span\n style={{\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {displayLabel}\n </span>\n\n {/* 외부 링크 아이콘 */}\n <IconSvg\n name=\"external-link-line\"\n size={12}\n color=\"var(--chatllm-text-muted, #94a3b8)\"\n style={{\n opacity: isHovered ? 1 : 0.6,\n flexShrink: 0,\n }}\n />\n </a>\n );\n};\n\nexport default LinkChip;\n","/**\n * @description 심층연구 진행 상태 UI 컴포넌트\n * @Todo vibecode - 심층연구 4단계 진행 상태 표시\n */\n\nimport React from 'react';\nimport { IconSvg } from './Icon';\nimport type { DeepResearchProgress, SubAgentProgress } from '../types';\n\nexport interface DeepResearchProgressUIProps {\n progress: DeepResearchProgress;\n}\n\n/**\n * @description 상태별 아이콘 컴포넌트\n */\nconst StatusIcon: React.FC<{ status: SubAgentProgress['status'] }> = ({ status }) => {\n switch (status) {\n case 'pending':\n return (\n <div\n style={{\n width: 16,\n height: 16,\n borderRadius: '50%',\n border: '2px solid var(--chatllm-border)',\n backgroundColor: 'transparent',\n }}\n />\n );\n case 'searching':\n case 'extracting':\n return (\n <div\n style={{\n width: 16,\n height: 16,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <div\n style={{\n width: 12,\n height: 12,\n borderRadius: '50%',\n border: '2px solid var(--chatllm-primary)',\n borderTopColor: 'transparent',\n animation: 'chatllm-spin 1s linear infinite',\n }}\n />\n </div>\n );\n case 'done':\n return <IconSvg name=\"check-line\" size={16} color=\"var(--chatllm-success, #10b981)\" />;\n case 'error':\n return <IconSvg name=\"close-line\" size={16} color=\"var(--chatllm-error, #ef4444)\" />;\n default:\n return null;\n }\n};\n\n/**\n * @description 단계별 진행 표시 바\n */\nconst PhaseProgress: React.FC<{ phase: DeepResearchProgress['phase'] }> = ({ phase }) => {\n const phases = ['analyzing', 'researching', 'evaluating', 'generating', 'done'] as const;\n const currentIndex = phases.indexOf(phase);\n\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginBottom: '16px',\n }}\n >\n {phases.slice(0, 4).map((p, index) => (\n <React.Fragment key={p}>\n <div\n style={{\n width: 24,\n height: 24,\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '12px',\n fontWeight: 600,\n backgroundColor:\n index < currentIndex\n ? 'var(--chatllm-primary)'\n : index === currentIndex\n ? 'var(--chatllm-primary-light)'\n : 'var(--chatllm-bg-secondary)',\n color:\n index < currentIndex\n ? '#fff'\n : index === currentIndex\n ? 'var(--chatllm-primary)'\n : 'var(--chatllm-text-muted)',\n border:\n index === currentIndex\n ? '2px solid var(--chatllm-primary)'\n : '2px solid transparent',\n }}\n >\n {index < currentIndex ? (\n <IconSvg name=\"check-line\" size={14} color=\"#fff\" />\n ) : (\n index + 1\n )}\n </div>\n {index < 3 && (\n <div\n style={{\n flex: 1,\n height: 2,\n backgroundColor:\n index < currentIndex\n ? 'var(--chatllm-primary)'\n : 'var(--chatllm-border)',\n }}\n />\n )}\n </React.Fragment>\n ))}\n </div>\n );\n};\n\n/**\n * @description 심층연구 진행 상태 UI\n */\nexport const DeepResearchProgressUI: React.FC<DeepResearchProgressUIProps> = ({ progress }) => {\n return (\n <div\n className=\"chatllm-research-progress\"\n style={{\n padding: '20px',\n backgroundColor: 'var(--chatllm-bg-secondary)',\n borderRadius: '16px',\n border: '1px solid var(--chatllm-border)',\n }}\n >\n {/* 헤더 */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n marginBottom: '16px',\n }}\n >\n <IconSvg name=\"search-eye-line\" size={20} color=\"var(--chatllm-primary)\" />\n <span\n style={{\n fontSize: '15px',\n fontWeight: 600,\n color: 'var(--chatllm-text)',\n }}\n >\n 심층연구\n </span>\n </div>\n\n {/* 단계 진행 표시 */}\n <PhaseProgress phase={progress.phase} />\n\n {/* 현재 단계 라벨 */}\n <div\n className=\"chatllm-research-progress__phase\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n marginBottom: '16px',\n }}\n >\n {progress.phase !== 'done' && (\n <div\n style={{\n width: 16,\n height: 16,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <div\n style={{\n width: 14,\n height: 14,\n borderRadius: '50%',\n border: '2px solid var(--chatllm-primary)',\n borderTopColor: 'transparent',\n animation: 'chatllm-spin 1s linear infinite',\n }}\n />\n </div>\n )}\n <span\n style={{\n fontSize: '14px',\n color: 'var(--chatllm-text-secondary)',\n }}\n >\n {progress.phaseLabel}\n </span>\n </div>\n\n {/* 서브에이전트 상태 (검색 단계일 때) */}\n {progress.phase === 'researching' && progress.subAgents.length > 0 && (\n <div\n className=\"chatllm-research-progress__agents\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: '10px',\n marginBottom: '16px',\n }}\n >\n {progress.subAgents.map((agent) => (\n <div\n key={agent.id}\n className=\"chatllm-research-progress__agent\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 14px',\n backgroundColor: 'var(--chatllm-bg)',\n borderRadius: '10px',\n border: '1px solid var(--chatllm-border)',\n }}\n >\n <StatusIcon status={agent.status} />\n <span\n style={{\n flex: 1,\n fontSize: '13px',\n color: 'var(--chatllm-text)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {agent.topic}\n </span>\n <span\n className=\"count\"\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted)',\n whiteSpace: 'nowrap',\n }}\n >\n {agent.resultsCount}개 수집\n </span>\n </div>\n ))}\n </div>\n )}\n\n {/* 전체 소스 카운트 */}\n <div\n className=\"chatllm-research-progress__total\"\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 14px',\n backgroundColor: 'var(--chatllm-primary-light)',\n borderRadius: '10px',\n }}\n >\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-primary)',\n }}\n >\n 총 {progress.totalSources}개 소스 수집\n </span>\n <IconSvg name=\"file-text-line\" size={16} color=\"var(--chatllm-primary)\" />\n </div>\n </div>\n );\n};\n\nexport default DeepResearchProgressUI;\n","/**\n * @description AI 주도 선택지 (Poll) 컴포넌트\n * @Todo vibecode - Claude Code 스타일 탭 UI (여러 질문 한 번에)\n */\n\nimport React, { useState, useCallback, useEffect } from 'react';\nimport { IconSvg } from './Icon';\nimport type { PollQuestion, PollResponse } from '../types';\n\n/**\n * @description 마크다운 인라인 서식을 React 엘리먼트로 렌더링\n * @Todo vibecode - **bold**, *italic*, `code`, ~~strikethrough~~ → styled span\n */\nconst renderInlineMarkdown = (text: string): React.ReactNode => {\n const parts: React.ReactNode[] = [];\n let remaining = text;\n let key = 0;\n\n while (remaining.length > 0) {\n /** @Todo vibecode - bold(**) → italic(*) → code(`) → strikethrough(~~) 순서 매칭 */\n const match = remaining.match(\n /(\\*\\*(.+?)\\*\\*|__(.+?)__|`(.+?)`|~~(.+?)~~|\\*(.+?)\\*|_(.+?)_)/\n );\n\n if (!match || match.index === undefined) {\n parts.push(remaining);\n break;\n }\n\n if (match.index > 0) {\n parts.push(remaining.slice(0, match.index));\n }\n\n const fullMatch = match[0];\n if (match[2] || match[3]) {\n parts.push(<strong key={key++}>{match[2] || match[3]}</strong>);\n } else if (match[4]) {\n parts.push(\n <code key={key++} style={{ backgroundColor: 'var(--chatllm-bg-tertiary, #f1f5f9)', padding: '1px 4px', borderRadius: '3px', fontSize: '0.9em' }}>\n {match[4]}\n </code>\n );\n } else if (match[5]) {\n parts.push(<s key={key++}>{match[5]}</s>);\n } else if (match[6] || match[7]) {\n parts.push(<em key={key++}>{match[6] || match[7]}</em>);\n }\n\n remaining = remaining.slice(match.index + fullMatch.length);\n }\n\n return parts.length === 1 && typeof parts[0] === 'string' ? parts[0] : <>{parts}</>;\n};\n\n/** @Todo vibecode - 탭 제목용 마크다운 제거 (plain text 필요) */\nconst stripMarkdown = (text: string): string =>\n text\n .replace(/\\*\\*(.+?)\\*\\*/g, '$1')\n .replace(/__(.+?)__/g, '$1')\n .replace(/\\*(.+?)\\*/g, '$1')\n .replace(/_(.+?)_/g, '$1')\n .replace(/`(.+?)`/g, '$1')\n .replace(/~~(.+?)~~/g, '$1');\n\nexport interface PollCardProps {\n /** 모든 질문 목록 */\n questions: PollQuestion[];\n /** 제출 콜백 (모든 질문의 응답) */\n onSubmit: (responses: PollResponse[]) => void;\n /** 건너뛰기 콜백 */\n onSkip?: () => void;\n}\n\n/**\n * @description 탭 형식 Poll 카드 컴포넌트\n * @Todo vibecode - 여러 질문을 탭으로 표시, 모두 답변 후 제출\n */\nexport const PollCard: React.FC<PollCardProps> = ({\n questions,\n onSubmit,\n onSkip,\n}) => {\n const [activeTab, setActiveTab] = useState(0);\n // 각 질문별 선택 상태: { questionId: Set<optionId> }\n const [selections, setSelections] = useState<Record<string, Set<string>>>({});\n // 각 질문별 기타 텍스트\n const [otherTexts, setOtherTexts] = useState<Record<string, string>>({});\n // 각 질문별 기타 선택 여부\n const [otherSelected, setOtherSelected] = useState<Record<string, boolean>>({});\n\n const currentQuestion = questions[activeTab];\n\n const handleOptionToggle = useCallback(\n (questionId: string, optionId: string, multiSelect: boolean) => {\n setSelections((prev) => {\n const current = prev[questionId] || new Set();\n const next = new Set(current);\n\n if (multiSelect) {\n if (next.has(optionId)) {\n next.delete(optionId);\n } else {\n next.add(optionId);\n }\n } else {\n next.clear();\n next.add(optionId);\n // 단일 선택 시 기타 해제\n setOtherSelected((os) => ({ ...os, [questionId]: false }));\n setOtherTexts((ot) => ({ ...ot, [questionId]: '' }));\n }\n\n return { ...prev, [questionId]: next };\n });\n },\n []\n );\n\n const handleOtherToggle = useCallback((questionId: string, multiSelect: boolean) => {\n if (multiSelect) {\n setOtherSelected((prev) => ({ ...prev, [questionId]: !prev[questionId] }));\n } else {\n setSelections((prev) => ({ ...prev, [questionId]: new Set() }));\n setOtherSelected((prev) => ({ ...prev, [questionId]: true }));\n }\n }, []);\n\n const handleSubmit = useCallback(() => {\n const responses: PollResponse[] = questions.map((q) => {\n const selected = selections[q.id] || new Set();\n const other = otherSelected[q.id] && otherTexts[q.id]?.trim();\n\n return {\n questionId: q.id,\n selectedOptions: Array.from(selected),\n otherText: other || undefined,\n skipped: false,\n };\n });\n onSubmit(responses);\n }, [questions, selections, otherSelected, otherTexts, onSubmit]);\n\n const handleSkip = useCallback(() => {\n const responses: PollResponse[] = questions.map((q) => ({\n questionId: q.id,\n selectedOptions: [],\n skipped: true,\n }));\n onSubmit(responses);\n onSkip?.();\n }, [questions, onSubmit, onSkip]);\n\n // ESC로 건너뛰기\n useEffect(() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n if (typeof window === 'undefined') return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') handleSkip();\n };\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [handleSkip]);\n\n // 각 질문별 선택 수\n const getSelectionCount = (questionId: string) => {\n const selected = selections[questionId]?.size || 0;\n const other = otherSelected[questionId] && otherTexts[questionId]?.trim() ? 1 : 0;\n return selected + other;\n };\n\n // 현재 탭 선택 여부\n const currentHasSelection = getSelectionCount(currentQuestion.id) > 0;\n const isLastTab = activeTab === questions.length - 1;\n const totalSelected = questions.reduce((sum, q) => sum + getSelectionCount(q.id), 0);\n\n /** @Todo vibecode - 마운트 시 옵션 stagger 애니메이션 (순차 등장) */\n const [visibleCount, setVisibleCount] = useState(0);\n const [cardVisible, setCardVisible] = useState(false);\n\n useEffect(() => {\n /** @Todo vibecode - 카드 페이드인 후 옵션 순차 등장 */\n const fadeTimer = setTimeout(() => setCardVisible(true), 50);\n const totalItems = currentQuestion.options.length + 1;\n const timers: ReturnType<typeof setTimeout>[] = [fadeTimer];\n\n for (let i = 1; i <= totalItems; i++) {\n timers.push(setTimeout(() => setVisibleCount(i), 150 + i * 80));\n }\n return () => timers.forEach(clearTimeout);\n }, [currentQuestion.options.length]);\n\n /** @Todo vibecode - 탭 전환 시 애니메이션 리셋 */\n useEffect(() => {\n setVisibleCount(0);\n const totalItems = currentQuestion.options.length + 1;\n const timers: ReturnType<typeof setTimeout>[] = [];\n for (let i = 1; i <= totalItems; i++) {\n timers.push(setTimeout(() => setVisibleCount(i), i * 80));\n }\n return () => timers.forEach(clearTimeout);\n }, [activeTab, currentQuestion.options.length]);\n\n /**\n * @description 확인 버튼: 다음 탭 이동 또는 마지막 탭에서 제출\n * @Todo vibecode - 탭 간 순차 이동 후 최종 제출\n */\n const handleNext = useCallback(() => {\n if (!isLastTab) {\n setActiveTab((prev) => prev + 1);\n } else {\n handleSubmit();\n }\n }, [isLastTab, handleSubmit]);\n\n return (\n <div\n className=\"chatllm-poll-card\"\n style={{\n backgroundColor: 'var(--chatllm-content-bg, #fff)',\n borderRadius: '12px',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n overflow: 'hidden',\n opacity: cardVisible ? 1 : 0,\n transform: cardVisible ? 'translateY(0)' : 'translateY(8px)',\n transition: 'opacity 0.3s ease, transform 0.3s ease',\n marginTop: '12px',\n }}\n >\n {/* Tabs */}\n {questions.length > 1 && (\n <div\n style={{\n display: 'flex',\n borderBottom: '1px solid var(--chatllm-border, #e5e7eb)',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n }}\n >\n {questions.map((q, idx) => {\n const isActive = idx === activeTab;\n const hasSelection = getSelectionCount(q.id) > 0;\n return (\n <button\n key={q.id}\n onClick={() => setActiveTab(idx)}\n style={{\n flex: 1,\n padding: '12px 16px',\n backgroundColor: isActive ? 'var(--chatllm-content-bg, #fff)' : 'transparent',\n border: 'none',\n borderBottom: isActive ? '2px solid var(--chatllm-primary, #4A90E2)' : '2px solid transparent',\n cursor: 'pointer',\n fontSize: '13px',\n fontWeight: isActive ? 600 : 500,\n color: isActive ? 'var(--chatllm-primary, #4A90E2)' : 'var(--chatllm-text-muted, #64748b)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '6px',\n transition: 'all 0.15s ease',\n }}\n >\n {hasSelection && (\n <IconSvg name=\"check-line\" size={14} color=\"var(--chatllm-success, #22c55e)\" />\n )}\n {(() => { const t = stripMarkdown(q.question); return t.length > 15 ? t.substring(0, 15) + '...' : t; })()}\n </button>\n );\n })}\n </div>\n )}\n\n {/* Question Header */}\n <div\n style={{\n padding: '16px',\n borderBottom: '1px solid var(--chatllm-border-light, #f1f5f9)',\n }}\n >\n <div\n style={{\n fontSize: '15px',\n fontWeight: 600,\n color: 'var(--chatllm-text, #1e293b)',\n }}\n >\n {renderInlineMarkdown(currentQuestion.question)}\n </div>\n {currentQuestion.multiSelect && (\n <div\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted, #94a3b8)',\n marginTop: '4px',\n }}\n >\n 복수 선택 가능\n </div>\n )}\n </div>\n\n {/* Options */}\n <div style={{ padding: '8px' }}>\n {currentQuestion.options.map((option, optIdx) => {\n const isSelected = selections[currentQuestion.id]?.has(option.id) || false;\n /** @Todo vibecode - stagger 애니메이션: visibleCount 기반 순차 등장 */\n const isVisible = optIdx < visibleCount;\n return (\n <button\n key={option.id}\n onClick={() => handleOptionToggle(currentQuestion.id, option.id, currentQuestion.multiSelect ?? false)}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'flex-start',\n gap: '12px',\n padding: '12px 14px',\n backgroundColor: isSelected\n ? 'var(--chatllm-primary-light, rgba(74, 144, 226, 0.08))'\n : 'transparent',\n border: isSelected\n ? '1px solid var(--chatllm-primary, #4A90E2)'\n : '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'all 0.2s ease',\n marginBottom: '6px',\n opacity: isVisible ? 1 : 0,\n transform: isVisible ? 'translateY(0)' : 'translateY(6px)',\n }}\n >\n {/* Checkbox */}\n <div\n style={{\n width: '20px',\n height: '20px',\n borderRadius: currentQuestion.multiSelect ? '4px' : '50%',\n border: `2px solid ${isSelected ? 'var(--chatllm-primary, #4A90E2)' : 'var(--chatllm-border, #d1d5db)'}`,\n backgroundColor: isSelected ? 'var(--chatllm-primary, #4A90E2)' : 'transparent',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n marginTop: '2px',\n transition: 'all 0.15s ease',\n }}\n >\n {isSelected && <IconSvg name=\"check-line\" size={14} color=\"#fff\" />}\n </div>\n <div style={{ flex: 1 }}>\n <span\n style={{\n fontSize: '14px',\n fontWeight: 500,\n color: 'var(--chatllm-text, #1e293b)',\n lineHeight: '1.4',\n }}\n >\n {renderInlineMarkdown(option.label)}\n </span>\n {option.description && (\n <div\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted, #64748b)',\n marginTop: '2px',\n lineHeight: '1.3',\n }}\n >\n {renderInlineMarkdown(option.description)}\n </div>\n )}\n </div>\n </button>\n );\n })}\n\n {/* Other Option */}\n {currentQuestion.allowOther !== false && (() => {\n /** @Todo vibecode - 기타 옵션도 stagger 애니메이션 적용 */\n const otherVisible = currentQuestion.options.length < visibleCount;\n return (\n <>\n <button\n onClick={() => handleOtherToggle(currentQuestion.id, currentQuestion.multiSelect ?? false)}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px 14px',\n backgroundColor: otherSelected[currentQuestion.id]\n ? 'var(--chatllm-primary-light, rgba(74, 144, 226, 0.08))'\n : 'transparent',\n border: otherSelected[currentQuestion.id]\n ? '1px solid var(--chatllm-primary, #4A90E2)'\n : '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'all 0.2s ease',\n opacity: otherVisible ? 1 : 0,\n transform: otherVisible ? 'translateY(0)' : 'translateY(6px)',\n }}\n >\n <div\n style={{\n width: '20px',\n height: '20px',\n borderRadius: currentQuestion.multiSelect ? '4px' : '50%',\n border: `2px solid ${otherSelected[currentQuestion.id] ? 'var(--chatllm-primary, #4A90E2)' : 'var(--chatllm-border, #d1d5db)'}`,\n backgroundColor: otherSelected[currentQuestion.id] ? 'var(--chatllm-primary, #4A90E2)' : 'transparent',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n transition: 'all 0.15s ease',\n }}\n >\n {otherSelected[currentQuestion.id] && <IconSvg name=\"check-line\" size={14} color=\"#fff\" />}\n </div>\n <span style={{ fontSize: '14px', color: 'var(--chatllm-text-muted, #64748b)' }}>\n 기타\n </span>\n </button>\n {otherSelected[currentQuestion.id] && (\n <div style={{ padding: '8px 0 4px 32px' }}>\n <input\n type=\"text\"\n value={otherTexts[currentQuestion.id] || ''}\n onChange={(e) => setOtherTexts((prev) => ({ ...prev, [currentQuestion.id]: e.target.value }))}\n placeholder=\"직접 입력...\"\n style={{\n width: '100%',\n padding: '10px 12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '6px',\n color: 'var(--chatllm-text, #1e293b)',\n fontSize: '13px',\n outline: 'none',\n }}\n autoFocus\n />\n </div>\n )}\n </>\n );\n })()}\n </div>\n\n {/* Footer */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderTop: '1px solid var(--chatllm-border, #e5e7eb)',\n }}\n >\n <span style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #94a3b8)' }}>\n {questions.length > 1\n ? `${activeTab + 1} / ${questions.length}`\n : `${totalSelected}개 선택됨`}\n </span>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <button\n onClick={handleSkip}\n style={{\n padding: '8px 16px',\n backgroundColor: 'transparent',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '6px',\n color: 'var(--chatllm-text-secondary, #64748b)',\n fontSize: '13px',\n fontWeight: 500,\n cursor: 'pointer',\n }}\n >\n 자동생성\n </button>\n <button\n onClick={handleNext}\n disabled={!currentHasSelection}\n style={{\n padding: '8px 20px',\n backgroundColor: currentHasSelection\n ? 'var(--chatllm-primary, #4A90E2)'\n : 'var(--chatllm-bg-disabled, #e5e7eb)',\n border: 'none',\n borderRadius: '6px',\n color: currentHasSelection ? '#fff' : 'var(--chatllm-text-muted, #94a3b8)',\n fontSize: '13px',\n fontWeight: 600,\n cursor: currentHasSelection ? 'pointer' : 'not-allowed',\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n }}\n >\n {isLastTab ? '제출' : '다음'}\n <IconSvg\n name=\"arrow-right-line\"\n size={16}\n color={currentHasSelection ? '#fff' : 'var(--chatllm-text-muted)'}\n />\n </button>\n </div>\n </div>\n </div>\n );\n};\n\nexport default PollCard;\n","/**\n * @description 스킬 실행 진행 상태 UI 컴포넌트\n * @Todo vibecode - 범용 스킬 실행 상태 표시\n */\n\nimport React from 'react';\nimport { IconSvg } from './Icon';\nimport type { IconName } from './Icon';\nimport type { SkillExecution } from '../types';\n\nexport interface SkillProgressUIProps {\n /** 스킬 실행 상태 */\n execution: SkillExecution;\n /** UI 표시용 레이블 */\n skillLabel?: string;\n /** 아이콘 이름 */\n skillIcon?: string;\n}\n\n/**\n * @description 스킬 아이콘 매핑\n */\nconst mapIcon = (icon?: string): IconName => {\n const iconMap: Record<string, IconName> = {\n search: 'search-eye-line',\n image: 'image-line',\n code: 'code-s-slash-line',\n file: 'file-text-line',\n document: 'file-text-line',\n };\n return icon ? iconMap[icon] || 'sparkling-line' : 'sparkling-line';\n};\n\nexport const SkillProgressUI: React.FC<SkillProgressUIProps> = ({\n execution,\n skillLabel,\n skillIcon,\n}) => {\n const label = skillLabel || execution.skillName;\n const isExecuting = execution.status === 'executing';\n const isDone = execution.status === 'done';\n const isError = execution.status === 'error';\n\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '12px 16px',\n marginTop: '8px',\n backgroundColor: isError\n ? 'rgba(239, 68, 68, 0.08)'\n : 'var(--chatllm-primary-light)',\n borderRadius: '12px',\n border: `1px solid ${isError ? 'rgba(239, 68, 68, 0.2)' : 'rgba(74, 144, 226, 0.15)'}`,\n }}\n >\n {/* 상태 아이콘 */}\n {isExecuting && (\n <div\n style={{\n width: 16,\n height: 16,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <div\n style={{\n width: 12,\n height: 12,\n borderRadius: '50%',\n border: '2px solid var(--chatllm-primary)',\n borderTopColor: 'transparent',\n animation: 'chatllm-spin 1s linear infinite',\n }}\n />\n </div>\n )}\n {isDone && <IconSvg name=\"check-line\" size={16} color=\"var(--chatllm-success)\" />}\n {isError && <IconSvg name=\"close-line\" size={16} color=\"var(--chatllm-error)\" />}\n\n {/* 스킬 아이콘 */}\n <IconSvg\n name={mapIcon(skillIcon)}\n size={16}\n color={isError ? 'var(--chatllm-error)' : 'var(--chatllm-primary)'}\n />\n\n {/* 상태 텍스트 */}\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: isError ? 'var(--chatllm-error)' : 'var(--chatllm-text-secondary)',\n }}\n >\n {isExecuting && `${label} 실행 중...`}\n {isDone && `${label} 완료`}\n {isError && `${label} 오류: ${execution.error || '알 수 없는 오류'}`}\n </span>\n\n {/* 진행 상태 (있는 경우) */}\n {execution.progress && isExecuting && (\n <span\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted)',\n marginLeft: 'auto',\n }}\n >\n {execution.progress.phaseLabel}\n {execution.progress.percentage != null && ` (${execution.progress.percentage}%)`}\n </span>\n )}\n </div>\n );\n};\n\nexport default SkillProgressUI;\n","/**\n * @description 이미지 콘텐츠 카드 컴포넌트\n * @Todo vibecode - 멀티 콘텐츠 메시지에서 이미지 인라인 표시\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\nimport type { ImageContentPart } from '../types';\n\nexport interface ImageContentCardProps {\n /** 이미지 콘텐츠 파트 */\n part: ImageContentPart;\n}\n\n/**\n * @description 이미지 카드 렌더러 (확대 모달 + 다운로드)\n * @Todo vibecode - 인라인 이미지 표시, 클릭 시 확대\n */\nexport const ImageContentCard: React.FC<ImageContentCardProps> = ({ part }) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const [isLoaded, setIsLoaded] = useState(false);\n const [hasError, setHasError] = useState(false);\n\n if (hasError) {\n return (\n <div\n style={{\n padding: '16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '8px',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n color: 'var(--chatllm-text-muted, #64748b)',\n fontSize: '13px',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n }}\n >\n <IconSvg name=\"error-warning-line\" size={16} color=\"var(--chatllm-error, #ef4444)\" />\n 이미지를 불러올 수 없습니다\n </div>\n );\n }\n\n return (\n <>\n <div\n style={{\n position: 'relative',\n borderRadius: '8px',\n overflow: 'hidden',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n cursor: 'pointer',\n maxWidth: part.width ? `${Math.min(part.width, 480)}px` : '480px',\n }}\n onClick={() => setIsExpanded(true)}\n >\n {!isLoaded && (\n <div\n style={{\n padding: '40px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'var(--chatllm-bg-secondary, #f1f5f9)',\n }}\n >\n <IconSvg name=\"loader-4-line\" size={24} color=\"var(--chatllm-text-muted, #94a3b8)\" />\n </div>\n )}\n <img\n src={part.url}\n alt={part.alt || ''}\n onLoad={() => setIsLoaded(true)}\n onError={() => setHasError(true)}\n style={{\n display: isLoaded ? 'block' : 'none',\n width: '100%',\n height: 'auto',\n maxHeight: '400px',\n objectFit: 'contain',\n }}\n />\n {part.alt && isLoaded && (\n <div\n style={{\n padding: '6px 10px',\n fontSize: '12px',\n color: 'var(--chatllm-text-muted, #64748b)',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderTop: '1px solid var(--chatllm-border, #e5e7eb)',\n }}\n >\n {part.alt}\n </div>\n )}\n </div>\n\n {/* @Todo vibecode - 이미지 확대 모달 */}\n {isExpanded && (\n <div\n onClick={() => setIsExpanded(false)}\n style={{\n position: 'fixed',\n inset: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.8)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 9999,\n cursor: 'zoom-out',\n }}\n >\n <img\n src={part.url}\n alt={part.alt || ''}\n style={{\n maxWidth: '90vw',\n maxHeight: '90vh',\n objectFit: 'contain',\n borderRadius: '4px',\n }}\n />\n </div>\n )}\n </>\n );\n};\n\nexport default ImageContentCard;\n","/**\n * @description 파일 콘텐츠 카드 컴포넌트\n * @Todo vibecode - 멀티 콘텐츠 메시지에서 파일 첨부 표시\n */\n\nimport React from 'react';\nimport { IconSvg } from './Icon';\nimport type { IconName } from './Icon';\nimport type { FileContentPart } from '../types';\n\nexport interface FileContentCardProps {\n /** 파일 콘텐츠 파트 */\n part: FileContentPart;\n}\n\n/**\n * @description 파일 사이즈 포맷팅\n * @Todo vibecode - bytes → KB/MB 변환\n */\nconst formatFileSize = (bytes?: number): string => {\n if (!bytes) return '';\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n};\n\n/**\n * @description MIME 타입에 따른 아이콘 선택\n * @Todo vibecode - 파일 유형별 아이콘 분기\n */\nconst getFileIcon = (mimeType?: string): IconName => {\n if (!mimeType) return 'file-text-line';\n if (mimeType.startsWith('image/')) return 'image-line';\n if (mimeType.startsWith('video/')) return 'video-line';\n if (mimeType.startsWith('audio/')) return 'mic-line';\n if (mimeType.includes('pdf')) return 'file-text-line';\n if (mimeType.includes('zip') || mimeType.includes('compressed')) return 'folder-line';\n return 'file-text-line';\n};\n\n/**\n * @description 파일 카드 렌더러 (파일명 + 아이콘 + 다운로드)\n * @Todo vibecode - 파일 첨부 인라인 표시\n */\nexport const FileContentCard: React.FC<FileContentCardProps> = ({ part }) => {\n return (\n <a\n href={part.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n download={part.name}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '12px 16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '8px',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n textDecoration: 'none',\n color: 'inherit',\n transition: 'background-color 0.15s ease',\n maxWidth: '320px',\n }}\n >\n <div\n style={{\n width: '36px',\n height: '36px',\n borderRadius: '8px',\n backgroundColor: 'var(--chatllm-primary-light, rgba(74, 144, 226, 0.1))',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n >\n <IconSvg name={getFileIcon(part.mimeType)} size={18} color=\"var(--chatllm-primary, #4A90E2)\" />\n </div>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-text, #1e293b)',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {part.name}\n </div>\n {(part.size || part.mimeType) && (\n <div\n style={{\n fontSize: '11px',\n color: 'var(--chatllm-text-muted, #94a3b8)',\n marginTop: '2px',\n }}\n >\n {[formatFileSize(part.size), part.mimeType].filter(Boolean).join(' · ')}\n </div>\n )}\n </div>\n <IconSvg name=\"download-line\" size={16} color=\"var(--chatllm-text-muted, #94a3b8)\" />\n </a>\n );\n};\n\nexport default FileContentCard;\n","/**\n * @description 도구 실행 상태 카드 컴포넌트\n * @Todo vibecode - 로딩/완료/에러 상태 표시 + 접이식 소스 목록\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\nimport { LinkChip } from './LinkChip';\nimport type { IconName } from './Icon';\nimport type { SourceItem } from '../types';\n\nexport interface ToolStatusCardProps {\n /** 도구 이름 (fallback 레이블용) */\n toolName: string;\n /** UI 표시용 레이블 (예: '웹 검색', '이미지 생성') */\n label?: string;\n /** 아이콘 키 (예: 'search', 'image') */\n icon?: string;\n /** 현재 상태 */\n status: 'loading' | 'done' | 'error';\n /** 출처 목록 (done 상태에서 접이식 표시) */\n sources?: SourceItem[];\n /** 에러 메시지 (error 상태) */\n errorMessage?: string;\n}\n\n/** @Todo vibecode - 도구 아이콘 매핑 */\nconst mapIcon = (icon?: string): IconName => {\n const iconMap: Record<string, IconName> = {\n search: 'search-eye-line',\n image: 'image-line',\n code: 'code-s-slash-line',\n file: 'file-text-line',\n document: 'file-text-line',\n };\n return icon ? iconMap[icon] || 'sparkling-line' : 'sparkling-line';\n};\n\n/** @Todo vibecode - 도구 이름 → 한국어 레이블 매핑 */\nconst getDefaultLabel = (toolName: string): string => {\n const labelMap: Record<string, string> = {\n web_search: '웹 검색',\n generate_image: '이미지 생성',\n search: '검색',\n };\n return labelMap[toolName] || toolName;\n};\n\n/** @Todo vibecode - 상태별 동사 접미사 */\nconst getStatusSuffix = (label: string, status: 'loading' | 'done' | 'error'): string => {\n if (status === 'loading') return `${label} 중...`;\n if (status === 'done') return `${label}됨`;\n return `${label} 오류`;\n};\n\nexport const ToolStatusCard: React.FC<ToolStatusCardProps> = ({\n toolName,\n label,\n icon,\n status,\n sources,\n errorMessage,\n}) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const displayLabel = label || getDefaultLabel(toolName);\n const statusText = getStatusSuffix(displayLabel, status);\n const hasSources = sources && sources.length > 0;\n const isClickable = status === 'done' && hasSources;\n const isError = status === 'error';\n const isLoading = status === 'loading';\n\n return (\n <div style={{ marginBottom: '4px' }}>\n {/* 상태 헤더 */}\n <div\n onClick={isClickable ? () => setIsExpanded(!isExpanded) : undefined}\n role={isClickable ? 'button' : undefined}\n tabIndex={isClickable ? 0 : undefined}\n onKeyDown={isClickable ? (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setIsExpanded(!isExpanded);\n }\n } : undefined}\n aria-expanded={isClickable ? isExpanded : undefined}\n aria-label={isClickable ? `${statusText} - ${sources!.length}개 소스` : statusText}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '8px',\n padding: '6px 12px',\n backgroundColor: isError\n ? 'var(--chatllm-error-bg, #fef2f2)'\n : 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '20px',\n border: `1px solid ${isError ? 'var(--chatllm-error-border, #fecaca)' : 'var(--chatllm-border-light, #e2e8f0)'}`,\n cursor: isClickable ? 'pointer' : 'default',\n transition: 'background-color 0.15s',\n userSelect: 'none',\n }}\n >\n {/* 상태 아이콘 */}\n {isLoading && (\n <div\n style={{\n width: 14,\n height: 14,\n borderRadius: '50%',\n border: '2px solid var(--chatllm-primary, #4A90E2)',\n borderTopColor: 'transparent',\n animation: 'chatllm-spin 1s linear infinite',\n flexShrink: 0,\n }}\n />\n )}\n {status === 'done' && (\n <IconSvg name=\"check-line\" size={14} color=\"var(--chatllm-success, #22c55e)\" />\n )}\n {isError && (\n <IconSvg name=\"error-warning-line\" size={14} color=\"var(--chatllm-error, #ef4444)\" />\n )}\n\n {/* 도구 아이콘 */}\n <IconSvg\n name={mapIcon(icon)}\n size={14}\n color={isError ? 'var(--chatllm-error, #ef4444)' : 'var(--chatllm-text-muted, #64748b)'}\n />\n\n {/* 상태 텍스트 */}\n <span\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: isError\n ? 'var(--chatllm-error, #ef4444)'\n : 'var(--chatllm-text-secondary, #475569)',\n }}\n >\n {isError && errorMessage ? `${statusText}: ${errorMessage}` : statusText}\n </span>\n\n {/* 소스 개수 + 펼침 화살표 */}\n {isClickable && (\n <>\n <span\n style={{\n fontSize: '12px',\n color: 'var(--chatllm-text-muted, #94a3b8)',\n fontWeight: 400,\n }}\n >\n · {sources!.length}개 소스\n </span>\n <span\n style={{\n fontSize: '10px',\n color: 'var(--chatllm-text-muted, #94a3b8)',\n transition: 'transform 0.2s',\n transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',\n }}\n >\n ▼\n </span>\n </>\n )}\n </div>\n\n {/* 접이식 소스 목록 */}\n {isExpanded && hasSources && (\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '6px',\n marginTop: '8px',\n padding: '10px 12px',\n backgroundColor: 'var(--chatllm-source-bg, #f8fafc)',\n borderRadius: '8px',\n border: '1px solid var(--chatllm-border-light, #e2e8f0)',\n }}\n >\n {sources!.map((source, si) => (\n <LinkChip\n key={si}\n text={source.title}\n url={source.url}\n index={si}\n showFavicon\n />\n ))}\n </div>\n )}\n </div>\n );\n};\n\nexport default ToolStatusCard;\n","/**\n * @description 멀티 콘텐츠 파트 렌더러\n * @Todo vibecode - contentParts 배열을 순서대로 렌더링\n */\n\nimport React from 'react';\nimport { MarkdownRenderer } from './MarkdownRenderer';\nimport type { ChoiceOption } from './MarkdownRenderer';\nimport { ImageContentCard } from './ImageContentCard';\nimport { FileContentCard } from './FileContentCard';\nimport { LinkChip } from './LinkChip';\nimport { ToolStatusCard } from './ToolStatusCard';\nimport { IconSvg } from './Icon';\nimport type { MessageContentPart, SourceItem } from '../types';\n\nexport interface ContentPartRendererProps {\n /** 콘텐츠 파트 배열 */\n parts: MessageContentPart[];\n /** 선택지 클릭 핸들러 */\n onChoiceClick?: (choice: ChoiceOption) => void;\n /** Thinking 블록 표시 여부 */\n showThinking?: boolean;\n /** Thinking 블록 기본 펼침 상태 */\n thinkingDefaultOpen?: boolean;\n}\n\n/**\n * @description contentParts 배열을 타입별로 렌더링\n * @Todo vibecode - text, image, file, search_result, tool_loading, tool_result, error 지원\n * tool_result → ToolStatusCard 기반 구조화 렌더링\n */\nexport const ContentPartRenderer: React.FC<ContentPartRendererProps> = ({\n parts,\n onChoiceClick,\n showThinking,\n thinkingDefaultOpen,\n}) => {\n /**\n * @Todo vibecode - tool_result/search_result에서 sources 수집\n * 후속 text 파트에 인라인 소스 참조용으로 전달\n */\n const collectedSources: SourceItem[] = [];\n for (const part of parts) {\n if (part.type === 'tool_result' && part.result.sources) {\n collectedSources.push(...part.result.sources);\n } else if (part.type === 'search_result') {\n collectedSources.push(...part.results);\n }\n }\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {parts.map((part, idx) => {\n switch (part.type) {\n case 'text':\n return (\n <MarkdownRenderer\n key={idx}\n content={part.content}\n onChoiceClick={onChoiceClick}\n showThinking={showThinking}\n thinkingDefaultOpen={thinkingDefaultOpen}\n sources={collectedSources.length > 0 ? collectedSources : undefined}\n />\n );\n\n case 'image':\n return <ImageContentCard key={idx} part={part} />;\n\n case 'file':\n return <FileContentCard key={idx} part={part} />;\n\n case 'search_result':\n return (\n <div key={idx} style={{ display: 'flex', flexWrap: 'wrap', gap: '6px' }}>\n {part.results.map((source, si) => (\n <LinkChip\n key={si}\n text={source.title}\n url={source.url}\n index={si + 1}\n showFavicon\n />\n ))}\n </div>\n );\n\n case 'tool_loading':\n return (\n <ToolStatusCard\n key={idx}\n toolName={part.toolName}\n label={part.label}\n status=\"loading\"\n />\n );\n\n case 'tool_result': {\n const { result } = part;\n return (\n <div key={idx} style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\n {/* 도구 상태 카드 (완료/에러 + 접이식 소스) */}\n <ToolStatusCard\n toolName={part.toolName}\n label={part.label}\n icon={part.icon}\n status={result.type === 'error' ? 'error' : 'done'}\n sources={result.sources}\n errorMessage={result.type === 'error' ? result.content : undefined}\n />\n {/* 실제 결과 콘텐츠 */}\n {result.type === 'image' && (\n <ImageContentCard\n part={{ type: 'image', url: result.content, alt: result.metadata?.alt }}\n />\n )}\n {result.type === 'file' && (\n <FileContentCard\n part={{\n type: 'file',\n name: result.metadata?.fileName || 'file',\n url: result.content,\n mimeType: result.metadata?.mimeType,\n }}\n />\n )}\n </div>\n );\n }\n\n case 'error':\n return (\n <div\n key={idx}\n style={{\n padding: '10px 14px',\n backgroundColor: 'var(--chatllm-error-bg, #fef2f2)',\n borderRadius: '8px',\n border: '1px solid var(--chatllm-error-border, #fecaca)',\n fontSize: '13px',\n color: 'var(--chatllm-error, #ef4444)',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n }}\n >\n <IconSvg name=\"error-warning-line\" size={16} color=\"var(--chatllm-error, #ef4444)\" />\n {part.message}\n </div>\n );\n\n default:\n return null;\n }\n })}\n </div>\n );\n};\n\nexport default ContentPartRenderer;\n","/**\n * @description 설정 모달 컴포넌트\n * 일반/개인화/데이터 설정 탭 포함\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\nimport type { PersonalizationConfig, SettingsTab } from '../types';\nimport type { MemoryItem } from './MemoryPanel';\n\nexport interface SettingsModalProps {\n /** 모달 열림 상태 */\n isOpen: boolean;\n /** 모달 닫기 핸들러 */\n onClose: () => void;\n /** 개인화 설정 */\n personalization: PersonalizationConfig;\n /** 개인화 설정 변경 핸들러 */\n onPersonalizationChange: (config: PersonalizationConfig) => void;\n /** API 키 */\n apiKey?: string;\n /** API 키 변경 핸들러 */\n onApiKeyChange?: (key: string) => void;\n /** 전체 데이터 삭제 핸들러 */\n onClearAllData?: () => void;\n /** API 키 레이블 */\n apiKeyLabel?: string;\n /** API 키 설명 */\n apiKeyDescription?: string;\n /** @description 메모리 아이템 목록 @Todo vibecode */\n memoryItems?: MemoryItem[];\n /** @description 컨텍스트 요약 (압축된 대화) @Todo vibecode */\n contextSummary?: string;\n /** @description 메모리 항목 삭제 핸들러 @Todo vibecode */\n onDeleteMemory?: (key: string) => void;\n /** @description 메모리 전체 삭제 핸들러 @Todo vibecode */\n onClearMemory?: () => void;\n /** @Todo vibecode - 개인화 설정 저장 핸들러 (저장 버튼 클릭 시) */\n onSave?: () => void;\n /** @description 프로젝트 메모리 아이템 목록 @Todo vibecode */\n projectMemoryItems?: MemoryItem[];\n /** @description 프로젝트 메모리 항목 삭제 핸들러 @Todo vibecode */\n onDeleteProjectMemory?: (key: string) => void;\n /** @description 프로젝트 메모리 전체 삭제 핸들러 @Todo vibecode */\n onClearProjectMemory?: () => void;\n /** @description 프로젝트 기능 활성화 여부 @Todo vibecode */\n enableProjects?: boolean;\n /** @description 현재 프로젝트 이름 @Todo vibecode */\n currentProjectTitle?: string;\n /** @description 메모리 탭 표시 여부 (기본: true) @Todo vibecode */\n showMemoryTab?: boolean;\n}\n\nconst DEFAULT_PERSONALIZATION: PersonalizationConfig = {\n responseStyle: {\n warmth: 'medium',\n enthusiasm: 'medium',\n emojiUsage: 'low',\n formatting: 'default',\n verbosity: 'balanced',\n },\n userProfile: {},\n useMemory: true,\n language: 'auto',\n};\n\nexport const SettingsModal: React.FC<SettingsModalProps> = ({\n isOpen,\n onClose,\n personalization,\n onPersonalizationChange,\n apiKey = '',\n onApiKeyChange,\n onClearAllData,\n apiKeyLabel = 'API Key',\n apiKeyDescription = 'Cloud 모델 사용에 필요합니다',\n memoryItems = [],\n contextSummary,\n onDeleteMemory,\n onClearMemory,\n onSave,\n projectMemoryItems = [],\n onDeleteProjectMemory,\n onClearProjectMemory,\n enableProjects = false,\n currentProjectTitle,\n showMemoryTab = true,\n}) => {\n const [activeTab, setActiveTab] = useState<SettingsTab>('general');\n const [localApiKey, setLocalApiKey] = useState(apiKey);\n\n if (!isOpen) return null;\n\n const updateResponseStyle = (key: string, value: string) => {\n onPersonalizationChange({\n ...personalization,\n responseStyle: {\n ...personalization.responseStyle,\n [key]: value,\n },\n });\n };\n\n const updateUserProfile = (key: string, value: string) => {\n onPersonalizationChange({\n ...personalization,\n userProfile: {\n ...personalization.userProfile,\n [key]: value,\n },\n });\n };\n\n const handleApiKeyChange = (value: string) => {\n setLocalApiKey(value);\n onApiKeyChange?.(value);\n };\n\n return (\n <div\n className=\"chatllm-settings-overlay\"\n style={{\n position: 'fixed',\n inset: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.3)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 1000,\n }}\n onClick={onClose}\n >\n <div\n className=\"chatllm-settings-modal\"\n style={{\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n borderRadius: '16px',\n width: '100%',\n maxWidth: '800px',\n height: '80vh',\n maxHeight: '600px',\n margin: '16px',\n boxShadow: '0 20px 60px rgba(0, 0, 0, 0.15)',\n display: 'flex',\n overflow: 'hidden',\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Sidebar */}\n <div\n style={{\n width: '200px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRight: '1px solid var(--chatllm-border, #e5e7eb)',\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n {/* Close Button */}\n <div style={{ padding: '16px', borderBottom: '1px solid var(--chatllm-border, #e5e7eb)' }}>\n <button\n onClick={onClose}\n style={{\n padding: '8px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg name=\"close-line\" size={20} color=\"var(--chatllm-text-muted, #6b7280)\" />\n </button>\n </div>\n\n {/* Tabs */}\n <nav style={{ flex: 1, padding: '8px' }}>\n <TabButton\n active={activeTab === 'general'}\n onClick={() => setActiveTab('general')}\n icon=\"settings-3-line\"\n label=\"일반\"\n />\n <TabButton\n active={activeTab === 'personalization'}\n onClick={() => setActiveTab('personalization')}\n icon=\"user-3-line\"\n label=\"개인 맞춤 설정\"\n />\n {/** @Todo vibecode - showMemoryTab으로 메모리 탭 노출 제어 */}\n {showMemoryTab && (\n <TabButton\n active={activeTab === 'memory'}\n onClick={() => setActiveTab('memory')}\n icon=\"robot-line\"\n label=\"AI 메모리\"\n />\n )}\n {showMemoryTab && enableProjects && (\n <TabButton\n active={activeTab === 'project-memory'}\n onClick={() => setActiveTab('project-memory')}\n icon=\"folder-line\"\n label=\"프로젝트 메모리\"\n />\n )}\n <TabButton\n active={activeTab === 'data'}\n onClick={() => setActiveTab('data')}\n icon=\"delete-bin-line\"\n label=\"데이터 제어\"\n />\n </nav>\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, overflow: 'auto', padding: '24px' }}>\n {activeTab === 'general' && (\n <div>\n <h2 style={{ fontSize: '20px', fontWeight: 600, marginBottom: '24px', color: 'var(--chatllm-text, #1f2937)' }}>\n 일반\n </h2>\n\n {/* Language */}\n <SettingRow label=\"언어\">\n <select\n value={personalization.language}\n onChange={(e) => onPersonalizationChange({ ...personalization, language: e.target.value })}\n style={selectStyle}\n >\n <option value=\"auto\">자동 탐지</option>\n <option value=\"ko\">한국어</option>\n <option value=\"en\">English</option>\n <option value=\"ja\">日本語</option>\n </select>\n </SettingRow>\n\n {/* Reset */}\n <SettingRow label=\"기본값으로 초기화\" description=\"모든 설정을 초기 상태로 되돌립니다\">\n <button\n onClick={() => onPersonalizationChange(DEFAULT_PERSONALIZATION)}\n style={buttonSecondaryStyle}\n >\n 초기화\n </button>\n </SettingRow>\n\n {/* API Key */}\n {onApiKeyChange && (\n <div style={{ marginTop: '32px', paddingTop: '24px', borderTop: '1px solid var(--chatllm-border, #e5e7eb)' }}>\n <h3 style={{ fontSize: '16px', fontWeight: 500, marginBottom: '16px', color: 'var(--chatllm-text, #1f2937)' }}>\n API 설정\n </h3>\n <div>\n <label style={{ display: 'block', fontSize: '14px', marginBottom: '8px', color: 'var(--chatllm-text, #374151)' }}>\n {apiKeyLabel}\n </label>\n <input\n type=\"password\"\n value={localApiKey}\n onChange={(e) => handleApiKeyChange(e.target.value)}\n placeholder=\"API 키를 입력하세요\"\n style={inputStyle}\n />\n <p style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #9ca3af)', marginTop: '4px' }}>\n {apiKeyDescription}\n </p>\n </div>\n </div>\n )}\n </div>\n )}\n\n {activeTab === 'personalization' && (\n <div>\n <h2 style={{ fontSize: '20px', fontWeight: 600, marginBottom: '24px', color: 'var(--chatllm-text, #1f2937)' }}>\n 개인 맞춤 설정\n </h2>\n\n {/* User Profile */}\n <section style={{ marginBottom: '32px' }}>\n <h3 style={{ fontSize: '14px', fontWeight: 500, color: 'var(--chatllm-text-muted, #6b7280)', marginBottom: '16px' }}>\n 사용자 프로필\n </h3>\n <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>\n <div>\n <label style={labelStyle}>닉네임</label>\n <input\n type=\"text\"\n value={personalization.userProfile.nickname || ''}\n onChange={(e) => updateUserProfile('nickname', e.target.value)}\n placeholder=\"어떻게 불러드릴까요?\"\n style={inputStyle}\n />\n </div>\n <div>\n <label style={labelStyle}>직업</label>\n <input\n type=\"text\"\n value={personalization.userProfile.occupation || ''}\n onChange={(e) => updateUserProfile('occupation', e.target.value)}\n placeholder=\"예: 소프트웨어 개발자\"\n style={inputStyle}\n />\n </div>\n <div>\n <label style={labelStyle}>추가 정보</label>\n <textarea\n value={personalization.userProfile.additionalInfo || ''}\n onChange={(e) => updateUserProfile('additionalInfo', e.target.value)}\n placeholder=\"관심사, 선호 사항 등\"\n rows={3}\n style={{ ...inputStyle, resize: 'none' }}\n />\n </div>\n </div>\n </section>\n\n {/* Response Style */}\n <section>\n <h3 style={{ fontSize: '14px', fontWeight: 500, color: 'var(--chatllm-text-muted, #6b7280)', marginBottom: '16px' }}>\n 응답 스타일\n </h3>\n\n <SettingRow label=\"따뜻함\">\n <select\n value={personalization.responseStyle.warmth}\n onChange={(e) => updateResponseStyle('warmth', e.target.value)}\n style={selectStyle}\n >\n <option value=\"high\">높음 - 친근하고 따뜻하게</option>\n <option value=\"medium\">기본값</option>\n <option value=\"low\">낮음 - 간결하고 사무적으로</option>\n </select>\n </SettingRow>\n\n <SettingRow label=\"열정적\">\n <select\n value={personalization.responseStyle.enthusiasm}\n onChange={(e) => updateResponseStyle('enthusiasm', e.target.value)}\n style={selectStyle}\n >\n <option value=\"high\">높음 - 적극적이고 활발하게</option>\n <option value=\"medium\">기본값</option>\n <option value=\"low\">낮음 - 차분하고 절제있게</option>\n </select>\n </SettingRow>\n\n <SettingRow label=\"이모지 사용\">\n <select\n value={personalization.responseStyle.emojiUsage}\n onChange={(e) => updateResponseStyle('emojiUsage', e.target.value)}\n style={selectStyle}\n >\n <option value=\"high\">높음 - 자주 사용</option>\n <option value=\"medium\">기본값</option>\n <option value=\"low\">낮음 - 거의 사용 안 함</option>\n </select>\n </SettingRow>\n\n <SettingRow label=\"응답 길이\">\n <select\n value={personalization.responseStyle.verbosity}\n onChange={(e) => updateResponseStyle('verbosity', e.target.value)}\n style={selectStyle}\n >\n <option value=\"detailed\">상세 - 자세하게 설명</option>\n <option value=\"balanced\">기본값</option>\n <option value=\"concise\">간결 - 핵심만 요약</option>\n </select>\n </SettingRow>\n </section>\n\n {/* @Todo vibecode - 개인화 설정 저장 버튼 */}\n {onSave && (\n <div style={{ marginTop: '24px', display: 'flex', justifyContent: 'flex-end' }}>\n <button\n onClick={onSave}\n style={{\n padding: '10px 24px',\n backgroundColor: 'var(--chatllm-primary, #4A90E2)',\n color: '#fff',\n border: 'none',\n borderRadius: '8px',\n fontSize: '14px',\n fontWeight: 600,\n cursor: 'pointer',\n transition: 'opacity 0.15s ease',\n }}\n onMouseEnter={(e) => (e.currentTarget.style.opacity = '0.85')}\n onMouseLeave={(e) => (e.currentTarget.style.opacity = '1')}\n >\n 저장\n </button>\n </div>\n )}\n </div>\n )}\n\n {activeTab === 'memory' && showMemoryTab && (\n <MemoryTabContent\n items={memoryItems}\n contextSummary={contextSummary}\n onDelete={onDeleteMemory}\n onClearAll={onClearMemory}\n />\n )}\n\n {activeTab === 'project-memory' && showMemoryTab && enableProjects && (\n <MemoryTabContent\n items={projectMemoryItems}\n onDelete={onDeleteProjectMemory}\n onClearAll={onClearProjectMemory}\n title={currentProjectTitle ? `${currentProjectTitle} 메모리` : '프로젝트 메모리'}\n emptyMessage=\"프로젝트에 저장된 메모리가 없습니다\"\n emptyDescription=\"대화가 진행되면 AI가 프로젝트 맥락을 자동으로 학습합니다\"\n />\n )}\n\n {activeTab === 'data' && (\n <div>\n <h2 style={{ fontSize: '20px', fontWeight: 600, marginBottom: '24px', color: 'var(--chatllm-text, #1f2937)' }}>\n 데이터 제어\n </h2>\n\n {/* Memory Toggle */}\n <SettingRow label=\"메모리 사용\" description=\"대화 컨텍스트를 기억합니다\">\n <button\n onClick={() => onPersonalizationChange({ ...personalization, useMemory: !personalization.useMemory })}\n style={{\n width: '48px',\n height: '28px',\n borderRadius: '14px',\n backgroundColor: personalization.useMemory\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-text-muted, #d1d5db)',\n border: 'none',\n cursor: 'pointer',\n position: 'relative',\n transition: 'background-color 0.2s',\n }}\n >\n <div\n style={{\n width: '22px',\n height: '22px',\n borderRadius: '50%',\n backgroundColor: '#ffffff',\n boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',\n position: 'absolute',\n top: '3px',\n left: personalization.useMemory ? '23px' : '3px',\n transition: 'left 0.2s',\n }}\n />\n </button>\n </SettingRow>\n\n {/* Clear All Data */}\n {onClearAllData && (\n <SettingRow label=\"대화 기록 삭제\" description=\"모든 대화 기록을 삭제합니다\">\n <button\n onClick={() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n if (typeof window !== 'undefined' && window.confirm('모든 대화 기록을 삭제하시겠습니까?')) {\n onClearAllData();\n }\n }}\n style={buttonDangerStyle}\n >\n 삭제\n </button>\n </SettingRow>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n\n// Tab Button Component\nconst TabButton: React.FC<{\n active: boolean;\n onClick: () => void;\n icon: string;\n label: string;\n}> = ({ active, onClick, icon, label }) => (\n <button\n onClick={onClick}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '10px 12px',\n borderRadius: '10px',\n border: 'none',\n backgroundColor: active ? 'var(--chatllm-bg, #ffffff)' : 'transparent',\n boxShadow: active ? '0 1px 3px rgba(0, 0, 0, 0.08)' : 'none',\n color: active ? 'var(--chatllm-primary, #3b82f6)' : 'var(--chatllm-text-muted, #6b7280)',\n fontSize: '14px',\n cursor: 'pointer',\n textAlign: 'left',\n marginBottom: '4px',\n }}\n >\n <IconSvg name={icon as any} size={20} />\n {label}\n </button>\n);\n\n// Setting Row Component\nconst SettingRow: React.FC<{\n label: string;\n description?: string;\n children: React.ReactNode;\n}> = ({ label, description, children }) => (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 0',\n borderBottom: '1px solid var(--chatllm-border-light, #f3f4f6)',\n }}\n >\n <div>\n <span style={{ fontSize: '14px', color: 'var(--chatllm-text, #374151)' }}>{label}</span>\n {description && (\n <p style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #9ca3af)', marginTop: '2px' }}>\n {description}\n </p>\n )}\n </div>\n {children}\n </div>\n);\n\n// Styles\nconst selectStyle: React.CSSProperties = {\n padding: '8px 12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n fontSize: '14px',\n color: 'var(--chatllm-text, #374151)',\n minWidth: '200px',\n cursor: 'pointer',\n};\n\nconst inputStyle: React.CSSProperties = {\n width: '100%',\n padding: '10px 12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '8px',\n fontSize: '14px',\n color: 'var(--chatllm-text, #374151)',\n};\n\nconst labelStyle: React.CSSProperties = {\n display: 'block',\n fontSize: '12px',\n color: 'var(--chatllm-text-muted, #6b7280)',\n marginBottom: '6px',\n};\n\nconst buttonSecondaryStyle: React.CSSProperties = {\n padding: '8px 16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f3f4f6)',\n border: 'none',\n borderRadius: '8px',\n fontSize: '14px',\n color: 'var(--chatllm-text, #374151)',\n cursor: 'pointer',\n};\n\nconst buttonDangerStyle: React.CSSProperties = {\n padding: '8px 16px',\n backgroundColor: 'var(--chatllm-danger-bg, #fef2f2)',\n border: 'none',\n borderRadius: '8px',\n fontSize: '14px',\n color: 'var(--chatllm-danger, #dc2626)',\n cursor: 'pointer',\n};\n\n/**\n * @description 메모리 탭 내부 콘텐츠\n * @Todo vibecode - SettingsModal 내 AI 메모리 뷰\n */\nconst memoryCategoryLabels: Record<string, string> = {\n fact: '사용자 정보',\n skill: '전문 분야/기술',\n preference: '사용자 선호',\n};\n\nconst memoryCategoryColors: Record<string, string> = {\n fact: '#f59e0b',\n skill: '#10b981',\n preference: '#8b5cf6',\n};\n\nconst MemoryTabContent: React.FC<{\n items: MemoryItem[];\n contextSummary?: string;\n onDelete?: (key: string) => void;\n onClearAll?: () => void;\n /** @description 탭 제목 @Todo vibecode */\n title?: string;\n /** @description 빈 상태 메시지 @Todo vibecode */\n emptyMessage?: string;\n /** @description 빈 상태 설명 @Todo vibecode */\n emptyDescription?: string;\n}> = ({ items, contextSummary, onDelete, onClearAll, title = 'AI 메모리', emptyMessage = '저장된 메모리가 없습니다', emptyDescription = '대화가 진행되면 AI가 자동으로 정보를 학습합니다' }) => {\n const [activeFilter, setActiveFilter] = useState<'all' | 'fact' | 'skill' | 'preference'>('all');\n const [expandedId, setExpandedId] = useState<string | null>(null);\n\n const filteredItems = activeFilter === 'all'\n ? items\n : items.filter((item) => item.category === activeFilter);\n\n const formatDate = (timestamp: number): string => {\n const date = new Date(timestamp);\n return date.toLocaleDateString('ko-KR', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n };\n\n return (\n <div>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '24px' }}>\n <h2 style={{ fontSize: '20px', fontWeight: 600, color: 'var(--chatllm-text, #1f2937)', margin: 0 }}>\n {title}\n </h2>\n <span style={{ fontSize: '13px', color: 'var(--chatllm-text-muted, #9ca3af)' }}>\n {items.length}개 항목\n </span>\n </div>\n\n {/* 카테고리 필터 */}\n <div style={{ display: 'flex', gap: '6px', marginBottom: '20px', flexWrap: 'wrap' }}>\n {(['all', 'fact', 'skill', 'preference'] as const).map((tab) => (\n <button\n key={tab}\n onClick={() => setActiveFilter(tab)}\n style={{\n padding: '6px 14px',\n fontSize: '13px',\n fontWeight: activeFilter === tab ? 500 : 400,\n backgroundColor: activeFilter === tab\n ? 'var(--chatllm-primary-light, #dbeafe)'\n : 'var(--chatllm-bg-secondary, #f9fafb)',\n color: activeFilter === tab\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-text-muted, #6b7280)',\n border: '1px solid ' + (activeFilter === tab\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-border, #e5e7eb)'),\n borderRadius: '8px',\n cursor: 'pointer',\n }}\n >\n {tab === 'all' ? '전체' : memoryCategoryLabels[tab]}\n </button>\n ))}\n </div>\n\n {/* 컨텍스트 요약 */}\n {contextSummary && activeFilter === 'all' && (\n <div\n style={{\n padding: '14px',\n marginBottom: '16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '10px',\n borderLeft: '3px solid var(--chatllm-primary, #3b82f6)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '6px', marginBottom: '8px' }}>\n <IconSvg name=\"file-text-line\" size={14} color=\"var(--chatllm-primary, #3b82f6)\" />\n <span style={{ fontSize: '12px', fontWeight: 500, color: 'var(--chatllm-primary, #3b82f6)' }}>\n 대화 요약\n </span>\n </div>\n <p style={{ fontSize: '13px', lineHeight: '1.6', color: 'var(--chatllm-text, #374151)', margin: 0 }}>\n {contextSummary}\n </p>\n </div>\n )}\n\n {/* 메모리 아이템 목록 */}\n {filteredItems.length === 0 ? (\n <div style={{ padding: '40px 16px', textAlign: 'center' }}>\n <IconSvg name=\"robot-line\" size={40} color=\"var(--chatllm-text-muted, #d1d5db)\" />\n <p style={{ fontSize: '14px', color: 'var(--chatllm-text-muted, #9ca3af)', marginTop: '12px' }}>\n {emptyMessage}\n </p>\n <p style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #d1d5db)', marginTop: '4px' }}>\n {emptyDescription}\n </p>\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {filteredItems.map((item) => (\n <div\n key={item.id}\n style={{\n padding: '12px 14px',\n backgroundColor: 'var(--chatllm-content-bg, #ffffff)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '10px',\n cursor: 'pointer',\n transition: 'border-color 0.2s',\n }}\n onClick={() => setExpandedId(expandedId === item.id ? null : item.id)}\n >\n <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between' }}>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>\n {item.category && (\n <span\n style={{\n fontSize: '11px',\n fontWeight: 500,\n padding: '2px 8px',\n backgroundColor: `${memoryCategoryColors[item.category]}15`,\n color: memoryCategoryColors[item.category],\n borderRadius: '4px',\n }}\n >\n {memoryCategoryLabels[item.category]}\n </span>\n )}\n <span style={{ fontSize: '11px', color: 'var(--chatllm-text-muted, #9ca3af)' }}>\n {formatDate(item.timestamp)}\n </span>\n </div>\n <div style={{ fontSize: '13px', fontWeight: 500, color: 'var(--chatllm-text, #1f2937)' }}>\n {item.key}\n </div>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>\n {onDelete && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onDelete(item.key);\n }}\n style={{\n padding: '4px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n opacity: 0.5,\n }}\n aria-label=\"메모리 삭제\"\n >\n <IconSvg name=\"delete-bin-line\" size={14} color=\"var(--chatllm-text-muted, #9ca3af)\" />\n </button>\n )}\n <IconSvg\n name={expandedId === item.id ? 'arrow-up-s-line' : 'arrow-down-s-line'}\n size={16}\n color=\"var(--chatllm-text-muted, #9ca3af)\"\n />\n </div>\n </div>\n\n {expandedId === item.id && (\n <div\n style={{\n marginTop: '12px',\n paddingTop: '12px',\n borderTop: '1px solid var(--chatllm-border-light, #f3f4f6)',\n }}\n >\n <p\n style={{\n fontSize: '13px',\n lineHeight: '1.6',\n color: 'var(--chatllm-text, #374151)',\n margin: 0,\n whiteSpace: 'pre-wrap',\n }}\n >\n {item.value}\n </p>\n </div>\n )}\n </div>\n ))}\n </div>\n )}\n\n {/* 전체 삭제 버튼 */}\n {onClearAll && items.length > 0 && (\n <div style={{ marginTop: '24px', paddingTop: '16px', borderTop: '1px solid var(--chatllm-border, #e5e7eb)' }}>\n <button\n onClick={() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n if (typeof window !== 'undefined' && window.confirm('모든 AI 메모리를 삭제하시겠습니까?')) {\n onClearAll();\n }\n }}\n style={buttonDangerStyle}\n >\n 전체 메모리 삭제\n </button>\n </div>\n )}\n </div>\n );\n};\n\nexport default SettingsModal;\n","/**\n * @description 프로젝트 설정 모달 - 일반/지침/파일 3탭 구조\n * @Todo vibecode - 프로젝트 정보 편집, Instructions, 파일 메타데이터 관리\n */\n\nimport React, { useState, useEffect } from 'react';\nimport { IconSvg } from './Icon';\nimport type { ChatProject, ProjectFile } from '../types';\n\nexport interface ProjectSettingsModalProps {\n isOpen: boolean;\n project: ChatProject | null;\n onClose: () => void;\n onUpdateProject: (projectId: string, data: Partial<ChatProject>) => void;\n onAddFile: (projectId: string, file: File) => void;\n onDeleteFile: (projectId: string, fileId: string) => void;\n /** @Todo vibecode - 프로젝트 삭제 핸들러 (기본 프로젝트 삭제 불가) */\n onDeleteProject?: (projectId: string) => void;\n}\n\n/** @Todo vibecode - 프로젝트 설정 탭 타입 */\ntype ProjectTab = 'general' | 'instructions' | 'files';\n\n/** @Todo vibecode - 프로젝트 색상 프리셋 */\nconst COLOR_PRESETS = [\n '#2563eb', '#7c3aed', '#db2777', '#dc2626',\n '#ea580c', '#d97706', '#16a34a', '#0d9488',\n];\n\nexport const ProjectSettingsModal: React.FC<ProjectSettingsModalProps> = ({\n isOpen,\n project,\n onClose,\n onUpdateProject,\n onAddFile,\n onDeleteFile,\n onDeleteProject,\n}) => {\n const [activeTab, setActiveTab] = useState<ProjectTab>('general');\n const [title, setTitle] = useState('');\n const [description, setDescription] = useState('');\n const [instructions, setInstructions] = useState('');\n const [color, setColor] = useState('#2563eb');\n\n /** @Todo vibecode - 프로젝트 데이터로 폼 초기화 */\n useEffect(() => {\n if (project) {\n setTitle(project.title);\n setDescription(project.description || '');\n setInstructions(project.instructions || '');\n setColor(project.color || '#2563eb');\n }\n }, [project]);\n\n if (!isOpen || !project) return null;\n\n const isDefaultProject = project.id === 'default';\n\n /** @Todo vibecode - 일반 탭 저장 핸들러 */\n const handleSaveGeneral = () => {\n onUpdateProject(project.id, { title, description, color });\n };\n\n /** @Todo vibecode - 지침 탭 저장 핸들러 */\n const handleSaveInstructions = () => {\n onUpdateProject(project.id, { instructions });\n };\n\n /** @Todo vibecode - 파일 업로드 핸들러 */\n const handleFileUpload = () => {\n const input = document.createElement('input');\n input.type = 'file';\n input.multiple = true;\n input.onchange = (e) => {\n const files = (e.target as HTMLInputElement).files;\n if (files) {\n Array.from(files).forEach((file) => onAddFile(project.id, file));\n }\n };\n input.click();\n };\n\n /** @Todo vibecode - 파일 타입별 아이콘 매핑 */\n const getFileIcon = (type: ProjectFile['type']) => {\n const icons = {\n image: 'image-line' as const,\n pdf: 'file-text-line' as const,\n text: 'file-text-line' as const,\n code: 'code-line' as const,\n other: 'file-text-line' as const,\n };\n return icons[type] || ('file-text-line' as const);\n };\n\n /** @Todo vibecode - 파일 크기 포매팅 */\n const formatSize = (bytes?: number): string => {\n if (!bytes) return '';\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n };\n\n const tabStyle = (tab: ProjectTab) => ({\n padding: '8px 16px',\n fontSize: '13px',\n fontWeight: activeTab === tab ? 600 : 400,\n color: activeTab === tab ? 'var(--chatllm-primary, #2563eb)' : 'var(--chatllm-text-muted, #999)',\n borderBottom: activeTab === tab ? '2px solid var(--chatllm-primary, #2563eb)' : '2px solid transparent',\n background: 'none',\n border: 'none',\n borderBottomStyle: 'solid' as const,\n cursor: 'pointer',\n fontFamily: 'inherit',\n });\n\n return (\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 100,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'rgba(0,0,0,0.4)',\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget) onClose();\n }}\n >\n <div\n style={{\n backgroundColor: 'var(--chatllm-content-bg, #fff)',\n borderRadius: '12px',\n width: '520px',\n maxWidth: '90vw',\n maxHeight: '80vh',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n }}\n >\n {/* 헤더 */}\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: '20px 24px 0',\n }}\n >\n <h2 style={{ fontSize: '16px', fontWeight: 600, margin: 0, color: 'var(--chatllm-text, #1a1a1a)' }}>\n 프로젝트 설정\n </h2>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n display: 'flex',\n alignItems: 'center',\n }}\n aria-label='닫기'\n >\n <IconSvg name='close-line' size={20} color='var(--chatllm-text-muted, #999)' />\n </button>\n </div>\n\n {/* 탭 */}\n <div\n style={{\n display: 'flex',\n gap: '4px',\n padding: '16px 24px 0',\n borderBottom: '1px solid var(--chatllm-border, #e0e0e0)',\n }}\n >\n <button onClick={() => setActiveTab('general')} style={tabStyle('general')}>\n 일반\n </button>\n <button onClick={() => setActiveTab('instructions')} style={tabStyle('instructions')}>\n 지침\n </button>\n <button onClick={() => setActiveTab('files')} style={tabStyle('files')}>\n 파일 ({project.files.length})\n </button>\n </div>\n\n {/* 탭 콘텐츠 */}\n <div style={{ padding: '24px', overflowY: 'auto', flex: 1 }}>\n {/* 일반 탭 */}\n {activeTab === 'general' && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>\n <div>\n <label style={{ display: 'block', fontSize: '13px', fontWeight: 500, marginBottom: '6px', color: 'var(--chatllm-text, #1a1a1a)' }}>\n 프로젝트 이름\n </label>\n <input\n type='text'\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder='프로젝트 이름'\n disabled={isDefaultProject}\n style={{\n width: '100%',\n padding: '8px 12px',\n borderRadius: '6px',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n fontSize: '14px',\n fontFamily: 'inherit',\n backgroundColor: isDefaultProject ? 'var(--chatllm-bg-tertiary, #f5f5f5)' : 'transparent',\n boxSizing: 'border-box',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n />\n </div>\n <div>\n <label style={{ display: 'block', fontSize: '13px', fontWeight: 500, marginBottom: '6px', color: 'var(--chatllm-text, #1a1a1a)' }}>\n 설명\n </label>\n <textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder='프로젝트에 대한 간단한 설명'\n rows={3}\n style={{\n width: '100%',\n padding: '8px 12px',\n borderRadius: '6px',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n fontSize: '14px',\n fontFamily: 'inherit',\n resize: 'vertical',\n boxSizing: 'border-box',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n />\n </div>\n <div>\n <label style={{ display: 'block', fontSize: '13px', fontWeight: 500, marginBottom: '6px', color: 'var(--chatllm-text, #1a1a1a)' }}>\n 색상\n </label>\n <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>\n {COLOR_PRESETS.map((c) => (\n <button\n key={c}\n onClick={() => setColor(c)}\n style={{\n width: '28px',\n height: '28px',\n borderRadius: '50%',\n backgroundColor: c,\n border: color === c ? '3px solid var(--chatllm-text, #1a1a1a)' : '2px solid transparent',\n cursor: 'pointer',\n padding: 0,\n }}\n aria-label={`색상 ${c}`}\n />\n ))}\n </div>\n </div>\n <div style={{ display: 'flex', gap: '8px', justifyContent: 'flex-end', marginTop: '8px' }}>\n {!isDefaultProject && onDeleteProject && (\n <button\n onClick={() => {\n /** @Todo vibecode - SSR 호환: window 가드 추가 */\n if (typeof window !== 'undefined' && window.confirm(`\"${project.title}\" 프로젝트와 소속 대화가 모두 삭제됩니다. 계속하시겠습니까?`)) {\n onDeleteProject(project.id);\n onClose();\n }\n }}\n style={{\n padding: '8px 16px',\n borderRadius: '6px',\n border: '1px solid #dc2626',\n backgroundColor: 'transparent',\n color: '#dc2626',\n fontSize: '13px',\n cursor: 'pointer',\n fontFamily: 'inherit',\n marginRight: 'auto',\n }}\n >\n 프로젝트 삭제\n </button>\n )}\n <button\n onClick={handleSaveGeneral}\n style={{\n padding: '8px 20px',\n borderRadius: '6px',\n border: 'none',\n backgroundColor: 'var(--chatllm-primary, #2563eb)',\n color: '#fff',\n fontSize: '13px',\n fontWeight: 500,\n cursor: 'pointer',\n fontFamily: 'inherit',\n }}\n >\n 저장\n </button>\n </div>\n </div>\n )}\n\n {/* 지침 탭 */}\n {activeTab === 'instructions' && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>\n <p style={{ fontSize: '13px', color: 'var(--chatllm-text-muted, #999)', margin: 0 }}>\n 이 프로젝트의 모든 대화에서 AI가 따라야 할 지침을 입력하세요.\n </p>\n <textarea\n value={instructions}\n onChange={(e) => setInstructions(e.target.value)}\n placeholder={'예:\\n- 너는 프로덕트 매니저 역할이야\\n- 항상 실행 가능한 액션 아이템을 제시해\\n- 기술적인 설명은 최소화해'}\n rows={12}\n style={{\n width: '100%',\n padding: '12px',\n borderRadius: '6px',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n fontSize: '14px',\n fontFamily: 'inherit',\n resize: 'vertical',\n lineHeight: 1.6,\n boxSizing: 'border-box',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n />\n <div style={{ display: 'flex', justifyContent: 'flex-end' }}>\n <button\n onClick={handleSaveInstructions}\n style={{\n padding: '8px 20px',\n borderRadius: '6px',\n border: 'none',\n backgroundColor: 'var(--chatllm-primary, #2563eb)',\n color: '#fff',\n fontSize: '13px',\n fontWeight: 500,\n cursor: 'pointer',\n fontFamily: 'inherit',\n }}\n >\n 저장\n </button>\n </div>\n </div>\n )}\n\n {/* 파일 탭 */}\n {activeTab === 'files' && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>\n <p style={{ fontSize: '13px', color: 'var(--chatllm-text-muted, #999)', margin: 0 }}>\n 프로젝트 컨텍스트로 사용할 파일을 관리합니다.\n </p>\n <button\n onClick={handleFileUpload}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n padding: '6px 14px',\n borderRadius: '6px',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n backgroundColor: 'transparent',\n fontSize: '13px',\n cursor: 'pointer',\n fontFamily: 'inherit',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n >\n <IconSvg name='upload-line' size={14} />\n 업로드\n </button>\n </div>\n\n {project.files.length === 0 ? (\n <div\n style={{\n padding: '32px',\n textAlign: 'center',\n color: 'var(--chatllm-text-muted, #999)',\n fontSize: '13px',\n border: '1px dashed var(--chatllm-border, #e0e0e0)',\n borderRadius: '8px',\n }}\n >\n 아직 파일이 없습니다\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\n {project.files.map((file) => (\n <div\n key={file.id}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 12px',\n border: '1px solid var(--chatllm-border, #e0e0e0)',\n borderRadius: '6px',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '10px', overflow: 'hidden' }}>\n <IconSvg name={getFileIcon(file.type)} size={18} color='var(--chatllm-text-muted, #999)' />\n <div style={{ overflow: 'hidden' }}>\n <div\n style={{\n fontSize: '13px',\n fontWeight: 500,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n color: 'var(--chatllm-text, #1a1a1a)',\n }}\n >\n {file.name}\n </div>\n <div style={{ fontSize: '11px', color: 'var(--chatllm-text-muted, #999)' }}>\n {file.type}{formatSize(file.size) ? ` · ${formatSize(file.size)}` : ''}\n </div>\n </div>\n </div>\n <button\n onClick={() => onDeleteFile(project.id, file.id)}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n opacity: 0.5,\n transition: 'opacity 0.1s',\n display: 'flex',\n alignItems: 'center',\n }}\n onMouseEnter={(e) => { (e.currentTarget as HTMLElement).style.opacity = '1'; }}\n onMouseLeave={(e) => { (e.currentTarget as HTMLElement).style.opacity = '0.5'; }}\n aria-label={`${file.name} 삭제`}\n >\n <IconSvg name='delete-bin-line' size={16} color='#dc2626' />\n </button>\n </div>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n","/**\n * @description AI 면책조항 모달 컴포넌트\n * @Todo vibecode - 하단 \"AI 채팅은 실수를 할 수 있습니다\" 클릭 시 노출\n */\n\nimport React from 'react';\nimport { IconSvg } from './Icon';\n\nexport interface DisclaimerModalProps {\n /** 모달 열림 상태 */\n isOpen: boolean;\n /** 모달 닫기 핸들러 */\n onClose: () => void;\n}\n\n/** @Todo vibecode - 강조 텍스트 인라인 스타일 */\nconst highlightStyle: React.CSSProperties = {\n color: 'var(--chatllm-text, #1e293b)',\n fontWeight: 600,\n};\n\n/** @Todo vibecode - AI 한계 안내 모달 (AI 1인칭 시점, 감성적 톤 + 핵심 강조) */\nexport const DisclaimerModal: React.FC<DisclaimerModalProps> = ({ isOpen, onClose }) => {\n if (!isOpen) return null;\n\n return (\n <div\n className=\"chatllm-disclaimer-overlay\"\n style={{\n position: 'fixed',\n inset: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.3)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 1000,\n }}\n onClick={onClose}\n >\n <div\n className=\"chatllm-disclaimer-modal\"\n style={{\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n borderRadius: '16px',\n width: '100%',\n maxWidth: '560px',\n maxHeight: '80vh',\n margin: '16px',\n boxShadow: '0 20px 60px rgba(0, 0, 0, 0.15)',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* 헤더 */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '20px 24px 16px',\n borderBottom: '1px solid var(--chatllm-border, #e5e7eb)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <IconSvg name=\"error-warning-line\" size={20} color=\"var(--chatllm-primary, #4A90E2)\" />\n <h2\n style={{\n margin: 0,\n fontSize: '16px',\n fontWeight: 600,\n color: 'var(--chatllm-text, #1e293b)',\n }}\n >\n 안녕하세요, 저는 AI입니다\n </h2>\n </div>\n <button\n onClick={onClose}\n aria-label=\"닫기\"\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '4px',\n borderRadius: '6px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg name=\"close-line\" size={20} color=\"var(--chatllm-text-muted, #64748b)\" />\n </button>\n </div>\n\n {/* 본문 */}\n <div\n className=\"chatllm-scrollbar\"\n style={{\n padding: '20px 24px 24px',\n overflow: 'auto',\n fontSize: '14px',\n lineHeight: 1.8,\n color: 'var(--chatllm-text-secondary, #475569)',\n }}\n >\n <p style={{ margin: '0 0 16px' }}>\n 저는 여러분의 질문에 <span style={highlightStyle}>최선의 답변을 드리기 위해 항상 노력</span>하고\n 있어요. 하지만 솔직하게 말씀드리면, 저도 때때로 실수를 하거나 정확하지 않은 답변을 드릴 수 있습니다.\n </p>\n\n {/* 핵심 안내 박스 */}\n <div\n style={{\n padding: '14px 16px',\n backgroundColor: 'var(--chatllm-primary-light, #eff6ff)',\n borderRadius: '10px',\n borderLeft: '3px solid var(--chatllm-primary, #4A90E2)',\n marginBottom: '16px',\n fontSize: '13px',\n lineHeight: 1.7,\n }}\n >\n <p style={{ margin: '0 0 8px', fontWeight: 600, color: 'var(--chatllm-text, #1e293b)' }}>\n 제가 이런 실수를 할 수 있어요\n </p>\n <ul style={{ margin: 0, paddingLeft: '18px', display: 'flex', flexDirection: 'column', gap: '4px' }}>\n <li>최신 정보를 반영하지 못한 답변을 드리는 경우</li>\n <li>그럴듯하게 들리지만 실제로는 정확하지 않은 내용</li>\n <li>실제로 존재하지 않는 출처나 인용을 만들어내는 경우</li>\n </ul>\n </div>\n\n <p style={{ margin: '0 0 16px' }}>\n 이런 현상을 <span style={highlightStyle}>&apos;환각(Hallucination)&apos;</span>이라고 부르는데요,\n 아직은 저와 같은 AI가 가진 근본적인 한계예요.\n 제 답변이 아무리 자연스러워 보여도, <span style={highlightStyle}>한 번 더 확인</span>해 주시면 감사하겠습니다.\n </p>\n\n <p style={{ margin: '0 0 16px' }}>\n <span style={highlightStyle}>제 답변은 참고 자료</span>로 활용해 주시고,\n 중요한 판단을 내리실 때는 꼭 추가로 확인해 주세요.\n 저도 더 정확한 답변을 드리기 위해 계속 발전하고 있습니다.\n </p>\n\n <p style={{ margin: '0 0 16px' }}>\n 제가 웹 검색 결과를 알려드릴 때도,{' '}\n <span style={highlightStyle}>원본 출처를 직접 확인</span>해 보시는 걸 추천드려요.\n 요약 과정에서 놓칠 수 있는 중요한 맥락이 원본에 담겨 있을 수 있거든요.\n </p>\n\n {/* 피드백 안내 */}\n <div\n style={{\n padding: '14px 16px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '10px',\n fontSize: '13px',\n lineHeight: 1.7,\n textAlign: 'center',\n }}\n >\n <p style={{ margin: 0 }}>\n 저에 대한 의견이나 개선 제안이 있으시다면{' '}\n <a\n href=\"mailto:info@gendive.ai\"\n style={{\n color: 'var(--chatllm-primary, #4A90E2)',\n textDecoration: 'none',\n fontWeight: 600,\n }}\n >\n info@gendive.ai\n </a>\n 로 알려주세요.\n <br />\n 여러분의 피드백 하나하나가 제가 성장하는 데 큰 힘이 됩니다.\n </p>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default DisclaimerModal;\n","/**\n * @description 심층연구 (Deep Research) 훅\n * @Todo vibecode - Perplexity 스타일 에이전트 기반 심층연구 기능\n *\n * 4단계 아키텍처:\n * 1. 쿼리 분석 - 질문 유형 판단, 서브토픽 분해\n * 2. 병렬 서브에이전트 실행 - 검색 API 호출, 결과 수집\n * 3. 충분성 판단 - 커버리지 평가, 필요시 추가 검색\n * 4. 보고서 생성 - 구조화된 보고서 + 인라인 인용\n */\n\nimport { useState, useCallback, useRef } from 'react';\nimport type {\n SearchResult,\n DeepResearchProgress,\n SubAgentProgress,\n SourceItem,\n} from '../types';\n\n/**\n * @description useDeepResearch 훅 옵션\n */\nexport interface UseDeepResearchOptions {\n /** 웹 검색 API 호출 (필수) */\n onWebSearch: (query: string) => Promise<SearchResult[]>;\n /** 페이지 본문 추출 (선택) */\n onExtractContent?: (url: string) => Promise<string>;\n /** API 엔드포인트 */\n apiEndpoint: string;\n /** API 키 */\n apiKey?: string;\n /** 사용할 모델 */\n model: string;\n /** 프로바이더 */\n provider: string;\n}\n\n/**\n * @description 리서치 플랜 타입\n */\ninterface ResearchPlan {\n questionType: 'factCheck' | 'comparison' | 'comprehensive';\n topics: string[];\n searchQueries: string[];\n}\n\n/**\n * @description 서브에이전트 결과 타입\n */\ninterface SubAgentResult {\n topic: string;\n sources: SearchResult[];\n summary: string;\n}\n\n/**\n * @description 보고서 생성 프롬프트\n */\nconst REPORT_GENERATION_PROMPT = `당신은 리서치 보고서 작성 전문가입니다.\n\n<collected_sources>\n{sources_json}\n</collected_sources>\n\n<user_question>\n{question}\n</user_question>\n\n<format_rules>\n1. 핵심 요약 2-3문장으로 시작 (헤더 없이)\n2. ## 헤더로 섹션 구분\n3. 문장 끝에 인라인 인용 [1][2] 형태로 출처 표시\n4. 종합 결론으로 마무리\n5. 이모지 사용 금지\n</format_rules>\n\n<structure>\n[요약 2-3문장]\n\n## 상세 분석\n깊이 있는 분석 [1][2]\n\n## 주요 발견\n- 핵심 포인트 1 [3]\n- 핵심 포인트 2 [4]\n\n## 결론\n종합적인 결론\n</structure>`;\n\n/**\n * @description 쿼리 분석 프롬프트\n */\nconst QUERY_ANALYSIS_PROMPT = `사용자 질문을 분석하여 심층연구를 위한 검색 계획을 수립하세요.\n\n<user_question>\n{question}\n</user_question>\n\n응답은 반드시 다음 JSON 형식으로만 작성하세요:\n{\n \"questionType\": \"factCheck\" | \"comparison\" | \"comprehensive\",\n \"topics\": [\"서브토픽1\", \"서브토픽2\", \"서브토픽3\"],\n \"searchQueries\": [\"검색어1\", \"검색어2\", \"검색어3\", \"검색어4\", \"검색어5\"]\n}\n\n규칙:\n- topics: 3-5개의 핵심 서브토픽\n- searchQueries: 5-8개의 다양한 검색 쿼리 (한국어/영어 혼합)\n- JSON 외 다른 텍스트 출력 금지`;\n\n/**\n * @description useDeepResearch 훅\n */\nexport const useDeepResearch = (options: UseDeepResearchOptions) => {\n const { onWebSearch, onExtractContent, apiEndpoint, apiKey, model, provider } = options;\n\n const [isResearching, setIsResearching] = useState(false);\n const [progress, setProgress] = useState<DeepResearchProgress | null>(null);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n /**\n * @description LLM API 호출 헬퍼\n */\n const callLLM = useCallback(\n async (prompt: string, stream = false): Promise<string | ReadableStream> => {\n const response = await fetch(apiEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(apiKey && { Authorization: `Bearer ${apiKey}` }),\n },\n body: JSON.stringify({\n model,\n provider,\n messages: [{ role: 'user', content: prompt }],\n stream,\n }),\n signal: abortControllerRef.current?.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API 오류: ${response.status}`);\n }\n\n if (stream) {\n return response.body as ReadableStream;\n }\n\n const data = await response.json();\n return data.choices?.[0]?.message?.content || data.content || '';\n },\n [apiEndpoint, apiKey, model, provider]\n );\n\n /**\n * @description 1단계: 쿼리 분석\n */\n const analyzeQuery = useCallback(\n async (query: string): Promise<ResearchPlan> => {\n const prompt = QUERY_ANALYSIS_PROMPT.replace('{question}', query);\n const response = (await callLLM(prompt)) as string;\n\n try {\n // JSON 파싱 시도\n const jsonMatch = response.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n return JSON.parse(jsonMatch[0]) as ResearchPlan;\n }\n } catch {\n // 파싱 실패 시 기본값\n }\n\n // 기본 플랜 반환\n return {\n questionType: 'comprehensive',\n topics: [query],\n searchQueries: [query, `${query} 최신`, `${query} 상세`],\n };\n },\n [callLLM]\n );\n\n /**\n * @description 2단계: 서브에이전트 실행\n */\n const runSubAgent = useCallback(\n async (\n topic: string,\n queries: string[],\n agentId: string,\n updateProgress: (update: Partial<SubAgentProgress>) => void\n ): Promise<SubAgentResult> => {\n updateProgress({ status: 'searching', searchCount: 0, resultsCount: 0 });\n\n const allResults: SearchResult[] = [];\n let searchCount = 0;\n\n // 관련 쿼리로 검색\n for (const query of queries.slice(0, 3)) {\n try {\n searchCount++;\n updateProgress({ searchCount });\n\n const results = await onWebSearch(query);\n allResults.push(...results);\n\n updateProgress({ resultsCount: allResults.length });\n\n // 충분한 결과가 있으면 중단\n if (allResults.length >= 10) break;\n } catch (error) {\n console.error(`검색 오류 (${query}):`, error);\n }\n }\n\n // 본문 추출 (옵션)\n if (onExtractContent && allResults.length > 0) {\n updateProgress({ status: 'extracting' });\n\n const topResults = allResults.slice(0, 5);\n await Promise.all(\n topResults.map(async (result) => {\n try {\n const content = await onExtractContent(result.url);\n result.content = content.slice(0, 2000); // 최대 2000자\n } catch {\n // 추출 실패 시 스니펫 사용\n }\n })\n );\n }\n\n updateProgress({ status: 'done' });\n\n return {\n topic,\n sources: allResults,\n summary: '',\n };\n },\n [onWebSearch, onExtractContent]\n );\n\n /**\n * @description 4단계: 보고서 생성 (스트리밍)\n */\n const generateReport = useCallback(\n async (\n query: string,\n results: SubAgentResult[],\n onStreamContent: (chunk: string) => void\n ): Promise<{ content: string; sources: SourceItem[] }> => {\n // 소스 목록 생성\n const allSources: SourceItem[] = [];\n const sourcesForPrompt: { index: number; title: string; url: string; snippet: string }[] = [];\n\n results.forEach((result) => {\n result.sources.forEach((source) => {\n const index = allSources.length + 1;\n allSources.push({\n id: `source-${index}`,\n title: source.title,\n url: source.url,\n snippet: source.snippet,\n });\n sourcesForPrompt.push({\n index,\n title: source.title,\n url: source.url,\n snippet: source.content || source.snippet,\n });\n });\n });\n\n const prompt = REPORT_GENERATION_PROMPT.replace(\n '{sources_json}',\n JSON.stringify(sourcesForPrompt, null, 2)\n ).replace('{question}', query);\n\n // 스트리밍 응답 처리\n const stream = (await callLLM(prompt, true)) as ReadableStream;\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let fullContent = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n\n // SSE 형식 파싱\n const lines = chunk.split('\\n');\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n\n try {\n const parsed = JSON.parse(data);\n const content =\n parsed.choices?.[0]?.delta?.content || parsed.delta?.content || '';\n if (content) {\n fullContent += content;\n onStreamContent(content);\n }\n } catch {\n // JSON 파싱 실패 시 원본 데이터 사용\n if (data && data !== '[DONE]') {\n fullContent += data;\n onStreamContent(data);\n }\n }\n }\n }\n }\n\n return { content: fullContent, sources: allSources };\n },\n [callLLM]\n );\n\n /**\n * @description 심층연구 실행\n */\n const runDeepResearch = useCallback(\n async (\n query: string,\n onStreamContent: (chunk: string) => void\n ): Promise<{ content: string; sources: SourceItem[] }> => {\n abortControllerRef.current = new AbortController();\n setIsResearching(true);\n\n const subAgentStates: Map<string, SubAgentProgress> = new Map();\n\n const updateSubAgentProgress = (id: string, update: Partial<SubAgentProgress>) => {\n const current = subAgentStates.get(id) || {\n id,\n topic: '',\n status: 'pending' as const,\n searchCount: 0,\n resultsCount: 0,\n };\n const updated = { ...current, ...update };\n subAgentStates.set(id, updated);\n\n setProgress((prev) => ({\n phase: prev?.phase || 'researching',\n phaseLabel: prev?.phaseLabel || '정보 수집 중...',\n subAgents: Array.from(subAgentStates.values()),\n totalSources: Array.from(subAgentStates.values()).reduce(\n (sum, agent) => sum + agent.resultsCount,\n 0\n ),\n }));\n };\n\n try {\n // 1단계: 쿼리 분석\n setProgress({\n phase: 'analyzing',\n phaseLabel: '질문 분석 중...',\n subAgents: [],\n totalSources: 0,\n });\n\n const plan = await analyzeQuery(query);\n\n // 2단계: 병렬 서브에이전트 실행\n plan.topics.forEach((topic, index) => {\n const agentId = `agent-${index}`;\n subAgentStates.set(agentId, {\n id: agentId,\n topic,\n status: 'pending',\n searchCount: 0,\n resultsCount: 0,\n });\n });\n\n setProgress({\n phase: 'researching',\n phaseLabel: '정보 수집 중...',\n subAgents: Array.from(subAgentStates.values()),\n totalSources: 0,\n });\n\n const results = await Promise.all(\n plan.topics.map((topic, index) => {\n const agentId = `agent-${index}`;\n // 각 토픽에 관련된 쿼리 필터링\n const relatedQueries = plan.searchQueries.filter(\n (q) =>\n q.toLowerCase().includes(topic.toLowerCase()) ||\n topic.toLowerCase().includes(q.toLowerCase().split(' ')[0])\n );\n const queries =\n relatedQueries.length > 0 ? relatedQueries : [topic, ...plan.searchQueries.slice(0, 2)];\n\n return runSubAgent(topic, queries, agentId, (update) =>\n updateSubAgentProgress(agentId, update)\n );\n })\n );\n\n // 3단계: 충분성 판단 (현재는 단순화)\n setProgress((prev) => ({\n ...prev!,\n phase: 'evaluating',\n phaseLabel: '결과 평가 중...',\n }));\n\n const totalSources = results.reduce((sum, r) => sum + r.sources.length, 0);\n\n // 결과가 부족하면 추가 검색\n if (totalSources < 5) {\n const additionalResult = await runSubAgent(\n query,\n [query, `${query} 정보`, `${query} 최신 뉴스`],\n 'agent-additional',\n (update) => updateSubAgentProgress('agent-additional', update)\n );\n results.push(additionalResult);\n }\n\n // 4단계: 보고서 생성\n setProgress((prev) => ({\n ...prev!,\n phase: 'generating',\n phaseLabel: '보고서 작성 중...',\n }));\n\n const report = await generateReport(query, results, onStreamContent);\n\n setProgress((prev) => ({\n ...prev!,\n phase: 'done',\n phaseLabel: '완료',\n }));\n\n return report;\n } catch (error) {\n if ((error as Error).name === 'AbortError') {\n throw new Error('심층연구가 취소되었습니다.');\n }\n throw error;\n } finally {\n setIsResearching(false);\n abortControllerRef.current = null;\n }\n },\n [analyzeQuery, runSubAgent, generateReport]\n );\n\n /**\n * @description 심층연구 중단\n */\n const stopResearch = useCallback(() => {\n abortControllerRef.current?.abort();\n setIsResearching(false);\n setProgress(null);\n }, []);\n\n return {\n runDeepResearch,\n stopResearch,\n isResearching,\n progress,\n };\n};\n\nexport default useDeepResearch;\n","/**\n * @description 빈 상태 컴포넌트 - Modern Canvas 디자인\n * @Todo vibecode - v0.11.0 새 디자인 시스템 적용 (Landing 화면)\n */\n\nimport React from 'react';\nimport { IconSvg, IconName } from './Icon';\nimport type { EmptyStateProps, ActionItem } from '../types';\n\nexport const EmptyState: React.FC<EmptyStateProps> = ({\n greeting,\n templates = [],\n onTemplateClick,\n actions = [],\n onActionSelect,\n}) => {\n const getActionIcon = (icon: string): IconName => {\n const iconMap: Record<string, IconName> = {\n search: 'search-line',\n image: 'image-line',\n code: 'code-s-slash-line',\n document: 'file-text-line',\n };\n return iconMap[icon] || 'sparkling-line';\n };\n\n const hasContent = actions.length > 0 || templates.length > 0;\n\n return (\n <div\n className=\"chatllm-empty-state\"\n style={{\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: hasContent ? 'center' : 'flex-end',\n padding: '48px 24px',\n paddingBottom: hasContent ? '200px' : '32px',\n textAlign: 'center',\n }}\n >\n {/* Logo */}\n <div\n className=\"chatllm-sheet\"\n style={{\n width: '64px',\n height: '64px',\n borderRadius: '16px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginBottom: '32px',\n color: 'var(--chatllm-primary)',\n }}\n >\n <IconSvg name=\"chat-1-line\" size={40} />\n </div>\n\n {/* Greeting */}\n <h1\n style={{\n fontSize: '30px',\n fontWeight: 700,\n color: 'var(--chatllm-text)',\n marginBottom: hasContent ? '40px' : '0',\n lineHeight: 1.3,\n }}\n >\n How can I help you today?\n </h1>\n\n {/* Quick Action Buttons (Pills) */}\n {(actions.length > 0 || templates.length > 0) && (\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n justifyContent: 'center',\n gap: '12px',\n maxWidth: '800px',\n marginBottom: '48px',\n }}\n >\n {/* Actions as pills */}\n {actions.map((action) => (\n <button\n key={action.id}\n onClick={() => onActionSelect?.(action)}\n className=\"chatllm-btn-secondary\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '12px 20px',\n fontSize: '14px',\n fontWeight: 500,\n }}\n >\n <IconSvg\n name={getActionIcon(action.icon)}\n size={18}\n color=\"var(--chatllm-primary)\"\n />\n {action.label}\n </button>\n ))}\n\n {/* Templates as pills */}\n {templates.slice(0, 4).map((template) => (\n <button\n key={template.id}\n onClick={() => onTemplateClick(template)}\n className=\"chatllm-btn-secondary\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '12px 20px',\n fontSize: '14px',\n fontWeight: 500,\n }}\n >\n <IconSvg\n name=\"sparkling-line\"\n size={18}\n color=\"var(--chatllm-primary)\"\n />\n {template.title}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n};\n\nexport default EmptyState;\n","/**\n * @description 메모리 패널 컴포넌트\n * 저장된 메모리, 컨텍스트 요약, 학습된 정보 조회\n */\n\nimport React, { useState } from 'react';\nimport { IconSvg } from './Icon';\n\nexport interface MemoryItem {\n id: string;\n key: string;\n value: string;\n category?: 'context' | 'preference' | 'skill' | 'fact';\n timestamp: number;\n}\n\nexport interface MemoryPanelProps {\n /** 메모리 아이템 목록 */\n items: MemoryItem[];\n /** 컨텍스트 요약 (압축된 대화) */\n contextSummary?: string;\n /** 삭제 핸들러 */\n onDelete?: (id: string) => void;\n /** 전체 삭제 핸들러 */\n onClearAll?: () => void;\n /** 패널 열림 상태 */\n isOpen: boolean;\n /** 패널 토글 */\n onToggle: () => void;\n}\n\nconst categoryLabels: Record<string, string> = {\n fact: '사용자 정보',\n skill: '전문 분야/기술',\n preference: '사용자 선호',\n};\n\nconst categoryColors: Record<string, string> = {\n fact: '#f59e0b',\n skill: '#10b981',\n preference: '#8b5cf6',\n};\n\nexport const MemoryPanel: React.FC<MemoryPanelProps> = ({\n items,\n contextSummary,\n onDelete,\n onClearAll,\n isOpen,\n onToggle,\n}) => {\n const [expandedId, setExpandedId] = useState<string | null>(null);\n const [activeTab, setActiveTab] = useState<'all' | 'fact' | 'skill' | 'preference'>('all');\n\n const filteredItems = activeTab === 'all'\n ? items\n : items.filter(item => item.category === activeTab);\n\n const formatDate = (timestamp: number): string => {\n const date = new Date(timestamp);\n return date.toLocaleDateString('ko-KR', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n };\n\n if (!isOpen) {\n return (\n <button\n onClick={onToggle}\n style={{\n position: 'fixed',\n right: '16px',\n bottom: '100px',\n width: '48px',\n height: '48px',\n borderRadius: '50%',\n backgroundColor: 'var(--chatllm-primary, #3b82f6)',\n border: 'none',\n boxShadow: '0 4px 12px rgba(59, 130, 246, 0.3)',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 100,\n }}\n >\n <IconSvg name=\"robot-line\" size={24} color=\"#ffffff\" />\n </button>\n );\n }\n\n return (\n <div\n className=\"chatllm-memory-panel\"\n style={{\n position: 'fixed',\n right: '16px',\n bottom: '16px',\n width: '380px',\n maxHeight: '70vh',\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n borderRadius: '16px',\n boxShadow: '0 8px 32px rgba(0, 0, 0, 0.12)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n zIndex: 100,\n }}\n >\n {/* Header */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '16px',\n borderBottom: '1px solid var(--chatllm-border, #e5e7eb)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>\n <div\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '8px',\n backgroundColor: 'var(--chatllm-primary-light, #dbeafe)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <IconSvg name=\"robot-line\" size={18} color=\"var(--chatllm-primary, #3b82f6)\" />\n </div>\n <div>\n <div style={{ fontSize: '15px', fontWeight: 600, color: 'var(--chatllm-text, #1f2937)' }}>\n AI 메모리\n </div>\n <div style={{ fontSize: '12px', color: 'var(--chatllm-text-muted, #9ca3af)' }}>\n {items.length}개 항목\n </div>\n </div>\n </div>\n <div style={{ display: 'flex', gap: '4px' }}>\n {onClearAll && items.length > 0 && (\n <button\n onClick={onClearAll}\n style={{\n padding: '8px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n }}\n title=\"전체 삭제\"\n >\n <IconSvg name=\"delete-bin-line\" size={18} color=\"var(--chatllm-text-muted, #9ca3af)\" />\n </button>\n )}\n <button\n onClick={onToggle}\n style={{\n padding: '8px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n }}\n >\n <IconSvg name=\"close-line\" size={18} color=\"var(--chatllm-text-muted, #9ca3af)\" />\n </button>\n </div>\n </div>\n\n {/* Tabs */}\n <div\n style={{\n display: 'flex',\n gap: '4px',\n padding: '12px 16px',\n borderBottom: '1px solid var(--chatllm-border-light, #f3f4f6)',\n overflowX: 'auto',\n }}\n >\n {(['all', 'fact', 'skill', 'preference'] as const).map((tab) => (\n <button\n key={tab}\n onClick={() => setActiveTab(tab)}\n style={{\n padding: '6px 12px',\n fontSize: '13px',\n fontWeight: activeTab === tab ? 500 : 400,\n backgroundColor: activeTab === tab\n ? 'var(--chatllm-primary-light, #dbeafe)'\n : 'transparent',\n color: activeTab === tab\n ? 'var(--chatllm-primary, #3b82f6)'\n : 'var(--chatllm-text-muted, #6b7280)',\n border: 'none',\n borderRadius: '6px',\n cursor: 'pointer',\n whiteSpace: 'nowrap',\n }}\n >\n {tab === 'all' ? '전체' : categoryLabels[tab]}\n </button>\n ))}\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, overflow: 'auto', padding: '12px' }}>\n {/* Context Summary */}\n {contextSummary && activeTab === 'all' && (\n <div\n style={{\n padding: '12px',\n marginBottom: '12px',\n backgroundColor: 'var(--chatllm-bg-secondary, #f9fafb)',\n borderRadius: '10px',\n borderLeft: '3px solid var(--chatllm-primary, #3b82f6)',\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n marginBottom: '8px',\n }}\n >\n <IconSvg name=\"file-text-line\" size={14} color=\"var(--chatllm-primary, #3b82f6)\" />\n <span style={{ fontSize: '12px', fontWeight: 500, color: 'var(--chatllm-primary, #3b82f6)' }}>\n 대화 요약\n </span>\n </div>\n <p\n style={{\n fontSize: '13px',\n lineHeight: '1.6',\n color: 'var(--chatllm-text, #374151)',\n margin: 0,\n }}\n >\n {contextSummary}\n </p>\n </div>\n )}\n\n {/* Memory Items */}\n {filteredItems.length === 0 ? (\n <div\n style={{\n padding: '32px 16px',\n textAlign: 'center',\n color: 'var(--chatllm-text-muted, #9ca3af)',\n }}\n >\n <IconSvg name=\"robot-line\" size={32} color=\"var(--chatllm-text-muted, #d1d5db)\" />\n <p style={{ fontSize: '14px', marginTop: '12px' }}>저장된 메모리가 없습니다</p>\n </div>\n ) : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {filteredItems.map((item) => (\n <div\n key={item.id}\n style={{\n padding: '12px',\n backgroundColor: 'var(--chatllm-bg, #ffffff)',\n border: '1px solid var(--chatllm-border, #e5e7eb)',\n borderRadius: '10px',\n cursor: 'pointer',\n transition: 'all 0.2s',\n }}\n onClick={() => setExpandedId(expandedId === item.id ? null : item.id)}\n >\n {/* Item Header */}\n <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between' }}>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>\n {item.category && (\n <span\n style={{\n fontSize: '11px',\n fontWeight: 500,\n padding: '2px 8px',\n backgroundColor: `${categoryColors[item.category]}15`,\n color: categoryColors[item.category],\n borderRadius: '4px',\n }}\n >\n {categoryLabels[item.category]}\n </span>\n )}\n <span style={{ fontSize: '11px', color: 'var(--chatllm-text-muted, #9ca3af)' }}>\n {formatDate(item.timestamp)}\n </span>\n </div>\n <div\n style={{\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--chatllm-text, #1f2937)',\n }}\n >\n {item.key}\n </div>\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>\n {onDelete && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onDelete(item.id);\n }}\n style={{\n padding: '4px',\n backgroundColor: 'transparent',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n opacity: 0.5,\n }}\n >\n <IconSvg name=\"delete-bin-line\" size={14} color=\"var(--chatllm-text-muted, #9ca3af)\" />\n </button>\n )}\n <IconSvg\n name={expandedId === item.id ? 'arrow-up-s-line' : 'arrow-down-s-line'}\n size={16}\n color=\"var(--chatllm-text-muted, #9ca3af)\"\n />\n </div>\n </div>\n\n {/* Expanded Content */}\n {expandedId === item.id && (\n <div\n style={{\n marginTop: '12px',\n paddingTop: '12px',\n borderTop: '1px solid var(--chatllm-border-light, #f3f4f6)',\n }}\n >\n <p\n style={{\n fontSize: '13px',\n lineHeight: '1.6',\n color: 'var(--chatllm-text, #374151)',\n margin: 0,\n whiteSpace: 'pre-wrap',\n }}\n >\n {item.value}\n </p>\n </div>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default MemoryPanel;\n"],"mappings":"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","names":["React","useState","useRef","useCallback","useEffect","useMemo","categoryLabels","useState","useCallback","useState","useCallback","useRef","useState","useRef","useCallback","useState","useCallback","useEffect","useRef","useState","useRef","useEffect","useCallback","newProject","fileMeta","generateId","generateId","useState","useRef","useEffect","useMemo","useCallback","savedPersonalization","messages","now","newSess","existingSession","options","currentSession","content","useState","useRef","useEffect","useState","useRef","useEffect","jsx","useState","useRef","useEffect","jsx","jsxs","useState","useRef","useEffect","jsx","jsxs","useState","Fragment","jsx","jsxs","useState","React","useRef","useEffect","useState","Fragment","jsx","jsxs","React","useRef","useState","useEffect","useRef","useEffect","useCallback","useState","useState","React","useMemo","useState","jsx","jsxs","useState","Fragment","jsx","jsxs","dataLines","colCount","result","jsx","React","jsxs","Fragment","useMemo","React","jsx","jsxs","React","useState","useCallback","useEffect","Fragment","jsx","jsxs","useState","useCallback","useEffect","jsx","jsxs","useState","Fragment","jsx","jsxs","useState","jsx","jsxs","useState","Fragment","jsx","jsxs","mapIcon","useState","jsx","jsxs","jsx","jsxs","useState","jsx","jsxs","useRef","useState","useCallback","useEffect","useState","jsx","jsxs","DEFAULT_PERSONALIZATION","useState","useState","useEffect","jsx","jsxs","useState","useEffect","getFileIcon","jsx","jsxs","Fragment","jsx","jsxs","React","generateTitle","useState","useCallback","useRef","REPORT_GENERATION_PROMPT","QUERY_ANALYSIS_PROMPT","callLLM","analyzeQuery","runSubAgent","generateReport","jsx","jsxs","useState","jsx","jsxs","useState"]}