Files
next-ai-draw-io/components/chat-panel.tsx

1483 lines
57 KiB
TypeScript
Raw Normal View History

"use client"
import { useChat } from "@ai-sdk/react"
import { DefaultChatTransport } from "ai"
import {
MessageSquarePlus,
PanelRightClose,
PanelRightOpen,
Settings,
} from "lucide-react"
import { usePathname, useRouter, useSearchParams } from "next/navigation"
import type React from "react"
import {
useCallback,
useEffect,
useLayoutEffect,
useRef,
useState,
} from "react"
import { flushSync } from "react-dom"
import { Toaster, toast } from "sonner"
import { ButtonWithTooltip } from "@/components/button-with-tooltip"
import { ChatInput } from "@/components/chat-input"
import Image from "@/components/image-with-basepath"
feat: multi-provider model configuration with UI/UX improvements (#355) * feat: add multi-provider model configuration - Add model config dialog for managing multiple AI providers - Support for OpenAI, Anthropic, Google, Azure, Bedrock, OpenRouter, DeepSeek, SiliconFlow, Ollama, and AI Gateway - Add model selector dropdown in chat panel header - Add API key validation endpoint - Add custom model ID input with keyboard navigation - Fix hover highlight in Command component - Add suggested models for each provider including latest Claude 4.5 series - Store configuration locally in browser * feat: improve model config UI and move selector to chat input - Move model selector from header to chat input (left of send button) - Add per-model validation status (queued, running, valid, invalid) - Filter model selector to only show verified models - Add editable model IDs in config dialog - Add custom model input field alongside suggested models dropdown - Fix hover states on provider buttons and select triggers - Update OpenAI suggested models with GPT-5 series - Add alert-dialog component for delete confirmation * refactor: revert shadcn component changes, apply hover fix at usage site * feat: add AWS credentials support for Bedrock provider - Add AWS Access Key ID, Secret Access Key, Region fields for Bedrock - Show different credential fields based on provider type - Update validation API to handle Bedrock with AWS credentials - Add region selector with common AWS regions * fix: reset Test button after validation completes * fix: reset validation button to Test after success * fix: complete bedrock support and UI/UX improvements - Add bedrock to ALLOWED_CLIENT_PROVIDERS for client credentials - Pass AWS credentials through full chain (headers → API → provider) - Replace non-existent GPT-5 models with real ones (o1, o3-mini) - Add accessibility: aria-labels, focus-visible rings, inline errors - Add more AWS regions (Ohio, London, Paris, Mumbai, Seoul, São Paulo) - Fix setTimeout cleanup with useRef on component unmount - Fix TypeScript type consistency in getSelectedAIConfig fallback * chore: remove unused code - Remove unused setAccessCodeRequired state in chat-panel.tsx - Remove unused getSelectedModel export in model-config.ts * fix: UI/UX improvements for model configuration dialog - Add gradient header styling with icon badge - Change Configuration section icon from Key to Settings2 - Add duplicate model detection with warning banner and inline removal - Filter out already-added models from suggestions dropdown - Add type-to-confirm for deleting providers with 3+ models - Enhance delete confirmation dialog with warning icon - Improve model selector discoverability (show model name + chevron) - Add truncation for long model names with title tooltip - Remove AI provider settings from Settings dialog (now in Model Config) - Extract ValidationButton into reusable component * fix: prevent duplicate model IDs within same provider - Block adding model if ID already exists in provider - Block editing model ID to match existing model in provider * fix: improve duplicate model ID notifications - Add toast notification when trying to add duplicate model - Allow free typing when editing model ID, validate on blur - Show warning toast instead of blocking input * fix: improve duplicate model validation UX in config dialog - Add inline error display for duplicate model IDs - Show red border on input when error exists - Validate on blur with shake animation for edit errors - Prevent saving empty model names - Clear errors when user starts typing - Simplify error styling (small red text, no heavy chips)
2025-12-22 22:36:36 +09:00
import { ModelConfigDialog } from "@/components/model-config-dialog"
import { SettingsDialog } from "@/components/settings-dialog"
import { useDiagram } from "@/contexts/diagram-context"
import { useDiagramToolHandlers } from "@/hooks/use-diagram-tool-handlers"
import { useDictionary } from "@/hooks/use-dictionary"
feat: multi-provider model configuration with UI/UX improvements (#355) * feat: add multi-provider model configuration - Add model config dialog for managing multiple AI providers - Support for OpenAI, Anthropic, Google, Azure, Bedrock, OpenRouter, DeepSeek, SiliconFlow, Ollama, and AI Gateway - Add model selector dropdown in chat panel header - Add API key validation endpoint - Add custom model ID input with keyboard navigation - Fix hover highlight in Command component - Add suggested models for each provider including latest Claude 4.5 series - Store configuration locally in browser * feat: improve model config UI and move selector to chat input - Move model selector from header to chat input (left of send button) - Add per-model validation status (queued, running, valid, invalid) - Filter model selector to only show verified models - Add editable model IDs in config dialog - Add custom model input field alongside suggested models dropdown - Fix hover states on provider buttons and select triggers - Update OpenAI suggested models with GPT-5 series - Add alert-dialog component for delete confirmation * refactor: revert shadcn component changes, apply hover fix at usage site * feat: add AWS credentials support for Bedrock provider - Add AWS Access Key ID, Secret Access Key, Region fields for Bedrock - Show different credential fields based on provider type - Update validation API to handle Bedrock with AWS credentials - Add region selector with common AWS regions * fix: reset Test button after validation completes * fix: reset validation button to Test after success * fix: complete bedrock support and UI/UX improvements - Add bedrock to ALLOWED_CLIENT_PROVIDERS for client credentials - Pass AWS credentials through full chain (headers → API → provider) - Replace non-existent GPT-5 models with real ones (o1, o3-mini) - Add accessibility: aria-labels, focus-visible rings, inline errors - Add more AWS regions (Ohio, London, Paris, Mumbai, Seoul, São Paulo) - Fix setTimeout cleanup with useRef on component unmount - Fix TypeScript type consistency in getSelectedAIConfig fallback * chore: remove unused code - Remove unused setAccessCodeRequired state in chat-panel.tsx - Remove unused getSelectedModel export in model-config.ts * fix: UI/UX improvements for model configuration dialog - Add gradient header styling with icon badge - Change Configuration section icon from Key to Settings2 - Add duplicate model detection with warning banner and inline removal - Filter out already-added models from suggestions dropdown - Add type-to-confirm for deleting providers with 3+ models - Enhance delete confirmation dialog with warning icon - Improve model selector discoverability (show model name + chevron) - Add truncation for long model names with title tooltip - Remove AI provider settings from Settings dialog (now in Model Config) - Extract ValidationButton into reusable component * fix: prevent duplicate model IDs within same provider - Block adding model if ID already exists in provider - Block editing model ID to match existing model in provider * fix: improve duplicate model ID notifications - Add toast notification when trying to add duplicate model - Allow free typing when editing model ID, validate on blur - Show warning toast instead of blocking input * fix: improve duplicate model validation UX in config dialog - Add inline error display for duplicate model IDs - Show red border on input when error exists - Validate on blur with shake animation for edit errors - Prevent saving empty model names - Clear errors when user starts typing - Simplify error styling (small red text, no heavy chips)
2025-12-22 22:36:36 +09:00
import { getSelectedAIConfig, useModelConfig } from "@/hooks/use-model-config"
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
import { useSessionManager } from "@/hooks/use-session-manager"
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
import { useValidateDiagram } from "@/hooks/use-validate-diagram"
import { getApiEndpoint } from "@/lib/base-path"
import { findCachedResponse } from "@/lib/cached-responses"
import type { DrawioTheme } from "@/lib/drawio-themes"
import { formatMessage } from "@/lib/i18n/utils"
import { isPdfFile, isTextFile } from "@/lib/pdf-utils"
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
import { sanitizeMessages } from "@/lib/session-storage"
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
import { STORAGE_KEYS } from "@/lib/storage"
import type { UrlData } from "@/lib/url-utils"
import { type FileData, useFileProcessor } from "@/lib/use-file-processor"
import { useQuotaManager } from "@/lib/use-quota-manager"
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
import { cn, formatXML, isRealDiagram } from "@/lib/utils"
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
import type { ValidationState } from "./chat/ValidationCard"
import { ChatMessageDisplay } from "./chat-message-display"
import { DevXmlSimulator } from "./dev-xml-simulator"
// localStorage keys for persistence
const STORAGE_SESSION_ID_KEY = "next-ai-draw-io-session-id"
// sessionStorage keys
const SESSION_STORAGE_INPUT_KEY = "next-ai-draw-io-input"
// Type for message parts (tool calls and their states)
interface MessagePart {
type: string
state?: string
toolName?: string
input?: { xml?: string; [key: string]: unknown }
[key: string]: unknown
}
interface ChatMessage {
role: string
parts?: MessagePart[]
[key: string]: unknown
}
interface ChatPanelProps {
isVisible: boolean
onToggleVisibility: () => void
drawioUi: DrawioTheme
onDrawioUiChange: (theme: DrawioTheme) => void
darkMode: boolean
onToggleDarkMode: () => void
isMobile?: boolean
}
// Constants for tool states
const TOOL_ERROR_STATE = "output-error" as const
const DEBUG = process.env.NODE_ENV === "development"
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
// Increased to 3 to support VLM validation retries (matches MAX_VALIDATION_RETRIES)
const MAX_AUTO_RETRY_COUNT = 3
const MAX_CONTINUATION_RETRY_COUNT = 2 // Limit for truncation continuation retries
/**
* Check if auto-resubmit should happen based on tool errors.
feat: add append_diagram tool and improve truncation handling (#252) * feat: add append_diagram tool for truncation continuation When LLM output hits maxOutputTokens mid-generation, instead of failing with an error loop, the system now: 1. Detects truncation (missing </root> in XML) 2. Stores partial XML and tells LLM to use new append_diagram tool 3. LLM continues generating from where it stopped 4. Fragments are accumulated until XML is complete 5. Server limits to 5 steps via stepCountIs(5) Key changes: - Add append_diagram tool definition in route.ts - Add append_diagram handler in chat-panel.tsx - Track continuation mode separately from error mode - Continuation mode has unlimited retries (not counted against limit) - Error mode still limited to MAX_AUTO_RETRY_COUNT (1) - Update system prompts to document append_diagram tool * fix: show friendly message and yellow badge for truncated output - Add yellow 'Truncated' badge in UI instead of red 'Error' when XML is incomplete - Show friendly error message for toolUse.input is invalid errors - Built on top of append_diagram continuation feature * refactor: remove debug logs and simplify truncation state - Remove all debug console.log statements - Remove isContinuationModeRef, derive from partialXmlRef.current.length > 0 * docs: fix append_diagram instructions for consistency - Change 'Do NOT include' to 'Do NOT start with' (clearer intent) - Add <mxCell id="0"> to prohibited start patterns - Change 'closing tags </root></mxGraphModel>' to just '</root>' (wrapWithMxFile handles the rest)
2025-12-14 12:34:34 +09:00
* Only checks the LAST tool part (most recent tool call), not all tool parts.
*/
function hasToolErrors(messages: ChatMessage[]): boolean {
const lastMessage = messages[messages.length - 1]
if (!lastMessage || lastMessage.role !== "assistant") {
return false
}
const toolParts =
(lastMessage.parts as MessagePart[] | undefined)?.filter((part) =>
part.type?.startsWith("tool-"),
) || []
if (toolParts.length === 0) {
return false
}
feat: add append_diagram tool and improve truncation handling (#252) * feat: add append_diagram tool for truncation continuation When LLM output hits maxOutputTokens mid-generation, instead of failing with an error loop, the system now: 1. Detects truncation (missing </root> in XML) 2. Stores partial XML and tells LLM to use new append_diagram tool 3. LLM continues generating from where it stopped 4. Fragments are accumulated until XML is complete 5. Server limits to 5 steps via stepCountIs(5) Key changes: - Add append_diagram tool definition in route.ts - Add append_diagram handler in chat-panel.tsx - Track continuation mode separately from error mode - Continuation mode has unlimited retries (not counted against limit) - Error mode still limited to MAX_AUTO_RETRY_COUNT (1) - Update system prompts to document append_diagram tool * fix: show friendly message and yellow badge for truncated output - Add yellow 'Truncated' badge in UI instead of red 'Error' when XML is incomplete - Show friendly error message for toolUse.input is invalid errors - Built on top of append_diagram continuation feature * refactor: remove debug logs and simplify truncation state - Remove all debug console.log statements - Remove isContinuationModeRef, derive from partialXmlRef.current.length > 0 * docs: fix append_diagram instructions for consistency - Change 'Do NOT include' to 'Do NOT start with' (clearer intent) - Add <mxCell id="0"> to prohibited start patterns - Change 'closing tags </root></mxGraphModel>' to just '</root>' (wrapWithMxFile handles the rest)
2025-12-14 12:34:34 +09:00
const lastToolPart = toolParts[toolParts.length - 1]
return lastToolPart?.state === TOOL_ERROR_STATE
}
export default function ChatPanel({
isVisible,
onToggleVisibility,
drawioUi,
onDrawioUiChange,
darkMode,
onToggleDarkMode,
isMobile = false,
}: ChatPanelProps) {
const {
loadDiagram: onDisplayChart,
handleExport: onExport,
handleExportWithoutHistory,
resolverRef,
2025-04-03 15:10:53 +00:00
chartXML,
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
latestSvg,
clearDiagram,
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
getThumbnailSvg,
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
captureValidationPng,
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
diagramHistory,
setDiagramHistory,
} = useDiagram()
const dict = useDictionary()
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
const router = useRouter()
const pathname = usePathname()
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
const searchParams = useSearchParams()
const urlSessionId = searchParams.get("session")
const onFetchChart = (saveToHistory = true) => {
return Promise.race([
new Promise<string>((resolve) => {
resolverRef.current = resolve
if (saveToHistory) {
onExport()
} else {
handleExportWithoutHistory()
}
}),
new Promise<string>((_, reject) => {
const currentResolver = resolverRef.current
setTimeout(() => {
if (resolverRef.current === currentResolver) {
resolverRef.current = null
}
reject(new Error("Chart export timed out after 10 seconds"))
}, 10000)
}),
])
}
// File processing using extracted hook
const { files, pdfData, handleFileChange, setFiles } = useFileProcessor()
const [urlData, setUrlData] = useState<Map<string, UrlData>>(new Map())
const [showSettingsDialog, setShowSettingsDialog] = useState(false)
feat: multi-provider model configuration with UI/UX improvements (#355) * feat: add multi-provider model configuration - Add model config dialog for managing multiple AI providers - Support for OpenAI, Anthropic, Google, Azure, Bedrock, OpenRouter, DeepSeek, SiliconFlow, Ollama, and AI Gateway - Add model selector dropdown in chat panel header - Add API key validation endpoint - Add custom model ID input with keyboard navigation - Fix hover highlight in Command component - Add suggested models for each provider including latest Claude 4.5 series - Store configuration locally in browser * feat: improve model config UI and move selector to chat input - Move model selector from header to chat input (left of send button) - Add per-model validation status (queued, running, valid, invalid) - Filter model selector to only show verified models - Add editable model IDs in config dialog - Add custom model input field alongside suggested models dropdown - Fix hover states on provider buttons and select triggers - Update OpenAI suggested models with GPT-5 series - Add alert-dialog component for delete confirmation * refactor: revert shadcn component changes, apply hover fix at usage site * feat: add AWS credentials support for Bedrock provider - Add AWS Access Key ID, Secret Access Key, Region fields for Bedrock - Show different credential fields based on provider type - Update validation API to handle Bedrock with AWS credentials - Add region selector with common AWS regions * fix: reset Test button after validation completes * fix: reset validation button to Test after success * fix: complete bedrock support and UI/UX improvements - Add bedrock to ALLOWED_CLIENT_PROVIDERS for client credentials - Pass AWS credentials through full chain (headers → API → provider) - Replace non-existent GPT-5 models with real ones (o1, o3-mini) - Add accessibility: aria-labels, focus-visible rings, inline errors - Add more AWS regions (Ohio, London, Paris, Mumbai, Seoul, São Paulo) - Fix setTimeout cleanup with useRef on component unmount - Fix TypeScript type consistency in getSelectedAIConfig fallback * chore: remove unused code - Remove unused setAccessCodeRequired state in chat-panel.tsx - Remove unused getSelectedModel export in model-config.ts * fix: UI/UX improvements for model configuration dialog - Add gradient header styling with icon badge - Change Configuration section icon from Key to Settings2 - Add duplicate model detection with warning banner and inline removal - Filter out already-added models from suggestions dropdown - Add type-to-confirm for deleting providers with 3+ models - Enhance delete confirmation dialog with warning icon - Improve model selector discoverability (show model name + chevron) - Add truncation for long model names with title tooltip - Remove AI provider settings from Settings dialog (now in Model Config) - Extract ValidationButton into reusable component * fix: prevent duplicate model IDs within same provider - Block adding model if ID already exists in provider - Block editing model ID to match existing model in provider * fix: improve duplicate model ID notifications - Add toast notification when trying to add duplicate model - Allow free typing when editing model ID, validate on blur - Show warning toast instead of blocking input * fix: improve duplicate model validation UX in config dialog - Add inline error display for duplicate model IDs - Show red border on input when error exists - Validate on blur with shake animation for edit errors - Prevent saving empty model names - Clear errors when user starts typing - Simplify error styling (small red text, no heavy chips)
2025-12-22 22:36:36 +09:00
const [showModelConfigDialog, setShowModelConfigDialog] = useState(false)
// Model configuration hook
const modelConfig = useModelConfig()
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Session manager for chat history (pass URL session ID for restoration)
const sessionManager = useSessionManager({ initialSessionId: urlSessionId })
const [input, setInput] = useState("")
const [dailyRequestLimit, setDailyRequestLimit] = useState(0)
const [dailyTokenLimit, setDailyTokenLimit] = useState(0)
const [tpmLimit, setTpmLimit] = useState(0)
const [minimalStyle, setMinimalStyle] = useState(false)
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
const [vlmValidationEnabled, setVlmValidationEnabled] = useState(false)
const [customSystemMessage, setCustomSystemMessage] = useState("")
fix: raise the output budget so reasoning models reach the tool call (#927) * fix: raise the output budget so reasoning models reach the tool call A reasoning model spends the output budget in order: thinking first, then prose, then the tool call. With 16000 the thinking alone can consume all of it, so the turn ends with finishReason "length" before display_diagram is ever called. The canvas stays empty and nothing surfaces in the UI, because no tool call means no tool error, and the client never reads finishReason. Measured on openrouter deepseek/deepseek-v4-flash, the model from the report: - max_tokens=800 with reasoning on returns reasoning_tokens=800, empty content, finish_reason length. So reasoning is billed against this budget, not exempt. - refining an existing diagram (19k chars of XML in the input) produced 49142 chars of reasoning, zero tool calls, finishReason "length" at 16000 - the same request at 40000 finished and called edit_diagram with 12 operations 64000 cannot just be sent to every model: bedrock claude-3-haiku caps at 4096, nova-lite at 10000, and the openrouter deepseek-r1 endpoint counts input and output against one 64000 ceiling. All three name the real limit in the 400, so parse it and retry once. Verified: nova-lite logs "64000 rejected, retrying with 10000" and then completes its tool call. Also expose the budget in Settings. It is sent as a header rather than read from env only, so desktop users can raise it themselves without an env file. vercel.json goes back to the 300s it had before #238 traded it for $2-4/month. That is now Vercel's own default, and billing pauses while the function waits on the model, so the saving that motivated 120s no longer applies. edgeone.json is left alone: its 120 may be that platform's actual ceiling. * fix: only reinterpret an error as a budget rejection when it says so Review of the first commit found the retry could fire on errors that have nothing to do with the budget, which would replace a readable provider error with a truncated response: exactly the symptom this PR exists to remove. - Drop the generic "lower than N" pattern. For the Bedrock message it was dead code, since "model limit of N" matches first with the same number. Left live, it would read a number out of any message shaped like "must be lower than 2". - Skip errors whose status is not 400 or 422, so auth and rate-limit failures are never reinterpreted. - Require the parsed ceiling to be at least 1024. Below that a diagram cannot come out whole, so retrying would hide the error behind broken XML. - Validate MAX_OUTPUT_TOKENS from env the same way as the header, so a stray "-1" falls back instead of reaching the provider. Adds tests for the retry wrapper itself, which had none: it retries once with the named ceiling, leaves a 401 alone, does not retry when the ceiling is not smaller, propagates a second rejection, and preserves the other call options. Re-verified against the live APIs: bedrock nova-lite still logs "64000 rejected, retrying with 10000" and completes its tool call, and deepseek-v4-flash still finishes normally at 64000.
2026-08-22 20:47:10 +09:00
const [maxOutputTokens, setMaxOutputTokens] = useState("")
const [shouldFocusInput, setShouldFocusInput] = useState(false)
2025-08-31 12:54:14 +09:00
// Restore input from sessionStorage on mount (when ChatPanel remounts due to key change)
useEffect(() => {
const savedInput = sessionStorage.getItem(SESSION_STORAGE_INPUT_KEY)
if (savedInput) {
setInput(savedInput)
}
}, [])
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
// Load VLM validation setting from localStorage on mount
useEffect(() => {
const stored = localStorage.getItem(STORAGE_KEYS.vlmValidationEnabled)
if (stored !== null) {
setVlmValidationEnabled(stored === "true")
}
}, [])
// Load custom system message from localStorage on mount
useEffect(() => {
const stored = localStorage.getItem(STORAGE_KEYS.customSystemMessage)
if (stored !== null) {
setCustomSystemMessage(stored)
}
}, [])
fix: raise the output budget so reasoning models reach the tool call (#927) * fix: raise the output budget so reasoning models reach the tool call A reasoning model spends the output budget in order: thinking first, then prose, then the tool call. With 16000 the thinking alone can consume all of it, so the turn ends with finishReason "length" before display_diagram is ever called. The canvas stays empty and nothing surfaces in the UI, because no tool call means no tool error, and the client never reads finishReason. Measured on openrouter deepseek/deepseek-v4-flash, the model from the report: - max_tokens=800 with reasoning on returns reasoning_tokens=800, empty content, finish_reason length. So reasoning is billed against this budget, not exempt. - refining an existing diagram (19k chars of XML in the input) produced 49142 chars of reasoning, zero tool calls, finishReason "length" at 16000 - the same request at 40000 finished and called edit_diagram with 12 operations 64000 cannot just be sent to every model: bedrock claude-3-haiku caps at 4096, nova-lite at 10000, and the openrouter deepseek-r1 endpoint counts input and output against one 64000 ceiling. All three name the real limit in the 400, so parse it and retry once. Verified: nova-lite logs "64000 rejected, retrying with 10000" and then completes its tool call. Also expose the budget in Settings. It is sent as a header rather than read from env only, so desktop users can raise it themselves without an env file. vercel.json goes back to the 300s it had before #238 traded it for $2-4/month. That is now Vercel's own default, and billing pauses while the function waits on the model, so the saving that motivated 120s no longer applies. edgeone.json is left alone: its 120 may be that platform's actual ceiling. * fix: only reinterpret an error as a budget rejection when it says so Review of the first commit found the retry could fire on errors that have nothing to do with the budget, which would replace a readable provider error with a truncated response: exactly the symptom this PR exists to remove. - Drop the generic "lower than N" pattern. For the Bedrock message it was dead code, since "model limit of N" matches first with the same number. Left live, it would read a number out of any message shaped like "must be lower than 2". - Skip errors whose status is not 400 or 422, so auth and rate-limit failures are never reinterpreted. - Require the parsed ceiling to be at least 1024. Below that a diagram cannot come out whole, so retrying would hide the error behind broken XML. - Validate MAX_OUTPUT_TOKENS from env the same way as the header, so a stray "-1" falls back instead of reaching the provider. Adds tests for the retry wrapper itself, which had none: it retries once with the named ceiling, leaves a 401 alone, does not retry when the ceiling is not smaller, propagates a second rejection, and preserves the other call options. Re-verified against the live APIs: bedrock nova-lite still logs "64000 rejected, retrying with 10000" and completes its tool call, and deepseek-v4-flash still finishes normally at 64000.
2026-08-22 20:47:10 +09:00
// Load output token budget from localStorage on mount
useEffect(() => {
const stored = localStorage.getItem(STORAGE_KEYS.maxOutputTokens)
if (stored !== null) {
setMaxOutputTokens(stored)
}
}, [])
// Check config on mount
useEffect(() => {
fetch(getApiEndpoint("/api/config"))
.then((res) => res.json())
.then((data) => {
setDailyRequestLimit(data.dailyRequestLimit || 0)
setDailyTokenLimit(data.dailyTokenLimit || 0)
setTpmLimit(data.tpmLimit || 0)
})
feat: multi-provider model configuration with UI/UX improvements (#355) * feat: add multi-provider model configuration - Add model config dialog for managing multiple AI providers - Support for OpenAI, Anthropic, Google, Azure, Bedrock, OpenRouter, DeepSeek, SiliconFlow, Ollama, and AI Gateway - Add model selector dropdown in chat panel header - Add API key validation endpoint - Add custom model ID input with keyboard navigation - Fix hover highlight in Command component - Add suggested models for each provider including latest Claude 4.5 series - Store configuration locally in browser * feat: improve model config UI and move selector to chat input - Move model selector from header to chat input (left of send button) - Add per-model validation status (queued, running, valid, invalid) - Filter model selector to only show verified models - Add editable model IDs in config dialog - Add custom model input field alongside suggested models dropdown - Fix hover states on provider buttons and select triggers - Update OpenAI suggested models with GPT-5 series - Add alert-dialog component for delete confirmation * refactor: revert shadcn component changes, apply hover fix at usage site * feat: add AWS credentials support for Bedrock provider - Add AWS Access Key ID, Secret Access Key, Region fields for Bedrock - Show different credential fields based on provider type - Update validation API to handle Bedrock with AWS credentials - Add region selector with common AWS regions * fix: reset Test button after validation completes * fix: reset validation button to Test after success * fix: complete bedrock support and UI/UX improvements - Add bedrock to ALLOWED_CLIENT_PROVIDERS for client credentials - Pass AWS credentials through full chain (headers → API → provider) - Replace non-existent GPT-5 models with real ones (o1, o3-mini) - Add accessibility: aria-labels, focus-visible rings, inline errors - Add more AWS regions (Ohio, London, Paris, Mumbai, Seoul, São Paulo) - Fix setTimeout cleanup with useRef on component unmount - Fix TypeScript type consistency in getSelectedAIConfig fallback * chore: remove unused code - Remove unused setAccessCodeRequired state in chat-panel.tsx - Remove unused getSelectedModel export in model-config.ts * fix: UI/UX improvements for model configuration dialog - Add gradient header styling with icon badge - Change Configuration section icon from Key to Settings2 - Add duplicate model detection with warning banner and inline removal - Filter out already-added models from suggestions dropdown - Add type-to-confirm for deleting providers with 3+ models - Enhance delete confirmation dialog with warning icon - Improve model selector discoverability (show model name + chevron) - Add truncation for long model names with title tooltip - Remove AI provider settings from Settings dialog (now in Model Config) - Extract ValidationButton into reusable component * fix: prevent duplicate model IDs within same provider - Block adding model if ID already exists in provider - Block editing model ID to match existing model in provider * fix: improve duplicate model ID notifications - Add toast notification when trying to add duplicate model - Allow free typing when editing model ID, validate on blur - Show warning toast instead of blocking input * fix: improve duplicate model validation UX in config dialog - Add inline error display for duplicate model IDs - Show red border on input when error exists - Validate on blur with shake animation for edit errors - Prevent saving empty model names - Clear errors when user starts typing - Simplify error styling (small red text, no heavy chips)
2025-12-22 22:36:36 +09:00
.catch(() => {})
}, [])
// Quota management using extracted hook
const quotaManager = useQuotaManager({
dailyRequestLimit,
dailyTokenLimit,
tpmLimit,
onConfigModel: () => setShowModelConfigDialog(true),
})
// Generate a unique session ID for Langfuse tracing (restore from localStorage if available)
const [sessionId, setSessionId] = useState(() => {
if (typeof window !== "undefined") {
const saved = localStorage.getItem(STORAGE_SESSION_ID_KEY)
if (saved) return saved
}
return `session-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
})
// Store XML snapshots for each user message (keyed by message index)
const xmlSnapshotsRef = useRef<Map<number, string>>(new Map())
// Flag to track if we've restored from localStorage
const hasRestoredRef = useRef(false)
const [isRestored, setIsRestored] = useState(false)
// Track previous isVisible to only animate when toggling (not on page load)
const prevIsVisibleRef = useRef(isVisible)
const [shouldAnimatePanel, setShouldAnimatePanel] = useState(false)
useEffect(() => {
// Only animate when visibility changes from false to true (not on initial load)
if (!prevIsVisibleRef.current && isVisible) {
setShouldAnimatePanel(true)
}
prevIsVisibleRef.current = isVisible
}, [isVisible])
// Ref to track latest chartXML for use in callbacks (avoids stale closure)
const chartXMLRef = useRef(chartXML)
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Track session ID that was loaded without a diagram (to prevent thumbnail contamination)
const justLoadedSessionIdRef = useRef<string | null>(null)
useEffect(() => {
chartXMLRef.current = chartXML
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Clear the no-diagram flag when a diagram is generated
if (chartXML) {
justLoadedSessionIdRef.current = null
}
}, [chartXML])
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Ref to track latest SVG for thumbnail generation
const latestSvgRef = useRef(latestSvg)
useEffect(() => {
latestSvgRef.current = latestSvg
}, [latestSvg])
// Ref to track consecutive auto-retry count (reset on user action)
const autoRetryCountRef = useRef(0)
// Ref to track continuation retry count (for truncation handling)
const continuationRetryCountRef = useRef(0)
feat: add append_diagram tool and improve truncation handling (#252) * feat: add append_diagram tool for truncation continuation When LLM output hits maxOutputTokens mid-generation, instead of failing with an error loop, the system now: 1. Detects truncation (missing </root> in XML) 2. Stores partial XML and tells LLM to use new append_diagram tool 3. LLM continues generating from where it stopped 4. Fragments are accumulated until XML is complete 5. Server limits to 5 steps via stepCountIs(5) Key changes: - Add append_diagram tool definition in route.ts - Add append_diagram handler in chat-panel.tsx - Track continuation mode separately from error mode - Continuation mode has unlimited retries (not counted against limit) - Error mode still limited to MAX_AUTO_RETRY_COUNT (1) - Update system prompts to document append_diagram tool * fix: show friendly message and yellow badge for truncated output - Add yellow 'Truncated' badge in UI instead of red 'Error' when XML is incomplete - Show friendly error message for toolUse.input is invalid errors - Built on top of append_diagram continuation feature * refactor: remove debug logs and simplify truncation state - Remove all debug console.log statements - Remove isContinuationModeRef, derive from partialXmlRef.current.length > 0 * docs: fix append_diagram instructions for consistency - Change 'Do NOT include' to 'Do NOT start with' (clearer intent) - Add <mxCell id="0"> to prohibited start patterns - Change 'closing tags </root></mxGraphModel>' to just '</root>' (wrapWithMxFile handles the rest)
2025-12-14 12:34:34 +09:00
// Ref to accumulate partial XML when output is truncated due to maxOutputTokens
// When partialXmlRef.current.length > 0, we're in continuation mode
const partialXmlRef = useRef<string>("")
// Persist processed tool call IDs so collapsing the chat doesn't replay old tool outputs
const processedToolCallsRef = useRef<Set<string>>(new Set())
// Store original XML for edit_diagram streaming - shared between streaming preview and tool handler
// Key: toolCallId, Value: original XML before any operations applied
const editDiagramOriginalXmlRef = useRef<Map<string, string>>(new Map())
// Debounce timeout for localStorage writes (prevents blocking during streaming)
const localStorageDebounceRef = useRef<ReturnType<
typeof setTimeout
> | null>(null)
const LOCAL_STORAGE_DEBOUNCE_MS = 1000 // Save at most once per second
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
// Validation state for displaying VLM validation progress
// Key: toolCallId, Value: ValidationState
const [validationStates, setValidationStates] = useState<
Record<string, ValidationState>
>({})
// Callback to update validation state from tool handler
const handleValidationStateChange = useCallback(
(toolCallId: string, state: ValidationState) => {
setValidationStates((prev) => ({
...prev,
[toolCallId]: state,
}))
},
[],
)
// Handler for VLM validation setting change
const handleVlmValidationChange = useCallback((value: boolean) => {
setVlmValidationEnabled(value)
localStorage.setItem(STORAGE_KEYS.vlmValidationEnabled, String(value))
}, [])
// Handler for custom system message change
const handleCustomSystemMessageChange = useCallback((value: string) => {
setCustomSystemMessage(value)
localStorage.setItem(STORAGE_KEYS.customSystemMessage, value)
}, [])
fix: raise the output budget so reasoning models reach the tool call (#927) * fix: raise the output budget so reasoning models reach the tool call A reasoning model spends the output budget in order: thinking first, then prose, then the tool call. With 16000 the thinking alone can consume all of it, so the turn ends with finishReason "length" before display_diagram is ever called. The canvas stays empty and nothing surfaces in the UI, because no tool call means no tool error, and the client never reads finishReason. Measured on openrouter deepseek/deepseek-v4-flash, the model from the report: - max_tokens=800 with reasoning on returns reasoning_tokens=800, empty content, finish_reason length. So reasoning is billed against this budget, not exempt. - refining an existing diagram (19k chars of XML in the input) produced 49142 chars of reasoning, zero tool calls, finishReason "length" at 16000 - the same request at 40000 finished and called edit_diagram with 12 operations 64000 cannot just be sent to every model: bedrock claude-3-haiku caps at 4096, nova-lite at 10000, and the openrouter deepseek-r1 endpoint counts input and output against one 64000 ceiling. All three name the real limit in the 400, so parse it and retry once. Verified: nova-lite logs "64000 rejected, retrying with 10000" and then completes its tool call. Also expose the budget in Settings. It is sent as a header rather than read from env only, so desktop users can raise it themselves without an env file. vercel.json goes back to the 300s it had before #238 traded it for $2-4/month. That is now Vercel's own default, and billing pauses while the function waits on the model, so the saving that motivated 120s no longer applies. edgeone.json is left alone: its 120 may be that platform's actual ceiling. * fix: only reinterpret an error as a budget rejection when it says so Review of the first commit found the retry could fire on errors that have nothing to do with the budget, which would replace a readable provider error with a truncated response: exactly the symptom this PR exists to remove. - Drop the generic "lower than N" pattern. For the Bedrock message it was dead code, since "model limit of N" matches first with the same number. Left live, it would read a number out of any message shaped like "must be lower than 2". - Skip errors whose status is not 400 or 422, so auth and rate-limit failures are never reinterpreted. - Require the parsed ceiling to be at least 1024. Below that a diagram cannot come out whole, so retrying would hide the error behind broken XML. - Validate MAX_OUTPUT_TOKENS from env the same way as the header, so a stray "-1" falls back instead of reaching the provider. Adds tests for the retry wrapper itself, which had none: it retries once with the named ceiling, leaves a 401 alone, does not retry when the ceiling is not smaller, propagates a second rejection, and preserves the other call options. Re-verified against the live APIs: bedrock nova-lite still logs "64000 rejected, retrying with 10000" and completes its tool call, and deepseek-v4-flash still finishes normally at 64000.
2026-08-22 20:47:10 +09:00
// Handler for output token budget change (empty string = use server default)
const handleMaxOutputTokensChange = useCallback((value: string) => {
const digitsOnly = value.replace(/\D/g, "")
setMaxOutputTokens(digitsOnly)
localStorage.setItem(STORAGE_KEYS.maxOutputTokens, digitsOnly)
}, [])
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
// Ref to store the sendMessage function for use in callbacks
const sendMessageRef = useRef<typeof sendMessage | null>(null)
// Callback to improve diagram with validation suggestions
const handleImproveWithSuggestions = useCallback((feedback: string) => {
if (sendMessageRef.current) {
// Send the feedback as a new user message to trigger regeneration
sendMessageRef.current({
role: "user",
parts: [{ type: "text", text: feedback }],
})
}
}, [])
// VLM validation hook using AI SDK's useObject
const { validateWithFallback } = useValidateDiagram()
// Diagram tool handlers (display_diagram, edit_diagram, append_diagram)
const { handleToolCall } = useDiagramToolHandlers({
partialXmlRef,
editDiagramOriginalXmlRef,
chartXMLRef,
onDisplayChart,
onFetchChart,
onExport,
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
captureValidationPng,
validateDiagram: validateWithFallback,
enableVlmValidation: vlmValidationEnabled,
sessionId,
onValidationStateChange: handleValidationStateChange,
})
const {
messages,
sendMessage,
addToolOutput,
status,
error,
setMessages,
stop,
} = useChat({
transport: new DefaultChatTransport({
api: getApiEndpoint("/api/chat"),
}),
onToolCall: async ({ toolCall }) => {
await handleToolCall({ toolCall }, addToolOutput)
},
onError: (error) => {
// Handle server-side quota limit (429 response)
// AI SDK puts the full response body in error.message for non-OK responses
try {
const data = JSON.parse(error.message)
if (data.type === "request") {
quotaManager.showQuotaLimitToast(data.used, data.limit)
return
}
if (data.type === "token") {
quotaManager.showTokenLimitToast(data.used, data.limit)
return
}
if (data.type === "tpm") {
quotaManager.showTPMLimitToast(data.limit)
return
}
} catch {
// Not JSON, fall through to string matching for backwards compatibility
}
// Fallback to string matching
if (error.message.includes("Daily request limit")) {
quotaManager.showQuotaLimitToast()
return
}
if (error.message.includes("Daily token limit")) {
quotaManager.showTokenLimitToast()
return
}
if (
error.message.includes("Rate limit exceeded") ||
error.message.includes("tokens per minute")
) {
quotaManager.showTPMLimitToast()
return
}
// Silence access code error in console since it's handled by UI
if (!error.message.includes("Invalid or missing access code")) {
console.error("Chat error:", error)
}
// Translate technical errors into user-friendly messages
// The server now handles detailed error messages, so we can display them directly.
// But we still handle connection/network errors that happen before reaching the server.
let friendlyMessage = error.message
feat: add append_diagram tool and improve truncation handling (#252) * feat: add append_diagram tool for truncation continuation When LLM output hits maxOutputTokens mid-generation, instead of failing with an error loop, the system now: 1. Detects truncation (missing </root> in XML) 2. Stores partial XML and tells LLM to use new append_diagram tool 3. LLM continues generating from where it stopped 4. Fragments are accumulated until XML is complete 5. Server limits to 5 steps via stepCountIs(5) Key changes: - Add append_diagram tool definition in route.ts - Add append_diagram handler in chat-panel.tsx - Track continuation mode separately from error mode - Continuation mode has unlimited retries (not counted against limit) - Error mode still limited to MAX_AUTO_RETRY_COUNT (1) - Update system prompts to document append_diagram tool * fix: show friendly message and yellow badge for truncated output - Add yellow 'Truncated' badge in UI instead of red 'Error' when XML is incomplete - Show friendly error message for toolUse.input is invalid errors - Built on top of append_diagram continuation feature * refactor: remove debug logs and simplify truncation state - Remove all debug console.log statements - Remove isContinuationModeRef, derive from partialXmlRef.current.length > 0 * docs: fix append_diagram instructions for consistency - Change 'Do NOT include' to 'Do NOT start with' (clearer intent) - Add <mxCell id="0"> to prohibited start patterns - Change 'closing tags </root></mxGraphModel>' to just '</root>' (wrapWithMxFile handles the rest)
2025-12-14 12:34:34 +09:00
// Simple check for network errors if message is generic
if (friendlyMessage === "Failed to fetch") {
friendlyMessage = "Network error. Please check your connection."
}
// Truncated tool input error (model output limit too low)
if (friendlyMessage.includes("toolUse.input is invalid")) {
friendlyMessage =
"Output was truncated before the diagram could be generated. Try a simpler request or increase the maxOutputLength."
}
// Translate image not supported error
if (
friendlyMessage.includes("image content block") ||
friendlyMessage.toLowerCase().includes("image_url")
) {
friendlyMessage = "This model doesn't support image input."
}
// Add system message for error so it can be cleared
setMessages((currentMessages) => {
const errorMessage = {
id: `error-${Date.now()}`,
role: "system" as const,
content: friendlyMessage,
parts: [{ type: "text" as const, text: friendlyMessage }],
}
return [...currentMessages, errorMessage]
})
if (error.message.includes("Invalid or missing access code")) {
// Show settings dialog to help user fix it
setShowSettingsDialog(true)
}
},
onFinish: () => {},
sendAutomaticallyWhen: ({ messages }) => {
const isInContinuationMode = partialXmlRef.current.length > 0
const shouldRetry = hasToolErrors(
messages as unknown as ChatMessage[],
)
if (!shouldRetry) {
// No error, reset retry count and clear state
autoRetryCountRef.current = 0
continuationRetryCountRef.current = 0
partialXmlRef.current = ""
return false
}
// Continuation mode: limited retries for truncation handling
if (isInContinuationMode) {
if (
continuationRetryCountRef.current >=
MAX_CONTINUATION_RETRY_COUNT
) {
toast.error(
formatMessage(dict.errors.continuationRetryLimit, {
max: MAX_CONTINUATION_RETRY_COUNT,
}),
)
continuationRetryCountRef.current = 0
partialXmlRef.current = ""
return false
}
continuationRetryCountRef.current++
} else {
// Regular error: check retry count limit
if (autoRetryCountRef.current >= MAX_AUTO_RETRY_COUNT) {
toast.error(
formatMessage(dict.errors.retryLimit, {
max: MAX_AUTO_RETRY_COUNT,
}),
)
autoRetryCountRef.current = 0
partialXmlRef.current = ""
return false
}
// Increment retry count for actual errors
autoRetryCountRef.current++
}
return true
},
})
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
// Store sendMessage in ref for use in callbacks (like handleImproveWithSuggestions)
useEffect(() => {
sendMessageRef.current = sendMessage
}, [sendMessage])
// Ref to track latest messages for unload persistence
const messagesRef = useRef(messages)
useEffect(() => {
messagesRef.current = messages
}, [messages])
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Track last synced session ID to detect external changes (e.g., URL back/forward)
const lastSyncedSessionIdRef = useRef<string | null>(null)
// Helper: Sync UI state with session data (eliminates duplication)
// Track message IDs that are being loaded from session (to skip animations/scroll)
const loadedMessageIdsRef = useRef<Set<string>>(new Set())
// Track when session was just loaded (to skip auto-save on load)
const justLoadedSessionRef = useRef(false)
const syncUIWithSession = useCallback(
(
data: {
messages: unknown[]
xmlSnapshots: [number, string][]
diagramXml: string
diagramHistory?: { svg: string; xml: string }[]
} | null,
) => {
const hasRealDiagram = isRealDiagram(data?.diagramXml)
if (data) {
// Mark all message IDs as loaded from session
const messageIds = (data.messages as any[]).map(
(m: any) => m.id,
)
loadedMessageIdsRef.current = new Set(messageIds)
setMessages(data.messages as any)
xmlSnapshotsRef.current = new Map(data.xmlSnapshots)
if (hasRealDiagram) {
onDisplayChart(data.diagramXml, true)
chartXMLRef.current = data.diagramXml
} else {
clearDiagram()
// Clear refs to prevent stale data from being saved
chartXMLRef.current = ""
latestSvgRef.current = ""
}
setDiagramHistory(data.diagramHistory || [])
} else {
loadedMessageIdsRef.current = new Set()
setMessages([])
xmlSnapshotsRef.current.clear()
clearDiagram()
// Clear refs to prevent stale data from being saved
chartXMLRef.current = ""
latestSvgRef.current = ""
setDiagramHistory([])
}
},
[setMessages, onDisplayChart, clearDiagram, setDiagramHistory],
)
// Helper: Build session data object for saving (eliminates duplication)
const buildSessionData = useCallback(
async (options: { withThumbnail?: boolean } = {}) => {
const currentDiagramXml = chartXMLRef.current || ""
// Only capture thumbnail if there's a meaningful diagram (not just empty template)
const hasRealDiagram = isRealDiagram(currentDiagramXml)
let thumbnailDataUrl: string | undefined
if (hasRealDiagram && options.withThumbnail) {
const freshThumb = await getThumbnailSvg()
if (freshThumb) {
latestSvgRef.current = freshThumb
thumbnailDataUrl = freshThumb
} else if (latestSvgRef.current) {
// Use cached thumbnail only if we have a real diagram
thumbnailDataUrl = latestSvgRef.current
}
}
return {
messages: sanitizeMessages(messagesRef.current),
xmlSnapshots: Array.from(xmlSnapshotsRef.current.entries()),
diagramXml: currentDiagramXml,
thumbnailDataUrl,
diagramHistory,
}
},
[diagramHistory, getThumbnailSvg],
)
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Restore messages and XML snapshots from session manager on mount
// This effect syncs with the session manager's loaded session
useLayoutEffect(() => {
if (hasRestoredRef.current) return
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
if (sessionManager.isLoading) return // Wait for session manager to load
hasRestoredRef.current = true
try {
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
const currentSession = sessionManager.currentSession
if (currentSession) {
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Restore from session manager (IndexedDB)
justLoadedSessionRef.current = true
syncUIWithSession(currentSession)
}
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Initialize lastSyncedSessionIdRef to prevent sync effect from firing immediately
lastSyncedSessionIdRef.current = sessionManager.currentSessionId
// Note: Migration from old localStorage format is handled by session-storage.ts
} catch (error) {
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
console.error("Failed to restore session:", error)
toast.error(dict.errors.sessionCorrupted)
} finally {
setIsRestored(true)
}
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
}, [
sessionManager.isLoading,
sessionManager.currentSession,
syncUIWithSession,
dict.errors.sessionCorrupted,
])
// Sync UI when session changes externally (e.g., URL navigation via back/forward)
// This handles changes AFTER initial restore
useEffect(() => {
if (!isRestored) return // Wait for initial restore to complete
if (!sessionManager.isAvailable) return
const newSessionId = sessionManager.currentSessionId
const newSession = sessionManager.currentSession
// Skip if session ID hasn't changed (our own saves don't change the ID)
if (newSessionId === lastSyncedSessionIdRef.current) return
// Update last synced ID
lastSyncedSessionIdRef.current = newSessionId
// Sync UI with new session
if (newSession) {
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
justLoadedSessionRef.current = true
syncUIWithSession(newSession)
} else if (!newSession) {
syncUIWithSession(null)
}
}, [
isRestored,
sessionManager.isAvailable,
sessionManager.currentSessionId,
sessionManager.currentSession,
syncUIWithSession,
])
// Save messages to session manager (debounced, only when not streaming)
// Destructure stable values to avoid effect re-running on every render
const {
isAvailable: sessionIsAvailable,
currentSessionId,
saveCurrentSession,
} = sessionManager
// Use ref for saveCurrentSession to avoid infinite loop
// (saveCurrentSession changes after each save, which would re-trigger the effect)
const saveCurrentSessionRef = useRef(saveCurrentSession)
saveCurrentSessionRef.current = saveCurrentSession
useEffect(() => {
if (!hasRestoredRef.current) return
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
if (!sessionIsAvailable) return
// Only save when not actively streaming to avoid write storms
if (status === "streaming" || status === "submitted") return
// Skip auto-save if session was just loaded (to prevent re-ordering)
if (justLoadedSessionRef.current) {
justLoadedSessionRef.current = false
return
}
// Clear any pending save
if (localStorageDebounceRef.current) {
clearTimeout(localStorageDebounceRef.current)
}
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Capture current session ID at schedule time to verify at save time
const scheduledForSessionId = currentSessionId
// Capture whether there's a REAL diagram NOW (not just empty template)
const hasDiagramNow = isRealDiagram(chartXMLRef.current)
// Check if this session was just loaded without a diagram
const isNodiagramSession =
justLoadedSessionIdRef.current === scheduledForSessionId
// Debounce: save after 1 second of no changes
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
localStorageDebounceRef.current = setTimeout(async () => {
try {
if (messages.length > 0 || hasDiagramNow) {
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
const sessionData = await buildSessionData({
// Only capture thumbnail if there was a diagram AND this isn't a no-diagram session
withThumbnail: hasDiagramNow && !isNodiagramSession,
})
await saveCurrentSessionRef.current(
sessionData,
scheduledForSessionId,
)
}
} catch (error) {
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
console.error("Failed to save session:", error)
}
}, LOCAL_STORAGE_DEBOUNCE_MS)
// Cleanup on unmount
return () => {
if (localStorageDebounceRef.current) {
clearTimeout(localStorageDebounceRef.current)
}
}
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
}, [
chartXML,
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
messages,
status,
sessionIsAvailable,
currentSessionId,
buildSessionData,
])
// Update URL when a new session is created (first message sent)
useEffect(() => {
if (sessionManager.currentSessionId && !urlSessionId) {
// A session was created but URL doesn't have the session param yet
router.replace(`?session=${sessionManager.currentSessionId}`, {
scroll: false,
})
}
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
}, [sessionManager.currentSessionId, urlSessionId, router])
// Save session ID to localStorage
useEffect(() => {
localStorage.setItem(STORAGE_SESSION_ID_KEY, sessionId)
}, [sessionId])
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Save session when page becomes hidden (tab switch, close, navigate away)
// This is more reliable than beforeunload for async IndexedDB operations
useEffect(() => {
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
if (!sessionManager.isAvailable) return
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
const handleVisibilityChange = async () => {
if (
document.visibilityState === "hidden" &&
(messagesRef.current.length > 0 ||
isRealDiagram(chartXMLRef.current))
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
) {
try {
// Attempt to save session - browser may not wait for completion
// Skip thumbnail capture as it may not complete in time
const sessionData = await buildSessionData({
withThumbnail: false,
})
await sessionManager.saveCurrentSession(sessionData)
} catch (error) {
console.error(
"Failed to save session on visibility change:",
error,
)
}
}
}
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
document.addEventListener("visibilitychange", handleVisibilityChange)
return () =>
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
document.removeEventListener(
"visibilitychange",
handleVisibilityChange,
)
}, [sessionManager, buildSessionData])
const onFormSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
const isProcessing = status === "streaming" || status === "submitted"
if (input.trim() && !isProcessing) {
// Check if input matches a cached example (only when no messages yet)
if (messages.length === 0) {
const cached = findCachedResponse(
input.trim(),
files.length > 0,
)
if (cached) {
// Add user message and fake assistant response to messages
// The chat-message-display useEffect will handle displaying the diagram
const toolCallId = `cached-${Date.now()}`
// Build user message text including any file content
const userText = await processFilesAndAppendContent(
input,
files,
pdfData,
undefined,
urlData,
)
setMessages([
{
id: `user-${Date.now()}`,
role: "user" as const,
parts: [{ type: "text" as const, text: userText }],
},
{
id: `assistant-${Date.now()}`,
role: "assistant" as const,
parts: [
{
type: "tool-display_diagram" as const,
toolCallId,
state: "output-available" as const,
input: { xml: cached.xml },
output: "Successfully displayed the diagram.",
},
],
},
] as any)
setInput("")
sessionStorage.removeItem(SESSION_STORAGE_INPUT_KEY)
setFiles([])
setUrlData(new Map())
return
}
}
try {
let chartXml = await onFetchChart()
chartXml = formatXML(chartXml)
2025-08-31 12:54:14 +09:00
// Build user text by concatenating input with pre-extracted text
// (Backend only reads first text part, so we must combine them)
const parts: any[] = []
const userText = await processFilesAndAppendContent(
input,
files,
pdfData,
parts,
urlData,
)
2025-08-31 12:54:14 +09:00
// Add the combined text as the first part
parts.unshift({ type: "text", text: userText })
// Get previous XML from the last snapshot (before this message)
const snapshotKeys = Array.from(
xmlSnapshotsRef.current.keys(),
).sort((a, b) => b - a)
const previousXml =
snapshotKeys.length > 0
? xmlSnapshotsRef.current.get(snapshotKeys[0]) || ""
: ""
// Save XML snapshot for this message (will be at index = current messages.length)
const messageIndex = messages.length
xmlSnapshotsRef.current.set(messageIndex, chartXml)
sendChatMessage(parts, chartXml, previousXml, sessionId)
2025-08-31 12:54:14 +09:00
// Token count is tracked in onFinish with actual server usage
setInput("")
sessionStorage.removeItem(SESSION_STORAGE_INPUT_KEY)
setFiles([])
setUrlData(new Map())
} catch (error) {
console.error("Error fetching chart data:", error)
}
}
}
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Handle session switching from history dropdown
const handleSelectSession = useCallback(
async (sessionId: string) => {
if (!sessionManager.isAvailable) return
// Save current session before switching
if (messages.length > 0) {
const sessionData = await buildSessionData({
withThumbnail: true,
})
await sessionManager.saveCurrentSession(sessionData)
}
// Switch to selected session
const sessionData = await sessionManager.switchSession(sessionId)
if (sessionData) {
const hasRealDiagram = isRealDiagram(sessionData.diagramXml)
justLoadedSessionRef.current = true
// CRITICAL: Update latestSvgRef with the NEW session's thumbnail
// This prevents stale thumbnail from previous session being used by auto-save
latestSvgRef.current = sessionData.thumbnailDataUrl || ""
// Track if this session has no real diagram - to prevent thumbnail contamination
if (!hasRealDiagram) {
justLoadedSessionIdRef.current = sessionId
} else {
justLoadedSessionIdRef.current = null
}
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
setValidationStates({}) // Clear validation states when switching sessions
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
syncUIWithSession(sessionData)
router.replace(`?session=${sessionId}`, { scroll: false })
}
},
[sessionManager, messages, buildSessionData, syncUIWithSession, router],
)
// Handle session deletion from history dropdown
const handleDeleteSession = useCallback(
async (sessionId: string) => {
if (!sessionManager.isAvailable) return
const result = await sessionManager.deleteSession(sessionId)
if (result.wasCurrentSession) {
// Deleted current session - clear UI and URL
syncUIWithSession(null)
router.replace(pathname, { scroll: false })
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
}
},
[sessionManager, syncUIWithSession, router, pathname],
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
)
const handleNewChat = useCallback(async () => {
// Save current session before creating new one
if (sessionManager.isAvailable && messages.length > 0) {
const sessionData = await buildSessionData({ withThumbnail: true })
await sessionManager.saveCurrentSession(sessionData)
// Refresh sessions list to ensure dropdown shows the saved session
await sessionManager.refreshSessions()
}
// Clear session manager state BEFORE clearing URL to prevent race condition
// (otherwise the URL update effect would restore the old session URL)
sessionManager.clearCurrentSession()
// Clear UI state (can't use syncUIWithSession here because we also need to clear files)
setMessages([])
setInput("")
clearDiagram()
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
setDiagramHistory([])
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
setValidationStates({}) // Clear validation states to prevent memory leak
handleFileChange([]) // Use handleFileChange to also clear pdfData
setUrlData(new Map())
const newSessionId = `session-${Date.now()}-${Math.random()
.toString(36)
.slice(2, 9)}`
setSessionId(newSessionId)
xmlSnapshotsRef.current.clear()
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
sessionStorage.removeItem(SESSION_STORAGE_INPUT_KEY)
toast.success(dict.dialogs.clearSuccess)
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
// Clear URL param to show blank state
router.replace(pathname, { scroll: false })
// After starting a fresh chat, move focus back to the chat input
setShouldFocusInput(true)
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
}, [
clearDiagram,
handleFileChange,
setMessages,
setSessionId,
sessionManager,
messages,
router,
dict.dialogs.clearSuccess,
buildSessionData,
setDiagramHistory,
pathname,
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
])
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
// Handle sending a template directly (called from TemplatePanel)
const handleSendTemplate = useCallback(
async (template: { prompt: string }) => {
flushSync(() => {
setInput(template.prompt)
setFiles([])
setUrlData(new Map())
})
const formElement = document.getElementById(
"chat-form",
) as HTMLFormElement | null
if (formElement) {
formElement.requestSubmit()
}
},
[setInput, setFiles, setUrlData],
)
2025-08-31 12:54:14 +09:00
const handleInputChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
2025-08-31 12:54:14 +09:00
) => {
saveInputToSessionStorage(e.target.value)
setInput(e.target.value)
}
2025-08-31 12:54:14 +09:00
const saveInputToSessionStorage = (input: string) => {
sessionStorage.setItem(SESSION_STORAGE_INPUT_KEY, input)
}
// Helper functions for message actions (regenerate/edit)
// Extract previous XML snapshot before a given message index
const getPreviousXml = (beforeIndex: number): string => {
const snapshotKeys = Array.from(xmlSnapshotsRef.current.keys())
.filter((k) => k < beforeIndex)
.sort((a, b) => b - a)
return snapshotKeys.length > 0
? xmlSnapshotsRef.current.get(snapshotKeys[0]) || ""
: ""
}
// Restore diagram from snapshot and update ref
const restoreDiagramFromSnapshot = (savedXml: string) => {
onDisplayChart(savedXml, true) // Skip validation for trusted snapshots
chartXMLRef.current = savedXml
}
// Clean up snapshots after a given message index
const cleanupSnapshotsAfter = (messageIndex: number) => {
for (const key of xmlSnapshotsRef.current.keys()) {
if (key > messageIndex) {
xmlSnapshotsRef.current.delete(key)
}
}
}
// Handle stop button click
const handleStop = useCallback(() => {
const lastMessage = messages[messages.length - 1]
const toolParts = lastMessage?.parts?.filter(
(part: any) =>
part.type?.startsWith("tool-") &&
part.state === "input-streaming",
)
toolParts?.forEach((part: any) => {
if (part.toolCallId) {
addToolOutput({
tool: part.type.replace("tool-", ""),
toolCallId: part.toolCallId,
state: "output-error",
errorText: "Stopped by user",
})
}
})
stop()
}, [messages, addToolOutput, stop])
// Send chat message with headers
const sendChatMessage = (
parts: any,
xml: string,
previousXml: string,
sessionId: string,
) => {
feat: add append_diagram tool and improve truncation handling (#252) * feat: add append_diagram tool for truncation continuation When LLM output hits maxOutputTokens mid-generation, instead of failing with an error loop, the system now: 1. Detects truncation (missing </root> in XML) 2. Stores partial XML and tells LLM to use new append_diagram tool 3. LLM continues generating from where it stopped 4. Fragments are accumulated until XML is complete 5. Server limits to 5 steps via stepCountIs(5) Key changes: - Add append_diagram tool definition in route.ts - Add append_diagram handler in chat-panel.tsx - Track continuation mode separately from error mode - Continuation mode has unlimited retries (not counted against limit) - Error mode still limited to MAX_AUTO_RETRY_COUNT (1) - Update system prompts to document append_diagram tool * fix: show friendly message and yellow badge for truncated output - Add yellow 'Truncated' badge in UI instead of red 'Error' when XML is incomplete - Show friendly error message for toolUse.input is invalid errors - Built on top of append_diagram continuation feature * refactor: remove debug logs and simplify truncation state - Remove all debug console.log statements - Remove isContinuationModeRef, derive from partialXmlRef.current.length > 0 * docs: fix append_diagram instructions for consistency - Change 'Do NOT include' to 'Do NOT start with' (clearer intent) - Add <mxCell id="0"> to prohibited start patterns - Change 'closing tags </root></mxGraphModel>' to just '</root>' (wrapWithMxFile handles the rest)
2025-12-14 12:34:34 +09:00
// Reset all retry/continuation state on user-initiated message
autoRetryCountRef.current = 0
continuationRetryCountRef.current = 0
feat: add append_diagram tool and improve truncation handling (#252) * feat: add append_diagram tool for truncation continuation When LLM output hits maxOutputTokens mid-generation, instead of failing with an error loop, the system now: 1. Detects truncation (missing </root> in XML) 2. Stores partial XML and tells LLM to use new append_diagram tool 3. LLM continues generating from where it stopped 4. Fragments are accumulated until XML is complete 5. Server limits to 5 steps via stepCountIs(5) Key changes: - Add append_diagram tool definition in route.ts - Add append_diagram handler in chat-panel.tsx - Track continuation mode separately from error mode - Continuation mode has unlimited retries (not counted against limit) - Error mode still limited to MAX_AUTO_RETRY_COUNT (1) - Update system prompts to document append_diagram tool * fix: show friendly message and yellow badge for truncated output - Add yellow 'Truncated' badge in UI instead of red 'Error' when XML is incomplete - Show friendly error message for toolUse.input is invalid errors - Built on top of append_diagram continuation feature * refactor: remove debug logs and simplify truncation state - Remove all debug console.log statements - Remove isContinuationModeRef, derive from partialXmlRef.current.length > 0 * docs: fix append_diagram instructions for consistency - Change 'Do NOT include' to 'Do NOT start with' (clearer intent) - Add <mxCell id="0"> to prohibited start patterns - Change 'closing tags </root></mxGraphModel>' to just '</root>' (wrapWithMxFile handles the rest)
2025-12-14 12:34:34 +09:00
partialXmlRef.current = ""
feat: multi-provider model configuration with UI/UX improvements (#355) * feat: add multi-provider model configuration - Add model config dialog for managing multiple AI providers - Support for OpenAI, Anthropic, Google, Azure, Bedrock, OpenRouter, DeepSeek, SiliconFlow, Ollama, and AI Gateway - Add model selector dropdown in chat panel header - Add API key validation endpoint - Add custom model ID input with keyboard navigation - Fix hover highlight in Command component - Add suggested models for each provider including latest Claude 4.5 series - Store configuration locally in browser * feat: improve model config UI and move selector to chat input - Move model selector from header to chat input (left of send button) - Add per-model validation status (queued, running, valid, invalid) - Filter model selector to only show verified models - Add editable model IDs in config dialog - Add custom model input field alongside suggested models dropdown - Fix hover states on provider buttons and select triggers - Update OpenAI suggested models with GPT-5 series - Add alert-dialog component for delete confirmation * refactor: revert shadcn component changes, apply hover fix at usage site * feat: add AWS credentials support for Bedrock provider - Add AWS Access Key ID, Secret Access Key, Region fields for Bedrock - Show different credential fields based on provider type - Update validation API to handle Bedrock with AWS credentials - Add region selector with common AWS regions * fix: reset Test button after validation completes * fix: reset validation button to Test after success * fix: complete bedrock support and UI/UX improvements - Add bedrock to ALLOWED_CLIENT_PROVIDERS for client credentials - Pass AWS credentials through full chain (headers → API → provider) - Replace non-existent GPT-5 models with real ones (o1, o3-mini) - Add accessibility: aria-labels, focus-visible rings, inline errors - Add more AWS regions (Ohio, London, Paris, Mumbai, Seoul, São Paulo) - Fix setTimeout cleanup with useRef on component unmount - Fix TypeScript type consistency in getSelectedAIConfig fallback * chore: remove unused code - Remove unused setAccessCodeRequired state in chat-panel.tsx - Remove unused getSelectedModel export in model-config.ts * fix: UI/UX improvements for model configuration dialog - Add gradient header styling with icon badge - Change Configuration section icon from Key to Settings2 - Add duplicate model detection with warning banner and inline removal - Filter out already-added models from suggestions dropdown - Add type-to-confirm for deleting providers with 3+ models - Enhance delete confirmation dialog with warning icon - Improve model selector discoverability (show model name + chevron) - Add truncation for long model names with title tooltip - Remove AI provider settings from Settings dialog (now in Model Config) - Extract ValidationButton into reusable component * fix: prevent duplicate model IDs within same provider - Block adding model if ID already exists in provider - Block editing model ID to match existing model in provider * fix: improve duplicate model ID notifications - Add toast notification when trying to add duplicate model - Allow free typing when editing model ID, validate on blur - Show warning toast instead of blocking input * fix: improve duplicate model validation UX in config dialog - Add inline error display for duplicate model IDs - Show red border on input when error exists - Validate on blur with shake animation for edit errors - Prevent saving empty model names - Clear errors when user starts typing - Simplify error styling (small red text, no heavy chips)
2025-12-22 22:36:36 +09:00
const config = getSelectedAIConfig()
sendMessage(
{ parts },
{
body: { xml, previousXml, sessionId, customSystemMessage },
headers: {
"x-access-code": config.accessCode,
...(config.aiProvider && {
"x-ai-provider": config.aiProvider,
...(config.aiBaseUrl && {
"x-ai-base-url": config.aiBaseUrl,
}),
...(config.aiApiKey && {
"x-ai-api-key": config.aiApiKey,
}),
...(config.aiModel && { "x-ai-model": config.aiModel }),
feat: multi-provider model configuration with UI/UX improvements (#355) * feat: add multi-provider model configuration - Add model config dialog for managing multiple AI providers - Support for OpenAI, Anthropic, Google, Azure, Bedrock, OpenRouter, DeepSeek, SiliconFlow, Ollama, and AI Gateway - Add model selector dropdown in chat panel header - Add API key validation endpoint - Add custom model ID input with keyboard navigation - Fix hover highlight in Command component - Add suggested models for each provider including latest Claude 4.5 series - Store configuration locally in browser * feat: improve model config UI and move selector to chat input - Move model selector from header to chat input (left of send button) - Add per-model validation status (queued, running, valid, invalid) - Filter model selector to only show verified models - Add editable model IDs in config dialog - Add custom model input field alongside suggested models dropdown - Fix hover states on provider buttons and select triggers - Update OpenAI suggested models with GPT-5 series - Add alert-dialog component for delete confirmation * refactor: revert shadcn component changes, apply hover fix at usage site * feat: add AWS credentials support for Bedrock provider - Add AWS Access Key ID, Secret Access Key, Region fields for Bedrock - Show different credential fields based on provider type - Update validation API to handle Bedrock with AWS credentials - Add region selector with common AWS regions * fix: reset Test button after validation completes * fix: reset validation button to Test after success * fix: complete bedrock support and UI/UX improvements - Add bedrock to ALLOWED_CLIENT_PROVIDERS for client credentials - Pass AWS credentials through full chain (headers → API → provider) - Replace non-existent GPT-5 models with real ones (o1, o3-mini) - Add accessibility: aria-labels, focus-visible rings, inline errors - Add more AWS regions (Ohio, London, Paris, Mumbai, Seoul, São Paulo) - Fix setTimeout cleanup with useRef on component unmount - Fix TypeScript type consistency in getSelectedAIConfig fallback * chore: remove unused code - Remove unused setAccessCodeRequired state in chat-panel.tsx - Remove unused getSelectedModel export in model-config.ts * fix: UI/UX improvements for model configuration dialog - Add gradient header styling with icon badge - Change Configuration section icon from Key to Settings2 - Add duplicate model detection with warning banner and inline removal - Filter out already-added models from suggestions dropdown - Add type-to-confirm for deleting providers with 3+ models - Enhance delete confirmation dialog with warning icon - Improve model selector discoverability (show model name + chevron) - Add truncation for long model names with title tooltip - Remove AI provider settings from Settings dialog (now in Model Config) - Extract ValidationButton into reusable component * fix: prevent duplicate model IDs within same provider - Block adding model if ID already exists in provider - Block editing model ID to match existing model in provider * fix: improve duplicate model ID notifications - Add toast notification when trying to add duplicate model - Allow free typing when editing model ID, validate on blur - Show warning toast instead of blocking input * fix: improve duplicate model validation UX in config dialog - Add inline error display for duplicate model IDs - Show red border on input when error exists - Validate on blur with shake animation for edit errors - Prevent saving empty model names - Clear errors when user starts typing - Simplify error styling (small red text, no heavy chips)
2025-12-22 22:36:36 +09:00
// AWS Bedrock credentials
...(config.awsAccessKeyId && {
"x-aws-access-key-id": config.awsAccessKeyId,
}),
...(config.awsSecretAccessKey && {
"x-aws-secret-access-key":
config.awsSecretAccessKey,
}),
...(config.awsRegion && {
"x-aws-region": config.awsRegion,
}),
...(config.awsSessionToken && {
"x-aws-session-token": config.awsSessionToken,
}),
// Vertex AI credentials (Express Mode)
...(config.vertexApiKey && {
"x-vertex-api-key": config.vertexApiKey,
}),
}),
// Send selected model ID for server model lookup (apiKeyEnv/baseUrlEnv)
...(config.selectedModelId && {
"x-selected-model-id": config.selectedModelId,
}),
...(minimalStyle && {
"x-minimal-style": "true",
}),
fix: raise the output budget so reasoning models reach the tool call (#927) * fix: raise the output budget so reasoning models reach the tool call A reasoning model spends the output budget in order: thinking first, then prose, then the tool call. With 16000 the thinking alone can consume all of it, so the turn ends with finishReason "length" before display_diagram is ever called. The canvas stays empty and nothing surfaces in the UI, because no tool call means no tool error, and the client never reads finishReason. Measured on openrouter deepseek/deepseek-v4-flash, the model from the report: - max_tokens=800 with reasoning on returns reasoning_tokens=800, empty content, finish_reason length. So reasoning is billed against this budget, not exempt. - refining an existing diagram (19k chars of XML in the input) produced 49142 chars of reasoning, zero tool calls, finishReason "length" at 16000 - the same request at 40000 finished and called edit_diagram with 12 operations 64000 cannot just be sent to every model: bedrock claude-3-haiku caps at 4096, nova-lite at 10000, and the openrouter deepseek-r1 endpoint counts input and output against one 64000 ceiling. All three name the real limit in the 400, so parse it and retry once. Verified: nova-lite logs "64000 rejected, retrying with 10000" and then completes its tool call. Also expose the budget in Settings. It is sent as a header rather than read from env only, so desktop users can raise it themselves without an env file. vercel.json goes back to the 300s it had before #238 traded it for $2-4/month. That is now Vercel's own default, and billing pauses while the function waits on the model, so the saving that motivated 120s no longer applies. edgeone.json is left alone: its 120 may be that platform's actual ceiling. * fix: only reinterpret an error as a budget rejection when it says so Review of the first commit found the retry could fire on errors that have nothing to do with the budget, which would replace a readable provider error with a truncated response: exactly the symptom this PR exists to remove. - Drop the generic "lower than N" pattern. For the Bedrock message it was dead code, since "model limit of N" matches first with the same number. Left live, it would read a number out of any message shaped like "must be lower than 2". - Skip errors whose status is not 400 or 422, so auth and rate-limit failures are never reinterpreted. - Require the parsed ceiling to be at least 1024. Below that a diagram cannot come out whole, so retrying would hide the error behind broken XML. - Validate MAX_OUTPUT_TOKENS from env the same way as the header, so a stray "-1" falls back instead of reaching the provider. Adds tests for the retry wrapper itself, which had none: it retries once with the named ceiling, leaves a 401 alone, does not retry when the ceiling is not smaller, propagates a second rejection, and preserves the other call options. Re-verified against the live APIs: bedrock nova-lite still logs "64000 rejected, retrying with 10000" and completes its tool call, and deepseek-v4-flash still finishes normally at 64000.
2026-08-22 20:47:10 +09:00
...(maxOutputTokens && {
"x-max-output-tokens": maxOutputTokens,
}),
},
},
)
}
// Process files and append content to user text (handles PDF, text, and optionally images)
const processFilesAndAppendContent = async (
baseText: string,
files: File[],
pdfData: Map<File, FileData>,
imageParts?: any[],
urlDataParam?: Map<string, UrlData>,
): Promise<string> => {
let userText = baseText
for (const file of files) {
if (isPdfFile(file)) {
const extracted = pdfData.get(file)
if (extracted?.text) {
userText += `\n\n[PDF: ${file.name}]\n${extracted.text}`
}
} else if (isTextFile(file)) {
const extracted = pdfData.get(file)
if (extracted?.text) {
userText += `\n\n[File: ${file.name}]\n${extracted.text}`
}
} else if (imageParts) {
// Handle as image (only if imageParts array provided)
const reader = new FileReader()
const dataUrl = await new Promise<string>((resolve) => {
reader.onload = () => resolve(reader.result as string)
reader.readAsDataURL(file)
})
imageParts.push({
type: "file",
url: dataUrl,
mediaType: file.type,
})
}
}
if (urlDataParam) {
for (const [url, data] of urlDataParam) {
if (data.content) {
userText += `\n\n[URL: ${url}]\nTitle: ${data.title}\n\n${data.content}`
}
}
}
return userText
}
const handleRegenerate = async (messageIndex: number) => {
const isProcessing = status === "streaming" || status === "submitted"
if (isProcessing) return
// Find the user message before this assistant message
let userMessageIndex = messageIndex - 1
while (
userMessageIndex >= 0 &&
messages[userMessageIndex].role !== "user"
) {
userMessageIndex--
}
if (userMessageIndex < 0) return
const userMessage = messages[userMessageIndex]
const userParts = userMessage.parts
// Get the text from the user message
const textPart = userParts?.find((p: any) => p.type === "text")
if (!textPart) return
// Get the saved XML snapshot for this user message
const savedXml = xmlSnapshotsRef.current.get(userMessageIndex)
if (!savedXml) {
console.error(
"No saved XML snapshot for message index:",
userMessageIndex,
)
return
}
// Get previous XML and restore diagram state
const previousXml = getPreviousXml(userMessageIndex)
restoreDiagramFromSnapshot(savedXml)
// Clean up snapshots for messages after the user message (they will be removed)
cleanupSnapshotsAfter(userMessageIndex)
// Remove the user message AND assistant message onwards (sendMessage will re-add the user message)
// Use flushSync to ensure state update is processed synchronously before sending
const newMessages = messages.slice(0, userMessageIndex)
flushSync(() => {
setMessages(newMessages)
})
// Now send the message after state is guaranteed to be updated
sendChatMessage(userParts, savedXml, previousXml, sessionId)
}
const handleEditMessage = async (messageIndex: number, newText: string) => {
const isProcessing = status === "streaming" || status === "submitted"
if (isProcessing) return
const message = messages[messageIndex]
if (!message || message.role !== "user") return
// Get the saved XML snapshot for this user message
const savedXml = xmlSnapshotsRef.current.get(messageIndex)
if (!savedXml) {
console.error(
"No saved XML snapshot for message index:",
messageIndex,
)
return
}
// Get previous XML and restore diagram state
const previousXml = getPreviousXml(messageIndex)
restoreDiagramFromSnapshot(savedXml)
// Clean up snapshots for messages after the user message (they will be removed)
cleanupSnapshotsAfter(messageIndex)
// Create new parts with updated text
const newParts = message.parts?.map((part: any) => {
if (part.type === "text") {
return { ...part, text: newText }
}
return part
}) || [{ type: "text", text: newText }]
// Remove the user message AND assistant message onwards (sendMessage will re-add the user message)
// Use flushSync to ensure state update is processed synchronously before sending
const newMessages = messages.slice(0, messageIndex)
flushSync(() => {
setMessages(newMessages)
})
// Now send the edited message after state is guaranteed to be updated
sendChatMessage(newParts, savedXml, previousXml, sessionId)
}
// Collapsed view (desktop only)
if (!isVisible && !isMobile) {
return (
<div className="h-full flex flex-col items-center pt-4 bg-card border border-border/30 rounded-xl">
<ButtonWithTooltip
tooltipContent={dict.nav.showPanel}
variant="ghost"
size="icon"
onClick={onToggleVisibility}
className="hover:bg-accent transition-colors"
>
<PanelRightOpen className="h-5 w-5 text-muted-foreground" />
</ButtonWithTooltip>
<div
className="text-sm font-medium text-muted-foreground mt-8 tracking-wide"
style={{
writingMode: "vertical-rl",
}}
>
{dict.nav.aiChat}
</div>
</div>
)
}
// Full view
return (
<div
className={cn(
"h-full flex flex-col bg-card shadow-soft rounded-xl border border-border/30 relative",
shouldAnimatePanel && "animate-slide-in-right",
)}
>
<Toaster
position="bottom-left"
richColors
expand
toastOptions={{
style: {
maxWidth: "480px",
},
duration: 2000,
}}
/>
{/* Header */}
<header
className={`${isMobile ? "px-3 py-2" : "px-5 py-4"} border-b border-border/50`}
>
<div className="flex items-center justify-between">
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
<button
type="button"
onClick={handleNewChat}
disabled={
status === "streaming" || status === "submitted"
}
className="flex items-center gap-2 overflow-x-hidden hover:opacity-80 transition-opacity cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
title={dict.nav.newChat}
>
<div className="flex items-center gap-2">
<Image
2025-12-26 17:16:12 +05:30
src={
darkMode
? "/favicon-white.svg"
: "/favicon.ico"
}
alt="Next AI Drawio"
width={isMobile ? 24 : 28}
height={isMobile ? 24 : 28}
className="rounded flex-shrink-0"
/>
<h1
className={`${isMobile ? "text-sm" : "text-base"} font-semibold tracking-tight whitespace-nowrap`}
>
Next AI Drawio
</h1>
</div>
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
</button>
<div className="flex items-center gap-1 justify-end overflow-visible">
<ButtonWithTooltip
tooltipContent={dict.nav.newChat}
variant="ghost"
size="icon"
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
onClick={handleNewChat}
disabled={
status === "streaming" || status === "submitted"
}
className="hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed"
test: add Vitest and Playwright testing infrastructure (#512) * test: add Vitest and Playwright testing infrastructure - Add Vitest for unit tests (39 tests) - cached-responses.test.ts - ai-providers.test.ts - chat-helpers.test.ts - utils.test.ts - Add Playwright for E2E tests (3 smoke tests) - Homepage load - Japanese locale - Settings dialog - Add CI workflow (.github/workflows/test.yml) - Add vitest.config.mts and playwright.config.ts - Update .gitignore for test artifacts * test: add more E2E tests for UI components - Chat panel tests (interactive elements, iframe) - Settings tests (dark mode, language, draw.io theme) - Save dialog tests (buttons exist) - History dialog tests - Model config tests - Keyboard interaction tests - Upload area tests Total: 15 E2E tests, all passing * test: fix E2E test issues from review Fixes based on Gemini and Codex review: - Remove brittle nth(1) selector in keyboard tests - Remove waitForTimeout(500) race condition - Remove if(isVisible) silent skip patterns - Add proper assertions instead of no-op checks - Remove expect(count >= 0) that always passes - Remove unused hasProviderUI variable All 14 E2E tests and 39 unit tests pass. * style: auto-format with Biome * fix: resolve lint errors for CI * test(e2e): add diagram generation tests with mocked AI responses - Add tests for generate, edit, and append diagram operations - Use SSE mocked responses matching AI SDK UI message stream format - Generate mxCell XML directly in tests for deterministic assertions - Tests verify tool card rendering and 'Complete' badge state * test: add comprehensive E2E tests for all major features - Error handling tests (API errors, rate limits, network timeout, truncated XML) - Multi-turn conversation tests (sequential requests, history preservation) - File upload tests (upload button, file preview, sending with message) - Theme switching tests (dark mode toggle, persistence, system preference) - Language switching tests (EN/JA/ZH, persistence, locale URLs) - Iframe interaction tests (draw.io loading, toolbar, diagram rendering) - Copy/paste tests (chat input, XML input, special characters) - History restore tests (new chat, persistence, browser navigation) * refactor: extract shared test helpers and improve error assertions - Create tests/e2e/lib/helpers.ts with shared SSE mock functions - Add proper error UI assertions to error-handling.spec.ts - Remove waitForTimeout calls in favor of real assertions - Update 6 test files to use shared helpers * docs: add testing section to CONTRIBUTING.md * fix: improve test infrastructure based on PR review - Fix double build in CI: remove redundant build from playwright webServer - Export chat helpers from shared module for proper unit testing - Replace waitForTimeout with explicit waits in E2E tests - Add data-testid attributes to settings and new chat buttons - Add list reporter for CI to show failures in logs - Add Playwright browser caching to speed up CI - Add vitest coverage configuration - Fix conditional test assertions to use test.skip() instead of silent pass - Remove unused variables flagged by linter * fix: improve E2E test assertions and remove silent skips - Replace silent test.skip() with explicit conditional skips - Add actual persistence assertion after page reload - Use data-testid selector for new chat button test * refactor: add shared fixtures and test.step() patterns - Add tests/e2e/lib/fixtures.ts with shared test helpers - Add tests/e2e/fixtures/diagrams.ts with XML test data - Add expectBeforeAndAfterReload() helper for persistence tests - Add test.step() for better test reporting in complex tests - Consolidate mock helpers into fixtures module - Reduce code duplication across 17 test files * fix: make persistence tests more reliable - Remove expectBeforeAndAfterReload from mocked API tests - Add explicit test.step() for before/after reload checks - Add retry config for flaky clipboard tests - Add sleep after reload for language persistence test * test: remove flaky XML paste test * docs: run both unit and e2e tests before PR * chore: add type check and unit test git hooks --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-05 01:37:32 +09:00
data-testid="new-chat-button"
>
<MessageSquarePlus
className={`${isMobile ? "h-4 w-4" : "h-5 w-5"} text-muted-foreground`}
/>
</ButtonWithTooltip>
<ButtonWithTooltip
tooltipContent={dict.nav.settings}
variant="ghost"
size="icon"
onClick={() => setShowSettingsDialog(true)}
className="hover:bg-accent"
test: add Vitest and Playwright testing infrastructure (#512) * test: add Vitest and Playwright testing infrastructure - Add Vitest for unit tests (39 tests) - cached-responses.test.ts - ai-providers.test.ts - chat-helpers.test.ts - utils.test.ts - Add Playwright for E2E tests (3 smoke tests) - Homepage load - Japanese locale - Settings dialog - Add CI workflow (.github/workflows/test.yml) - Add vitest.config.mts and playwright.config.ts - Update .gitignore for test artifacts * test: add more E2E tests for UI components - Chat panel tests (interactive elements, iframe) - Settings tests (dark mode, language, draw.io theme) - Save dialog tests (buttons exist) - History dialog tests - Model config tests - Keyboard interaction tests - Upload area tests Total: 15 E2E tests, all passing * test: fix E2E test issues from review Fixes based on Gemini and Codex review: - Remove brittle nth(1) selector in keyboard tests - Remove waitForTimeout(500) race condition - Remove if(isVisible) silent skip patterns - Add proper assertions instead of no-op checks - Remove expect(count >= 0) that always passes - Remove unused hasProviderUI variable All 14 E2E tests and 39 unit tests pass. * style: auto-format with Biome * fix: resolve lint errors for CI * test(e2e): add diagram generation tests with mocked AI responses - Add tests for generate, edit, and append diagram operations - Use SSE mocked responses matching AI SDK UI message stream format - Generate mxCell XML directly in tests for deterministic assertions - Tests verify tool card rendering and 'Complete' badge state * test: add comprehensive E2E tests for all major features - Error handling tests (API errors, rate limits, network timeout, truncated XML) - Multi-turn conversation tests (sequential requests, history preservation) - File upload tests (upload button, file preview, sending with message) - Theme switching tests (dark mode toggle, persistence, system preference) - Language switching tests (EN/JA/ZH, persistence, locale URLs) - Iframe interaction tests (draw.io loading, toolbar, diagram rendering) - Copy/paste tests (chat input, XML input, special characters) - History restore tests (new chat, persistence, browser navigation) * refactor: extract shared test helpers and improve error assertions - Create tests/e2e/lib/helpers.ts with shared SSE mock functions - Add proper error UI assertions to error-handling.spec.ts - Remove waitForTimeout calls in favor of real assertions - Update 6 test files to use shared helpers * docs: add testing section to CONTRIBUTING.md * fix: improve test infrastructure based on PR review - Fix double build in CI: remove redundant build from playwright webServer - Export chat helpers from shared module for proper unit testing - Replace waitForTimeout with explicit waits in E2E tests - Add data-testid attributes to settings and new chat buttons - Add list reporter for CI to show failures in logs - Add Playwright browser caching to speed up CI - Add vitest coverage configuration - Fix conditional test assertions to use test.skip() instead of silent pass - Remove unused variables flagged by linter * fix: improve E2E test assertions and remove silent skips - Replace silent test.skip() with explicit conditional skips - Add actual persistence assertion after page reload - Use data-testid selector for new chat button test * refactor: add shared fixtures and test.step() patterns - Add tests/e2e/lib/fixtures.ts with shared test helpers - Add tests/e2e/fixtures/diagrams.ts with XML test data - Add expectBeforeAndAfterReload() helper for persistence tests - Add test.step() for better test reporting in complex tests - Consolidate mock helpers into fixtures module - Reduce code duplication across 17 test files * fix: make persistence tests more reliable - Remove expectBeforeAndAfterReload from mocked API tests - Add explicit test.step() for before/after reload checks - Add retry config for flaky clipboard tests - Add sleep after reload for language persistence test * test: remove flaky XML paste test * docs: run both unit and e2e tests before PR * chore: add type check and unit test git hooks --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-05 01:37:32 +09:00
data-testid="settings-button"
>
<Settings
className={`${isMobile ? "h-4 w-4" : "h-5 w-5"} text-muted-foreground`}
/>
</ButtonWithTooltip>
<div className="hidden sm:flex items-center gap-2">
{!isMobile && (
<ButtonWithTooltip
tooltipContent={dict.nav.hidePanel}
variant="ghost"
size="icon"
className="hover:bg-accent"
onClick={onToggleVisibility}
>
<PanelRightClose className="h-5 w-5 text-muted-foreground" />
</ButtonWithTooltip>
)}
</div>
</div>
</div>
</header>
{/* Messages */}
<main className="flex-1 w-full overflow-hidden">
<ChatMessageDisplay
messages={messages}
setInput={setInput}
setFiles={handleFileChange}
processedToolCallsRef={processedToolCallsRef}
editDiagramOriginalXmlRef={editDiagramOriginalXmlRef}
sessionId={sessionId}
onRegenerate={handleRegenerate}
feat: Display AI reasoning/thinking blocks in chat interface (#152) * feat: Add reasoning/thinking blocks display in chat interface * feat: add multi-provider options support and replace custom reasoning UI with AI Elements * resolve conflicting reasoning configs and correct provider-specific reasoning parameters * try to solve conflict * fix: simplify reasoning display and remove unnecessary dependencies - Remove Streamdown dependency (~5MB) - reasoning is plain text only - Fix Bedrock providerOptions merging for Claude reasoning configs - Remove unsupported DeepSeek reasoning configuration - Clean up unused environment variables (REASONING_BUDGET_TOKENS, REASONING_EFFORT, DEEPSEEK_REASONING_*) - Remove dead commented code from route.ts Reasoning blocks contain plain thinking text and don't need markdown/diagram/code rendering. * feat: comprehensive reasoning support improvements Major improvements: - Auto-enable reasoning display for all supported models - Fix provider-specific reasoning configurations - Remove unnecessary Streamdown dependency (~5MB) - Clean up debug logging Provider changes: - OpenAI: Auto-enable reasoningSummary for o1/o3/gpt-5 models - Google: Auto-enable includeThoughts for Gemini 2.5/3 models - Bedrock: Restrict reasoningConfig to only Claude/Nova (fixes MiniMax error) - Ollama: Add thinking support for qwen3-like models Other improvements: - Remove ENABLE_REASONING toggle (always enabled) - Fix Bedrock providerOptions merging for Claude - Simplify reasoning component (plain text rendering) - Clean up unused environment variables * fix: critical bugs and documentation gaps in reasoning support Critical fixes: - Fix Bedrock shallow merge bug (deep merge preserves anthropicBeta + reasoningConfig) - Add parseInt validation with parseIntSafe helper (prevents NaN errors) - Validate all numeric env vars with min/max ranges Documentation improvements: - Add BEDROCK_REASONING_BUDGET_TOKENS and BEDROCK_REASONING_EFFORT to env.example - Add OLLAMA_ENABLE_THINKING to env.example - Update JSDoc with accurate env var list and ranges Code cleanup: - Remove debug console.log statements from route.ts - Refactor duplicate providerOptions assignments --------- Co-authored-by: Dayuan Jiang <34411969+DayuanJiang@users.noreply.github.com> Co-authored-by: Dayuan Jiang <jdy.toh@gmail.com>
2025-12-10 20:54:43 +05:30
status={status}
onEditMessage={handleEditMessage}
isRestored={isRestored}
feat: add chat session history with IndexedDB persistence (#500) * feat(session): add chat session history with IndexedDB storage - Add session-storage.ts with IndexedDB wrapper using idb library - Add use-session-manager.ts hook for session state management - Add session-history-dropdown.tsx for session selection UI - Integrate session system into chat-panel.tsx - Auto-generate session titles from first user message - Auto-save sessions on message completion - Support session switching, deletion, and creation - Migrate existing localStorage data to IndexedDB - Add i18n translations for session history UI * feat(session): improve history dropdown and persist diagram history - Add time-based grouping (Today, Yesterday, This Week, Earlier) - Add thumbnail previews using Next.js Image component - Add staggered entrance animations with fade-in effects - Improve active session indicator with left border accent - Fix scrolling by using native overflow instead of ScrollArea - Persist diagram version history to IndexedDB sessions - Remove redundant diagram XML from localStorage - Add i18n strings for time group labels (en, ja, zh) * fix(session): prevent data loss on theme change and tab close - Add isDrawioReady effect to restore diagram after DrawIO remount - Add visibilitychange handler to save session when page becomes hidden - Fix missing currentSessionId in saveCurrentSession dependency array - Remove unused sanitizeMessages import from use-session-manager * fix(session): fix diagram save and migration data loss bugs - Add diagramHistory to save effect dependency array so diagram-only edits trigger saves (previously only message changes did) - Destructure stable sessionManager values to prevent unnecessary effect re-runs on every render - Add try-catch wrapper around debounced async save operation - Make saveSession() return boolean to indicate success/failure - Verify IndexedDB write succeeded before deleting localStorage data during migration (prevents data loss if write silently fails) - Keep localStorage data for retry if migration fails instead of marking as complete anyway * refactor(session): extract helpers to reduce code duplication - Add syncUIWithSession helper to consolidate 4 duplicate UI sync blocks - Add buildSessionData helper to consolidate 4 duplicate save logic blocks - Remove unused saveTimeoutRef and its cleanup effect - Net reduction of ~80 lines of duplicate code * style(ui): improve history dropdown and delete dialog styling - Change destructive color from coral to muted rose for refined look - Make session history panel taller (400px fixed height) - Fix popover alignment to prevent truncation - Style delete button with soft red outline instead of solid fill - Make delete dialog more compact (max-w-sm) * fix(session): reset refs on new chat and show recent sessions - Fix cached example diagrams not displaying after creating new session - Reset previousXML, lastProcessedXmlRef and processedToolCalls when messages become empty (new chat or session switch) - Add recent chats section in empty chat state with collapsible examples - Pass sessions and onSelectSession to ChatMessageDisplay - Add loadedMessageIdsRef to skip animations on session restore - Add debug console.log for diagram processing flow * feat(session): add search bar and improve history UI - Remove session history dropdown, use main panel instead - Add search bar to filter history chats by title - Show minutes (Xm ago) instead of "Just now" for recent sessions - Scroll to top when switching to new/empty chat - Remove title truncation limit for better searchability - Remove debug console.log statements * refactor: remove redundant code and fix nested button hydration error - Remove unused 'sessions' from deleteSession dependency array - Remove unused 'switchedTo' variable and simplify return type - Remove unused 'restoredMessageIdsRef' (always empty) - Fix nested button hydration error by using div with role=button - Simplify handleDeleteSession callback * fix(session): fix migration bug, improve metadata perf, truncate titles - Fix migration retry loop when localStorage has empty array - Use cursor-based iteration for getAllSessionMetadata - Truncate session titles to 100 chars with ellipsis * refactor: remove dead code and extract diagram length constant - Remove unused exports: getAllSessions, createNewSession, updateSessionTitle - Remove write-only CURRENT_SESSION_KEY and all localStorage calls - Remove dead messagesEndRef and unused scroll effect - Extract magic number 300 to MIN_REAL_DIAGRAM_LENGTH constant - Add isRealDiagram() helper function for semantic clarity
2026-01-04 10:25:19 +09:00
sessions={sessionManager.sessions}
onSelectSession={handleSelectSession}
onDeleteSession={handleDeleteSession}
loadedMessageIdsRef={loadedMessageIdsRef}
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
validationStates={validationStates}
onImproveWithSuggestions={handleImproveWithSuggestions}
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
onSendTemplate={handleSendTemplate}
currentInput={input}
/>
</main>
{/* Dev XML Streaming Simulator - only in development */}
{DEBUG && (
<DevXmlSimulator
setMessages={setMessages}
onDisplayChart={onDisplayChart}
onShowQuotaToast={() =>
quotaManager.showQuotaLimitToast(50, 50)
}
/>
)}
{/* Input */}
<footer
className={`${isMobile ? "p-2" : "p-4"} border-t border-border/50 bg-card/50`}
>
<ChatInput
input={input}
status={status}
onSubmit={onFormSubmit}
onChange={handleInputChange}
onStop={handleStop}
files={files}
onFileChange={handleFileChange}
pdfData={pdfData}
urlData={urlData}
onUrlChange={setUrlData}
sessionId={sessionId}
error={error}
feat: multi-provider model configuration with UI/UX improvements (#355) * feat: add multi-provider model configuration - Add model config dialog for managing multiple AI providers - Support for OpenAI, Anthropic, Google, Azure, Bedrock, OpenRouter, DeepSeek, SiliconFlow, Ollama, and AI Gateway - Add model selector dropdown in chat panel header - Add API key validation endpoint - Add custom model ID input with keyboard navigation - Fix hover highlight in Command component - Add suggested models for each provider including latest Claude 4.5 series - Store configuration locally in browser * feat: improve model config UI and move selector to chat input - Move model selector from header to chat input (left of send button) - Add per-model validation status (queued, running, valid, invalid) - Filter model selector to only show verified models - Add editable model IDs in config dialog - Add custom model input field alongside suggested models dropdown - Fix hover states on provider buttons and select triggers - Update OpenAI suggested models with GPT-5 series - Add alert-dialog component for delete confirmation * refactor: revert shadcn component changes, apply hover fix at usage site * feat: add AWS credentials support for Bedrock provider - Add AWS Access Key ID, Secret Access Key, Region fields for Bedrock - Show different credential fields based on provider type - Update validation API to handle Bedrock with AWS credentials - Add region selector with common AWS regions * fix: reset Test button after validation completes * fix: reset validation button to Test after success * fix: complete bedrock support and UI/UX improvements - Add bedrock to ALLOWED_CLIENT_PROVIDERS for client credentials - Pass AWS credentials through full chain (headers → API → provider) - Replace non-existent GPT-5 models with real ones (o1, o3-mini) - Add accessibility: aria-labels, focus-visible rings, inline errors - Add more AWS regions (Ohio, London, Paris, Mumbai, Seoul, São Paulo) - Fix setTimeout cleanup with useRef on component unmount - Fix TypeScript type consistency in getSelectedAIConfig fallback * chore: remove unused code - Remove unused setAccessCodeRequired state in chat-panel.tsx - Remove unused getSelectedModel export in model-config.ts * fix: UI/UX improvements for model configuration dialog - Add gradient header styling with icon badge - Change Configuration section icon from Key to Settings2 - Add duplicate model detection with warning banner and inline removal - Filter out already-added models from suggestions dropdown - Add type-to-confirm for deleting providers with 3+ models - Enhance delete confirmation dialog with warning icon - Improve model selector discoverability (show model name + chevron) - Add truncation for long model names with title tooltip - Remove AI provider settings from Settings dialog (now in Model Config) - Extract ValidationButton into reusable component * fix: prevent duplicate model IDs within same provider - Block adding model if ID already exists in provider - Block editing model ID to match existing model in provider * fix: improve duplicate model ID notifications - Add toast notification when trying to add duplicate model - Allow free typing when editing model ID, validate on blur - Show warning toast instead of blocking input * fix: improve duplicate model validation UX in config dialog - Add inline error display for duplicate model IDs - Show red border on input when error exists - Validate on blur with shake animation for edit errors - Prevent saving empty model names - Clear errors when user starts typing - Simplify error styling (small red text, no heavy chips)
2025-12-22 22:36:36 +09:00
models={modelConfig.models}
selectedModelId={modelConfig.selectedModelId}
onModelSelect={modelConfig.setSelectedModelId}
onConfigureModels={() => setShowModelConfigDialog(true)}
showUnvalidatedModels={modelConfig.showUnvalidatedModels}
shouldFocus={shouldFocusInput}
onFocused={() => setShouldFocusInput(false)}
/>
</footer>
<SettingsDialog
open={showSettingsDialog}
onOpenChange={setShowSettingsDialog}
drawioUi={drawioUi}
onDrawioUiChange={onDrawioUiChange}
darkMode={darkMode}
onToggleDarkMode={onToggleDarkMode}
minimalStyle={minimalStyle}
onMinimalStyleChange={setMinimalStyle}
Add VLM-based diagram validation (#602) * [Feature] Add VLM-based diagram validation Add automatic VLM (Vision Language Model) validation after display_diagram tool execution. The system captures a screenshot of the rendered diagram, sends it to a VLM for visual analysis, and uses feedback to improve diagram quality through the existing retry mechanism. Changes: - Add /api/validate-diagram endpoint for VLM validation - Add diagram-validator.ts for client-side validation orchestration - Add validation-prompts.ts for VLM system prompts - Add ValidationCard component to display validation status in chat - Add PNG capture functionality to diagram context - Integrate validation into tool handlers with retry support (max 3) - Add "Improve with Suggestions" button for manual regeneration - Add settings toggle to enable/disable VLM validation - Add getValidationModel() helper in ai-providers.ts * refactor(validation): use AI SDK structured outputs and address review feedback - Replace generateText + manual JSON parsing with generateObject and Zod schema for type-safe structured validation output - Use AbortSignal.timeout() instead of Promise.race for cleaner timeout handling - Add timeout validation with minimum 1000ms to handle malformed env values - Remove unused xml parameter from validateRenderedDiagram API - Remove parseValidationResponse function (now handled by schema) - Clear validationStates on session switch and new chat to prevent memory leak - Update 100ms render delay comment to clarify best-effort heuristic - Remove unused useEffect import from ValidationCard - Fix optional chaining lint warning in ValidationCard - Add unit tests for formatValidationFeedback function * refactor(validation): use AI SDK experimental_useObject hook instead of raw fetch - Change API endpoint from generateObject to streamObject for useObject compatibility - Create useValidateDiagram hook using AI SDK's experimental_useObject for reactive validation - Update useDiagramToolHandlers to accept validation function as parameter - Update chat-panel to use new useValidateDiagram hook - Remove validateRenderedDiagram function from lib/diagram-validator.ts (now in hook) - Export ValidationResultSchema from API route for client-side use * fix(validation): extract schema to shared file for client/server compatibility Move ValidationResultSchema to lib/validation-schema.ts to avoid importing server-side modules (ai-providers) into client-side code. This fixes the Turbopack build error caused by the hook importing from the API route. * fix(validation): use 'Valid' instead of 'Complete' for validation success Change ValidationCard success label from 'Complete' to 'Valid' to avoid conflicting with ToolCallCard's 'Complete' badge in E2E tests. This fixes the diagram-generation E2E test that expects a specific count of 'Complete' badges. * fix(validation): add aria-hidden to icons to prevent duplicate ID warning * fix: improve VLM validation with bug fixes and i18n - Fix race condition in pendingValidationRef (reject previous pending validation) - Fix response format consistency (use streaming for all responses) - Remove dead code (unused lastRequestRef and ValidationRequest interface) - Consolidate duplicate types (re-export from validation-schema.ts) - Add 'success_with_warnings' status for valid diagrams with warnings - Fix tool card auto-collapse (only collapse once, respect user toggle) - Set VLM validation default to disabled - Add i18n support for diagram validation settings (en/zh/ja) - Mark feature as experimental in settings UI * fix: resolve TypeScript errors in electron-standalone - Add forwardRef support to ChatInput component with ChatInputRef type - Copy electron.d.ts to electron-standalone/electron folder - Exclude electron-standalone from root tsconfig type checking * fix: return empty string for valid result with no issues in formatValidationFeedback * feat(i18n): add validation strings for ValidationCard component - Add validation section to en.json, zh.json, ja.json dictionaries - Update ValidationCard to use useDictionary hook - Replace all hardcoded English strings with i18n keys --------- Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-01-20 20:52:04 +09:00
vlmValidationEnabled={vlmValidationEnabled}
onVlmValidationChange={handleVlmValidationChange}
customSystemMessage={customSystemMessage}
onCustomSystemMessageChange={handleCustomSystemMessageChange}
fix: raise the output budget so reasoning models reach the tool call (#927) * fix: raise the output budget so reasoning models reach the tool call A reasoning model spends the output budget in order: thinking first, then prose, then the tool call. With 16000 the thinking alone can consume all of it, so the turn ends with finishReason "length" before display_diagram is ever called. The canvas stays empty and nothing surfaces in the UI, because no tool call means no tool error, and the client never reads finishReason. Measured on openrouter deepseek/deepseek-v4-flash, the model from the report: - max_tokens=800 with reasoning on returns reasoning_tokens=800, empty content, finish_reason length. So reasoning is billed against this budget, not exempt. - refining an existing diagram (19k chars of XML in the input) produced 49142 chars of reasoning, zero tool calls, finishReason "length" at 16000 - the same request at 40000 finished and called edit_diagram with 12 operations 64000 cannot just be sent to every model: bedrock claude-3-haiku caps at 4096, nova-lite at 10000, and the openrouter deepseek-r1 endpoint counts input and output against one 64000 ceiling. All three name the real limit in the 400, so parse it and retry once. Verified: nova-lite logs "64000 rejected, retrying with 10000" and then completes its tool call. Also expose the budget in Settings. It is sent as a header rather than read from env only, so desktop users can raise it themselves without an env file. vercel.json goes back to the 300s it had before #238 traded it for $2-4/month. That is now Vercel's own default, and billing pauses while the function waits on the model, so the saving that motivated 120s no longer applies. edgeone.json is left alone: its 120 may be that platform's actual ceiling. * fix: only reinterpret an error as a budget rejection when it says so Review of the first commit found the retry could fire on errors that have nothing to do with the budget, which would replace a readable provider error with a truncated response: exactly the symptom this PR exists to remove. - Drop the generic "lower than N" pattern. For the Bedrock message it was dead code, since "model limit of N" matches first with the same number. Left live, it would read a number out of any message shaped like "must be lower than 2". - Skip errors whose status is not 400 or 422, so auth and rate-limit failures are never reinterpreted. - Require the parsed ceiling to be at least 1024. Below that a diagram cannot come out whole, so retrying would hide the error behind broken XML. - Validate MAX_OUTPUT_TOKENS from env the same way as the header, so a stray "-1" falls back instead of reaching the provider. Adds tests for the retry wrapper itself, which had none: it retries once with the named ceiling, leaves a 401 alone, does not retry when the ceiling is not smaller, propagates a second rejection, and preserves the other call options. Re-verified against the live APIs: bedrock nova-lite still logs "64000 rejected, retrying with 10000" and completes its tool call, and deepseek-v4-flash still finishes normally at 64000.
2026-08-22 20:47:10 +09:00
maxOutputTokens={maxOutputTokens}
onMaxOutputTokensChange={handleMaxOutputTokensChange}
onOpenModelConfig={() => setShowModelConfigDialog(true)}
/>
feat: multi-provider model configuration with UI/UX improvements (#355) * feat: add multi-provider model configuration - Add model config dialog for managing multiple AI providers - Support for OpenAI, Anthropic, Google, Azure, Bedrock, OpenRouter, DeepSeek, SiliconFlow, Ollama, and AI Gateway - Add model selector dropdown in chat panel header - Add API key validation endpoint - Add custom model ID input with keyboard navigation - Fix hover highlight in Command component - Add suggested models for each provider including latest Claude 4.5 series - Store configuration locally in browser * feat: improve model config UI and move selector to chat input - Move model selector from header to chat input (left of send button) - Add per-model validation status (queued, running, valid, invalid) - Filter model selector to only show verified models - Add editable model IDs in config dialog - Add custom model input field alongside suggested models dropdown - Fix hover states on provider buttons and select triggers - Update OpenAI suggested models with GPT-5 series - Add alert-dialog component for delete confirmation * refactor: revert shadcn component changes, apply hover fix at usage site * feat: add AWS credentials support for Bedrock provider - Add AWS Access Key ID, Secret Access Key, Region fields for Bedrock - Show different credential fields based on provider type - Update validation API to handle Bedrock with AWS credentials - Add region selector with common AWS regions * fix: reset Test button after validation completes * fix: reset validation button to Test after success * fix: complete bedrock support and UI/UX improvements - Add bedrock to ALLOWED_CLIENT_PROVIDERS for client credentials - Pass AWS credentials through full chain (headers → API → provider) - Replace non-existent GPT-5 models with real ones (o1, o3-mini) - Add accessibility: aria-labels, focus-visible rings, inline errors - Add more AWS regions (Ohio, London, Paris, Mumbai, Seoul, São Paulo) - Fix setTimeout cleanup with useRef on component unmount - Fix TypeScript type consistency in getSelectedAIConfig fallback * chore: remove unused code - Remove unused setAccessCodeRequired state in chat-panel.tsx - Remove unused getSelectedModel export in model-config.ts * fix: UI/UX improvements for model configuration dialog - Add gradient header styling with icon badge - Change Configuration section icon from Key to Settings2 - Add duplicate model detection with warning banner and inline removal - Filter out already-added models from suggestions dropdown - Add type-to-confirm for deleting providers with 3+ models - Enhance delete confirmation dialog with warning icon - Improve model selector discoverability (show model name + chevron) - Add truncation for long model names with title tooltip - Remove AI provider settings from Settings dialog (now in Model Config) - Extract ValidationButton into reusable component * fix: prevent duplicate model IDs within same provider - Block adding model if ID already exists in provider - Block editing model ID to match existing model in provider * fix: improve duplicate model ID notifications - Add toast notification when trying to add duplicate model - Allow free typing when editing model ID, validate on blur - Show warning toast instead of blocking input * fix: improve duplicate model validation UX in config dialog - Add inline error display for duplicate model IDs - Show red border on input when error exists - Validate on blur with shake animation for edit errors - Prevent saving empty model names - Clear errors when user starts typing - Simplify error styling (small red text, no heavy chips)
2025-12-22 22:36:36 +09:00
<ModelConfigDialog
open={showModelConfigDialog}
onOpenChange={setShowModelConfigDialog}
modelConfig={modelConfig}
/>
</div>
)
}