* 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)
* feat: add get_shape_library tool for AI icon discovery
- Add server-side tool that returns shape library documentation
- AI can fetch icon/shape names on-demand before generating diagrams
- Includes path traversal protection and input sanitization
- Library index embedded in tool description for discoverability
- Supports 33 libraries: AWS, Azure, GCP, Kubernetes, Cisco, etc.
* fix: improve get_shape_library error handling and imports
- Move fs/path imports to top of file (avoid dynamic imports per call)
- Distinguish file-not-found vs other errors in catch block
- Include invalid input in validation error message
- Log unexpected errors for debugging
* docs: add get_shape_library to system prompt tool list
- Add Tool4 (get_shape_library) to available tools section
- Add usage guidance in 'Choose the right tool' section
- Update AWS icons note to reference get_shape_library for icon discovery
* fix: display get_shape_library tool output in chat UI
* fix: correct state check for get_shape_library output display
* fix: make get_shape_library output respect fold state
* style: auto-format with Biome
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* refactor: replace text-based edit_diagram with ID-based operations
- Add applyDiagramOperations() function using DOMParser for ID lookup
- New schema: operations array with type (update/add/delete), cell_id, new_xml
- Update chat-panel.tsx handler for new operations format
- Update OperationsDisplay component to show operation type and cell_id
- Simplify system prompts with new ID-based examples
- Add ID validation for add operations
- Add warning for edges referencing deleted cells
* fix: add ID validation to update operation and remove dead code
- Add ID mismatch validation to update operation (consistency with add)
- Remove orphaned replaceXMLParts function (~300 lines of dead code)
- Update cell_id schema description for clarity
- Add unit tests for applyDiagramOperations (11 tests)
* feat: add minimal style mode toggle for faster diagram generation
- Add Minimal/Styled toggle switch in chat input UI
- When enabled, removes color/style instructions from system prompt
- Faster generation with plain black/white diagrams
- Improves XML auto-fix: handle foreign tags, extra closing tags, trailing garbage
- Fix isMxCellXmlComplete to strip Anthropic function-calling wrappers
- Add debug logging for truncation detection diagnosis
* fix: prevent false XML parse errors during streaming
- Escape unescaped & characters in convertToLegalXml() before DOMParser validation
- Only log console.error for final output, not during streaming updates
- Prevents Next.js dev mode error overlay from showing for expected streaming states
* refactor: simplify LLM XML format to output bare mxCells only
- Update wrapWithMxFile() to always add root cells (id=0, id=1) automatically
- LLM now generates only mxCell elements starting from id=2 (no wrapper tags)
- Update system prompts and tool descriptions with new format instructions
- Update cached responses to remove root cells and wrapper tags
- Update truncation detection to check for complete mxCell endings
- Update documentation in xml_guide.md
* fix: address PR review issues for XML format refactor
- Fix critical bug: inconsistent truncation check using old </root> pattern
- Fix stale error message referencing </root> tag
- Add isMxCellXmlComplete() helper for consistent truncation detection
- Improve regex patterns to handle any attribute order in root cells
- Update wrapWithMxFile JSDoc to document root cell removal behavior
* fix: handle non-self-closing root cells in wrapWithMxFile regex
* 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)
Some models (e.g. minimax) copy placeholder text instead of generating
fresh XML, causing tool call validation failures and infinite loops.
Added ENABLE_HISTORY_XML_REPLACE env var (default: false) to control
this behavior.
- Add client-side PDF text extraction using unpdf library
- Support text files (.txt, .md, .json, .csv, .py, .js, .ts, etc.)
- Add file preview with character count for PDF/text files
- Add 150k character limit for extracted content
- Highlight Paper to Diagram example with NEW badge
- Fix React hydration error by adding explicit IDs to ResizablePanelGroup
- Remove code duplication by centralizing file utilities in pdf-utils.ts
- Add replaceHistoricalToolInputs to replace XML in tool calls with placeholders
- Send both previousXml and current xml so LLM can understand user's manual edits
- Update system message to mark current XML as authoritative source of truth
- Fix React StrictMode issue with blob URL cleanup in FilePreviewList
- Add unoptimized prop to Image components for blob URLs
- 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>
* feat: support minimax model with XML wrapping fix
- Add wrapWithMxFile utility to properly wrap XML for draw.io
- Fix 'Not a diagram file' error when model generates raw <root> XML
- Add supportsPromptCaching check for conditional caching
- Only enable Bedrock prompt caching for Claude models
* docs: update model mention to minimax-m2 across About pages and READMEs
- Update tooltip in chat-panel.tsx to mention minimax-m2 model change
- Update English, Chinese, and Japanese About pages with model change info
- Update English, Chinese, and Japanese READMEs with demo site model note
---------
Co-authored-by: dayuan.jiang <jiangdy@amazon.co.jp>
* feat: add daily token limit with actual usage tracking
- Add DAILY_TOKEN_LIMIT env var for configurable daily token limit
- Track actual tokens from Bedrock API response metadata (not estimates)
- Server sends inputTokens + cachedInputTokens + outputTokens via messageMetadata
- Client increments token count in onFinish callback with actual usage
- Add NaN guards to prevent corrupted localStorage values
- Add token limit toast notification with quota display
- Remove client-side token estimation (was blocking legitimate requests)
- Switch to js-tiktoken for client compatibility (pure JS, no WASM)
* feat: add TPM (tokens per minute) rate limiting
- Add 50k tokens/min client-side rate limit
- Track tokens per minute with automatic minute rollover
- Check TPM limit after daily limits pass
- Show toast when rate limit reached
- NaN guards for localStorage values
* feat: make TPM limit configurable via TPM_LIMIT env var
* chore: restore cache debug logs
* fix: prevent race condition in TPM tracking
checkTPMLimit was resetting TPM count to 0 when checking, which
overwrote the count saved by incrementTPMCount. Now checkTPMLimit
only reads and incrementTPMCount handles all writes.
* chore: improve TPM limit error message clarity
- Fix bug where text after tool calls was merged with initial text
- Group consecutive text/file parts into bubbles while keeping tools in order
- Parts now display as: plan -> tool_result -> additional text
- Remove debug logs from fixToolCallInputs function
Co-authored-by: dayuan.jiang <jiangdy@amazon.co.jp>
- Add client-side cache check in onFormSubmit to bypass API calls for example prompts
- Use findCachedResponse to match input against cached examples
- Directly set messages with cached tool response when example matches
- Hide regenerate button for cached example responses (toolCallId starts with 'cached-')
- Prevents unnecessary API calls when using example buttons
Co-authored-by: dayuan.jiang <jiangdy@amazon.co.jp>
- Add validation to loadDiagram in diagram-context, returns error or null
- display_diagram and edit_diagram tools now check validation result
- Return error to AI agent with state: output-error so it can retry
- Skip validation for trusted sources (localStorage, history, internal templates)
- Add debug logging for tool call inputs to diagnose Bedrock API issues
* Fix: remove hardcoded temperature parameter to support reasoning models
* feat: make temperature configurable via AI_TEMPERATURE env var
- Instead of removing temperature entirely, make it optional via env var
- Set AI_TEMPERATURE=0 for deterministic output (recommended for diagrams)
- Leave unset for models that don't support temperature (e.g., GPT-5.1 reasoning)
* docs: add AI_TEMPERATURE env var documentation
- Update env.example with AI_TEMPERATURE option
- Update README.md configuration section
- Add Temperature Setting section in ai-providers.md
* docs: add TEMPERATURE env var documentation
- Update env.example with TEMPERATURE option
- Update README.md, README_CN.md, README_JA.md configuration sections
- Add Temperature Setting section in ai-providers.md
- Update route.ts to use TEMPERATURE env var
---------
Co-authored-by: dayuan.jiang <jiangdy@amazon.co.jp>
- Add fixToolCallInputs() to fix Bedrock API requirement (JSON object, not string)
- Add experimental_repairToolCall for malformed JSON from model
- Add stepCountIs(5) limit to prevent infinite loops
- Update edit_diagram tool description with JSON escaping warning
Co-authored-by: dayuan.jiang <jiangdy@amazon.co.jp>
- 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
- Add App Context section describing the left/right panel layout
- Add App Features section with icon locations (history, theme, upload, export, clear)
- Dynamically inject model name into system prompt via {{MODEL_NAME}} placeholder
- Expand edit_diagram tool description with usage guidelines
- Remove 15s streaming timeout detection (too slow, added complexity)
- Remove status indicator (issue resolved by switching model)
- Remove streamingError state and related refs
- Simplify onFinish callback (remove 503 detection logging)
- Remove errorHandler function (use default AI SDK errors)
The real fix was switching from global.* to us.* Bedrock model.
This removes ~134 lines of unnecessary complexity.
Bedrock streaming responses don't auto-report token usage to OpenTelemetry.
This fix manually sets span attributes (ai.usage.promptTokens, gen_ai.usage.input_tokens)
from the AI SDK onFinish callback to ensure Langfuse captures token counts.
- Extract system prompts to dedicated lib/system-prompts.ts module
- Add extended system prompt (~4000 tokens) for models with higher cache minimums (Opus 4.5, Haiku 4.5)
- Clean up debug logs while preserving informational and cache-related logs
- Improve code formatting and organization in chat route
* feat: add trace-level input/output to Langfuse observability
- Add @langfuse/client and @langfuse/tracing dependencies
- Wrap POST handler with observe() for proper tracing
- Use updateActiveTrace() to set trace input, output, sessionId, userId
- Filter Next.js HTTP spans in shouldExportSpan so AI SDK spans become root traces
- Enable recordInputs/recordOutputs in experimental_telemetry
* refactor: extract Langfuse logic to separate lib/langfuse.ts module
When models like DeepSeek (deepseek-chat, deepseek-reasoner) receive image
inputs, they return a cryptic error about 'unknown variant image_url'.
This change detects such errors and shows a clear message asking users
to remove the image or switch to a vision-capable model.
Fixes#42
- Add essential draw.io XML structure rules to system prompt
- Include critical rules about mxCell nesting (all must be direct children of root)
- Add shape/vertex and connector/edge examples with proper structure
- Improve tool description for display_diagram with validation rules
- Update xml_guide.md with better swimlane examples showing flat structure
- Add client-side XML validation to catch nested mxCell errors early
Helps address issues #40 (local Ollama models not working) and #39 (mxCell nesting errors)
- Add lib/cached-responses.ts with pre-generated XML for 4 example prompts
- Modify chat API route to check cache before calling AI
- Cache returns instant response (~0.26s) vs AI generation (~20-25s)
- Add "(cached for instant response)" text to example panel
- Cache only activates for first message with empty diagram
* feat: add Bedrock prompt caching for system and conversation messages
- Add cache point to system message (2558+ tokens cached)
- Add cache point to last assistant message in conversation history
- This caches the entire conversation prefix for subsequent requests
- Reduces latency and costs for multi-turn conversations
* refactor: remove duplicated system prompt
* fix: filter out messages with empty content arrays for Bedrock API
The convertToModelMessages function from AI SDK can produce messages with
empty content arrays when assistant messages have only tool call parts or
when tool results aren't properly converted. Bedrock API rejects these with
400 errors. This fix filters out invalid messages before sending to the API.
* fix: add diagnostic logging for empty message content
Added logging to capture the original UI message structure when empty content
is detected after conversion. This helps debug the root cause while the
filter provides a safety net for Bedrock API compatibility.
* fix: correct anthropic beta header config for fine-grained tool streaming
- Use bedrock.anthropicBeta for Bedrock provider (not additionalModelRequestFields)
- Use top-level headers for direct Anthropic API
- Update @ai-sdk/amazon-bedrock to 3.0.62
- Add headers support to ModelConfig interface
* fix: update @ai-sdk/amazon-bedrock to 3.0.62 for tool streaming support
- Add Examples section to README with 2-column grid layout
- Include demo images for GCP, AWS, Azure, animated connectors, and cat
- Update example panel buttons with clearer labels
- Add animated connector example button
- Add instruction for animated connectors in chat route