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.
* feat: add all Draw.io themes to settings panel
Add all available Draw.io themes (kennedy, atlas, dark, min, sketch, simple)
to the settings panel dropdown. Previously only min and sketch were available
as a toggle button.
Changes:
- Replace the Draw.io style toggle button with a dropdown selector
- Expand theme type from "min" | "sketch" to include all 6 themes
- Update localStorage validation to accept all themes
- Update handler from toggle to direct theme selection
Closes#499
* fix: localize theme labels, tighten DrawioTheme typing, sync dark param
- Move DRAWIO_THEMES + DrawioTheme to lib/drawio-themes.ts; reuse in
page.tsx, chat-panel.tsx and settings-dialog.tsx instead of `string`
- Localize theme dropdown labels (Dark/Minimal/Sketch/Simple) in
en/zh/ja/zh-Hant; keep proper-noun themes (Kennedy/Atlas) as-is
- Drop trailing colon from drawioStyleDescription and remove dead
switchTo/minimal/sketch keys in all 4 dictionaries
- Auto-sync drawio dark URL param when ui="dark" is selected
- Add aria-label to drawio-style SelectTrigger
* fix: use kennedy as default theme and label it "Default"
---------
Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
When ACCESS_CODE_LIST is configured on the server, the settings dialog
was not showing the access code input field in two cases:
1. Stale localStorage cache: if a user had previously visited without
ACCESS_CODE_LIST enabled, the cached value of accessCodeRequired=false
would be used indefinitely, hiding the password input.
2. Race condition on first visit: the dialog could open triggered
by an auth error before the async fetch to /api/config completed,
showing a blank settings dialog with no access code field.
Fix by re-fetching /api/config whenever the dialog opens (on open
change) instead of only once on mount with a cache guard. The cached
value in localStorage is still updated on success, keeping the fast
initial render intact while ensuring the dialog always reflects the
server configuration.
Fixes#811
Co-authored-by: octo-patch <octo-patch@github.com>
* 增加了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>
* feat: add custom system message setting for AI personalization
Allow users to enter custom instructions via a textarea in Settings
that get appended to the AI's system prompt. Includes server-side
validation (type check + 5000 char limit), localStorage persistence,
and i18n support for all 4 locales.
* fix: add accessibility htmlFor/id pairing on custom system message textarea
Add full Traditional Chinese support for Hong Kong/Taiwan users by
creating a zh-Hant dictionary and registering the locale across the
web app, metadata, and Electron desktop menu system.
* [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>
* i18n: add translations for send shortcut setting
* feat: configurable keyboard shortcut for sending messages
* refactor,review: using storage key for send shortcut
* Increase the width of the trigger in the settings dialog. Previously, at 160px, it hide the letter “d” from the word “Send.”
* Update components/chat-input.tsx
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: from review, ctrl send support for mac
* refactor: from review, reduce local storage read
* fix: make send shortcut setting reactive without page refresh
---------
Co-authored-by: Biki Kalita <86558912+Biki-dev@users.noreply.github.com>
Co-authored-by: Dayuan Jiang <34411969+DayuanJiang@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
- Remove About link and sponsor notice icon from chat panel header
- Remove language switcher (English | 中文 | 日本語) from all about pages
- Fix About link in settings dialog to use current language
- Remove unused sponsorTooltip translation key from all dictionaries
* fix: move History and Download buttons to Settings dialog for cleaner chat interface
* fix: cleanup unused imports/props, add i18n for diagram style
* fix: use npx directly to avoid package-lock.json changes in CI
---------
Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
- Use fixed port 61337 in production instead of random ports (10000-65535)
- localStorage is origin-specific, so random ports caused settings loss
- Add locale save/restore since language is URL-based
- Fixes#399
- Add CSS design system tokens (surfaces, borders, animations) to globals.css
- Update dialog.tsx with rounded-2xl, shadow-dialog, refined close button
- Enhance input.tsx with rounded-xl and refined focus states
- Refactor settings-dialog with SettingItem pattern and consistent control sizing
- Refactor model-config-dialog with ConfigSection/ConfigCard helpers
- Replace emerald-* classes with success design tokens
- Remove unused ValidationButton component and scrollState
* feat: support subdirectory deployment (NEXT_PUBLIC_BASE_PATH)
* removed unwanted check and fix favicon issue
* Use getAssetUrl for manifest assets to avoid undefined NEXT_PUBLIC_BASE_PATH
* Add validation warning for NEXT_PUBLIC_BASE_PATH format
---------
Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
* fix:custom model setting bug
* refactor: consolidate aiProvider checks for cleaner code
* fix:Integrated the language selection option into the `SettingsDialog`
* fix:useSearchParams() should be wrapped in a suspense boundary at page
* fix: improve semantic HTML and maintainability
- Replace nested button>a with proper anchor element for GitHub link
- Use i18n.locales.map() with LANGUAGE_LABELS for language options
---------
Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
* 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)
Summary
- Adds browser theme detection on first visit using
prefers-color-scheme media query
- Renames localStorage key from dark-mode to
next-ai-draw-io-dark-mode for consistency with other keys
- Uses STORAGE_DIAGRAM_XML_KEY constant instead of hardcoded
string in diagram-context.tsx
Changes
app/page.tsx:
- On first visit (no saved preference), detect browser's color
scheme preference
- Update localStorage key to follow project naming convention
(next-ai-draw-io-*)
contexts/diagram-context.tsx:
- Import STORAGE_DIAGRAM_XML_KEY from chat-panel.tsx
- Replace hardcoded "next-ai-draw-io-diagram-xml" with the
constant
- Add AI provider settings to config panel (provider, model, API key, base URL)
- Support 7 providers: OpenAI, Anthropic, Google, Azure, OpenRouter, DeepSeek, SiliconFlow
- Client API keys stored in localStorage, never stored on server
- Client settings override server env vars when provided
- Skip server credential validation when client provides API key
- Bypass usage limits (request/token/TPM) when using own API key
- Add /api/config endpoint for fetching usage limits
- Add privacy notices to settings dialog, about pages, and quota toast
- Add clear settings button to reset saved API keys
- Update README files (EN/CN/JA) with BYOK documentation
Co-authored-by: dayuan.jiang <jiangdy@amazon.co.jp>
- Add Close Protection toggle to Settings dialog
- Save setting to localStorage (default: enabled)
- Make beforeunload confirmation conditional
- Settings button now always visible in header
- Add shadcn Switch and Label components
- Add Biome as formatter and linter (replaces Prettier)
- Configure Husky + lint-staged for pre-commit hooks
- Add VS Code settings for format on save
- Ignore components/ui/ (shadcn generated code)
- Remove semicolons, use 4-space indent
- Reformat all files to new style