Commit Graph
17 Commits
Author SHA1 Message Date
dayuan.jiang c75f74a5a0 fix: what the third round broke, and the first batch's review
MCP preview after the server lost a session (it expired, or the MCP
process restarted):
- Every server state has an id, made when the state is created. The tab
  notices a new id even when the version numbers happen to match, and
  every push names the state it was based on, so one based on a lost state
  is refused, also when it comes before the tab's first poll (the server
  recovers the saved file first).
- The tab keeps the newest canvas XML, saved or not. When the server knows
  nothing (no file) or exactly what the tab last saved, the canvas wins and
  is saved, so edits made while the server was down are kept. Otherwise
  the server's diagram (an AI write the tab missed, a cleared document
  that was saved) is shown and the tab's copy goes to History.
- Late answers to an old state's push or poll are dropped; a failed push
  says the server is unreachable; Download as .drawio saves the canvas.

Settings and server:
- Saved providers this version does not know stay in storage with their
  keys, and sending no longer trips over them.
- The desktop "Ollama (Local)" preset with a key goes to local Ollama
  again; a server model's Ollama URL variable is read; the admin panel
  writes Ollama Cloud's URL for a key without one.
- Provider error texts show again in the desktop app and for EdgeOne.
- .env: a quoted value followed by a comment ending in a quote is read as
  dotenv reads it; unquoted values are unchanged.
- Desktop app: the next launch opens the port where a chat was last
  saved; a launch elsewhere that saves nothing does not move it, and a
  page with no chats lets the next launch try the other port once.
- The Test button no longer stays busy after another tab changed the key.
- A completed append_diagram is no longer undone by an earlier failed
  edit's preview; a file read once in vain is saved again once it is read
  or gone.

From the first batch's review:
- The admin panel's Test of an entry without a URL now tests the server's
  <P>_BASE_URL, where chat sends the entry's key; chat is unchanged (the
  first fix rerouted working setups).
- The model list ends downloads that are too large, accepts answers
  without a body, and keeps the "redirects are not allowed" explanation.
- A test covers the preview's History rendering.
2026-10-05 17:33:36 +09:00
dayuan.jiang 50c7ad3ec4 fix(server): keep users' keys at their own endpoints, and more fixes from the third review
- Bedrock: a user's AWS keys no longer go to an endpoint the server sets
  in AWS_ENDPOINT_URL_BEDROCK_RUNTIME / AWS_ENDPOINT_URL (read by the
  upgraded SDK), and admin panel keys win over AWS_BEARER_TOKEN_BEDROCK,
  as the Test button checks them. Checked with Bedrock.
- Ollama: a server key without a base URL (admin panel, OLLAMA_API_KEY)
  goes to Ollama Cloud, as env.example says, instead of 127.0.0.1.
- Quota: EdgeOne counts whatever key header comes along, keyless Ollama at
  a private address counts, and their provider texts stay in the log.
- An EdgeOne server model (admin panel, ai-models.json) works: the route
  checked the raw provider header, which holds the name's slug.
- parse-url ends downloads it does not read (too large, PDF, errors).
- Desktop app: the port follows where the chats are (IndexedDB per
  origin) instead of a remembered port, which could hide them for good;
  a same-port restart tells the page to refetch the server models; a
  failed preset switch no longer undoes a newer choice; a presets file
  removed after a failed read can be saved again; .env values quoted from
  start to end keep their inner quotes, as dotenv reads them.
2026-10-05 13:04:51 +09:00
dayuan.jiang 6236124338 feat(settings): fetch the model list from any provider and flag models that cannot draw
The "Fetch models" button asks the provider for its models (OpenAI-style
/models, Anthropic, Google, Ollama, OpenRouter, Vercel Gateway, AIHubMix)
and shows them in a searchable picker. This replaces the route that only
worked for AIHubMix.

A snapshot of models.dev (MIT) says which models support tool calls.
Models without them get a "no tool calls" badge in the picker and a hint
in the model list, since drawing needs tool calls. Refresh the snapshot
with scripts/update-model-catalog.mjs.
2026-10-04 14:02:54 +09:00
dayuan.jiang 99890e9e37 feat(settings): link to each provider's key page and clean up base URLs
- A "Get API key" link next to the API Key field for the 19 providers
  that have a key page (from env.example and the providers' docs). 17
  answered 200 to curl; OpenAI's is behind a Cloudflare challenge and
  DeepSeek's behind a regional block, both checked in Chrome
- Base URLs drop spaces, trailing slashes and a pasted endpoint path
  (/chat/completions, /completions, /messages, /responses), which the
  SDK would otherwise append a second time and get a 404. getAIModel does
  this for the chat and the Test button; the field does it on blur and
  shows the URL requests go to
2026-10-04 13:37:39 +09:00
dayuan.jiang c24aae6de0 refactor(providers): one model factory for chat and the settings Test button
- getAIModel resolves credentials (client key, server env vars, the
  existing SSRF rules) and createModel builds the model by SDK. The
  provider-by-provider switch shrinks from 24 cases to the few that
  differ (lib/ai-providers.ts 1531 -> 1106 lines)
- /api/validate-model calls getAIModel instead of its own 24-case switch
  (503 -> 175 lines), which had drifted from the chat: it built Azure
  with createOpenAI, Kimi and MiMo with createOpenAI instead of
  createDeepSeek, and the official OpenAI endpoint with Chat Completions.
  A passing test now means the chat works
- Plain OpenAI-compatible providers (SiliconFlow, SGLang, ModelScope,
  GLM, Qwen, Qiniu, Novita, Atlas Cloud, EdgeOne, Doubao, MiniMax in
  OpenAI mode, AIHubMix on a custom URL) use @ai-sdk/openai-compatible,
  which reads reasoning_content, so their reasoning shows, and accepts
  SGLang's stream as is (its 95-line stream rewrite is gone).
  includeUsage keeps token usage for quotas. <think> tags in their text
  become reasoning (extractReasoningMiddleware)
- SGLang without a base URL used OpenAI's endpoint; it now defaults to
  http://127.0.0.1:8000/v1 like the Test button did
- Chat requests to a client base URL refuse redirects, as the Test
  button already did (redirectGuardedFetch moves to lib/ssrf-protection)
- The Test button streams like the chat (the ModelScope special case is
  gone), times out after 15 s, does not retry, asks the model to call a
  ping tool and warns when it answers without one, and tests all models
  at once. The time each test took shows on its check mark
- Unknown provider names are rejected with Object.hasOwn, and the error
  texts list providers from PROVIDER_INFO instead of hand-kept lists
2026-10-04 13:31:47 +09:00
nb213andbinyangzhu000-sudo c8463aefa7 Add Atlas Cloud provider support (#896)
* Add Atlas Cloud provider support

* fix: restore files removed by Atlas provider PR

---------

Co-authored-by: binyangzhu000-sudo <[email protected]>
2026-07-30 23:27:18 +09:00
Dayuan Jiang 80baf43827 fix: remove name-based image-input detection (#874) (#877)
supportsImageInput() guessed multimodal capability from the model id
string. The heuristic misfired on newer models (e.g. kimi-k3.6, qwen36),
either wrongly rejecting images for capable models or letting them through.

The AI SDK does not emit a warning when an OpenAI-compatible endpoint
silently drops an image, so the guess was the only signal — but an
unreliable one. Drop the detection entirely and let the real provider
error surface instead (already translated to a friendly message in
chat-panel.tsx). Validation falls back to "valid" on any model error.

- Remove supportsImageInput() and its pre-send check in chat route
- Drop the vision-capability throw in getValidationModel()
- Remove the corresponding unit tests
2026-06-28 00:26:23 +09:00
YOYO-doandLL 0f9699843f feat: add AIHubMix provider (#865)
* feat: add AIHubMix provider

* feat: load AIHubMix models dynamically

* feat: polish AIHubMix model setup

* feat: send AIHubMix app code

* docs: remove redundant AIHubMix recommendation

---------

Co-authored-by: LL <[email protected]>
2026-06-15 13:54:18 +09:00
Octopusandocto-patch a9ffd6a1de feat: upgrade MiniMax default model to M3 (#857)
- Add MiniMax-M3 to the model selection list (set as new default at top)
- Retain MiniMax-M2.7 and MiniMax-M2.7-highspeed
- Remove deprecated MiniMax-M2.5 / M2.5-highspeed
- Update supportsImageInput: M3 supports image input (M2.x stay text-only)
- Update unit tests to reflect new model lineup
- Update example AI_MODEL in CN/EN/JA docs to MiniMax-M3

Co-authored-by: octo-patch <[email protected]>
2026-06-02 19:38:49 +09:00
Octopusandocto-patch c60e3930a3 fix: use createDeepSeek for kimi provider to handle reasoning_content in multi-turn conversations (fixes #824) (#825)
Kimi thinking models (e.g. kimi-k2.6) return reasoning_content in their
responses. The previous createOpenAI-based implementation silently ignored
this field, so reasoning was never captured or replayed in subsequent turns.
Switching to createDeepSeek (which natively understands reasoning_content)
ensures that reasoning context is preserved across conversation turns,
resolving the "cannot interact a second time" error with Kimi k2.6.

This mirrors the existing doubao provider pattern, which already uses
createDeepSeek for kimi-based models routed through Doubao.

Co-authored-by: octo-patch <[email protected]>
2026-05-15 14:02:26 +09:00
Octopusandocto-patch 171174378c fix: allow QvQ (Qwen Visual QA) models to use image input (#808)
QvQ models (e.g. qvq-72b-preview, qvq-max) are visual reasoning models
from the Qwen family that support image input. When accessed via providers
that prefix model names with 'qwen/' (e.g., OpenRouter), these models
contain 'qwen' in their ID but lack the 'vl' or 'vision' indicator.

This caused supportsImageInput() to incorrectly return false for model
IDs like 'qwen/qvq-72b-preview', blocking image uploads for vision-capable
models.

Add 'qvq' as an explicit exception in the Qwen text-model check so that
QvQ models are correctly allowed to receive image input regardless of the
provider prefix.

Co-authored-by: octo-patch <[email protected]>
2026-04-13 20:05:57 +09:00
Octopusandocto-patch 43ddb7a999 fix: allow Qwen3.5 models to use image input (fixes #799) (#800)
Qwen3.5 models deployed via vLLM natively support image input, but the
supportsImageInput() check was incorrectly blocking them. The function
only exempted qwen3.5-plus and qwen3.5-flash variants, missing the base
qwen3.5 model name.

Simplify the exception to cover all qwen3.5 variants with a single
substring check on "qwen3.5", since it is a common prefix of all three.

Co-authored-by: octo-patch <[email protected]>
2026-04-10 10:23:39 +09:00
sbillyanddayuan.jiang 524b77a948 feat: add glm vision model check (#741)
* Implement GLM model identification logic

Add checks for GLM text and visual model naming conventions.

* fix: simplify GLM vision detection and add tests

- Remove redundant includes("v-") check that could cause false positives
  on model names containing "dev-", "csv-", etc.
- Remove unnecessary includes("v") pre-check
- Update comments with real GLM model names
- Add unit tests for GLM text and vision models

* feat: add vision detection for MiniMax, Moonshot, and fix Qwen

- Add MiniMax text model detection (M2.x series are text-only)
- Add Moonshot v1 text model detection (moonshot-v1-* are text-only)
- Add qwen3.5-flash to Qwen vision model exceptions
- Add unit tests for all new model checks

---------

Co-authored-by: dayuan.jiang <[email protected]>
2026-03-21 01:22:44 +09:00
Marvelous Ikponmwosaanddayuan.jiang a5d1554c3f Add Ollama Cloud support with Base URL and API Key configuration (#692)
* Add Ollama Cloud support with Base URL and API Key configuration

* implemented feedback

* fix: use OLLAMA_BASE_URL env fallback in validate-model endpoint

* Remove dedicated Ollama configuration block

* security(ollama): prevent API key leak to client-controlled URLs

* added test

* fix: security hardening and Ollama Cloud default URL

- Add server OLLAMA_API_KEY fallback to validate-model endpoint with
  SSRF guard mirroring ai-providers.ts
- Tighten top-level SSRF exemption: only exempt Ollama when no server
  OLLAMA_API_KEY is configured
- Update Electron config to support OLLAMA_API_KEY env var
- Change default Ollama URL from localhost:11434 to ollama.com/api
  (Ollama Cloud) for web UI users
- Add tests for server env combo, API-key-only, and SSRF guard scenarios

---------

Co-authored-by: dayuan.jiang <[email protected]>
2026-02-26 21:55:21 +09:00
Dayuan Jiang 4624ad40a1 fix: enable image support for Kimi K2.5 model (#670)
* fix: enable image support for Kimi K2.5 model

Kimi K2.5 supports image input but was incorrectly blocked by the
supportsImageInput check that excluded all Kimi models without
"vision" in the name. Updated the condition to only exclude the
older K2 model while allowing K2.5.

* fix: improve Kimi K2.5 image support logic and add tests

- Only block kimi-k2 specifically, not all Kimi models
- Add unit test for kimi-k2.5 image support
2026-02-02 00:14:27 +09:00
dayuan.jiang 9677737745 test: add unit tests for baseURL isolation logic
Add comprehensive tests for the resolveBaseURL utility function:
- Tests for user-provided API key scenarios
- Tests for server credential scenarios
- Edge case tests for empty strings and undefined values

This addresses the Copilot review suggestion to add test coverage
for the critical security fix.
2026-01-13 22:14:45 +09:00
Dayuan Jiangandgithub-actions[bot] c7a85d398f 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