Commit Graph
508 Commits
Author SHA1 Message Date
digua 40d7d9e840 fix(ai): harden validation and db handle reuse 2026-06-02 15:41:21 +08:00
digua eea1dad907 fix(electron): offload chart plugin compute to worker 2026-06-02 15:41:21 +08:00
diguaandClaude Opus 4.8 d96299b16e fix(ai): enable fetch-models and validate buttons when editing with stored key
In edit mode the API key is intentionally not returned to the client,
causing both buttons to be disabled. Now the backend resolves the stored
key by configId when the client sends an empty key, and the frontend
passes configId for the reuse case so both buttons work without exposing
the key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 15:41:21 +08:00
digua b66aeb9737 fix(ui): resolve web type-check regressions 2026-06-02 15:41:21 +08:00
digua bf14c68899 refactor(ai): migrate remaining AI IPC to shared HTTP routes 2026-06-02 15:41:21 +08:00
digua 7dcc37e714 refactor(electron): remove session index IPC 2026-06-02 15:41:21 +08:00
digua 9a0e6093f3 fix(ai): harden shared SSE streaming 2026-06-02 15:41:21 +08:00
digua 1af644e4ab refactor(ai): migrate streaming to shared HTTP SSE
Squash Phase 2-2 streaming migration: frontend stream service, LLM SSE route, Agent SSE route, and IPC/preload cleanup.
2026-06-02 15:41:21 +08:00
diguaandCursor 769115240e feat(cache): migrate cache routes to shared HTTP package
Create CacheServiceAdapter + FetchCacheAdapter service layer and move
7 cache routes (info, clear, data-dir, import-log, save-to-downloads,
open-dir, show-in-folder) to @openchatlab/http-routes. Inject platform
callbacks (shell.openPath, showItemInFolder) via HttpRouteContext.
Frontend calls converge from window.cacheApi to useCacheService().
Electron IPC retains only selectDataDir/setDataDir (native dialog).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 15:41:21 +08:00
diguaandCursor fcca22a8dc refactor(ai): remove orphaned AI conversation/message IPC handlers
Migrate conversation/message CRUD and debug queries from IPC to HTTP
by having ElectronAIAdapter extend FetchAIAdapter. Remove 18 dead
handlers (14 CRUD + 3 debug + 1 compressContext) from ipc/ai.ts and
slim down preload AiApi to IPC-only methods (filtering, export, tool
testing, desensitize rules, native shell).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 15:41:21 +08:00
diguaandClaude Sonnet 4.6 1310b04bc0 fix(ui): make data source token required in add modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 15:41:21 +08:00
diguaandCursor ae90db63a5 feat(merge): migrate merge routes from IPC to shared HTTP package
Unify the merge workflow (parse/conflicts/execute/clear/export-for-merge)
across CLI, Electron, and web-serve into a single set of shared routes in
@openchatlab/http-routes.

Key changes:
- Move MergeSessionCache from CLI to node-runtime shared package
- Add dual-mode parse route (multipart upload for web, JSON filePath for Electron)
- Integrate merge routes into Electron internal API server with @fastify/multipart
- Create installMergeShims() with filePath-to-handle mapping for frontend
- Remove Electron merge IPC handlers, merger module, and preload bridges (~790 lines deleted)
- Address CodeX review: CHAT_DB_TABLES in openDatabase, no chatApi patching,
  outputName sanitization, resp.ok checks, @fastify/multipart in desktop deps

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 15:41:21 +08:00
diguaandCursor 3ab162162b feat(ai): migrate AI CRUD routes to shared package and establish frontend service layer
Extract LLM config, assistant, skill, conversation and summary CRUD
routes from CLI-specific ai.ts into @openchatlab/http-routes, enabling
Electron Internal Server to serve AI endpoints via shared routes.

Frontend service layer:
- Create src/services/{llm,assistant,skill}/ with typed adapters
- Migrate all window.llmApi/assistantApi/skillApi calls to service layer
- Clean up Electron preload: remove CRUD bridges, keep only streaming IPC

Shared AI routes (packages/http-routes):
- ai-llm: config CRUD, provider registry, model catalog, custom store
- ai-assistants: CRUD, import/reimport, tool catalog
- ai-skills: CRUD, import/reimport, builtin catalog
- ai-conversations: conversation/message/debug CRUD
- ai-summaries: summary generation with LLM config injection
- Add requireAi fail-fast option to registerSharedRoutes

Backend improvements:
- Extract CustomProviderStore/CustomModelStore to node-runtime
- Fix authProfile persistence (onApiKeyCreated returns profileName)
- Reuse AI manager singletons in Electron (avoid dual instances)
- Prevent plaintext API key leakage in addConfig response
- Add authProfile regression tests

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 15:41:21 +08:00
diguaandCursor 09a7d7c5e2 refactor: remove unused chart plugin and NLP API shims
Both shims were installed only in web-serve mode. Chart modules
already use useDataService() directly and NLP components use
HTTP helpers, so the window.chatApi.pluginQuery/pluginCompute/
getMemberActivity/getAvailableYears and window.nlpApi shims
have zero remaining callers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 15:41:21 +08:00
diguaandCursor f9b5b6b13d refactor: consolidate IPC bridge to native-only
Remove business IPC handlers/preload APIs that are now served by
Internal HTTP Server: preferences, NLP, data queries, message search,
analytics, members, SQL lab. Migrate chart modules from window.*Api
direct calls to useDataService() and NLP components to HTTP.

Make Internal Server a hard dependency, delete ElectronDataAdapter/
MessageAdapter/PreferencesAdapter and IPC fallback path. Retain IPC
only for native capabilities: file import, AI/LLM, session-index
summaries, agent streaming.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 15:41:21 +08:00
digua 96a9d143c4 feat(electron): add internal http server for renderer adapters 2026-06-02 15:41:21 +08:00
diguaandCursor cd3ae8c5ba feat(auth): harden auth security and add remember-me login
Improve auth hook security: restructure URL classification to fix
/_web/* bypass when requireAuth is active, use HMAC-SHA256 for constant-
time token comparison, remove dead webModeEnabled code.

Improve frontend auth flow: extract initializeApp() with watch-based
re-init after login, add getToken callback for real-time store reads,
unify SSE 401 handling via fetchWithAuth, switch default storage to
sessionStorage, add router guard consuming meta.public.

Add "Remember this device" checkbox on login page with dual
localStorage/sessionStorage strategy and safety warning.

Add 23 unit tests for auth hook matrix and http client.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 15:41:21 +08:00
diguaandCursor 8490e2b257 feat(web): add token auth support for frontend with login page
Complete the frontend side of the --require-auth feature:

- Add configureHttpClient() with token injection and 401 handling
- Auto-inject Authorization header in all HTTP helpers and SSE
- Replace 32+ direct fetch('/_web/...') calls with fetchWithAuth
- Add login page for Server mode (token input + validation)
- Add auth store for token persistence (localStorage)
- Add logout button in Settings > About (Server mode only)
- Add i18n translations for login flow (zh-CN/en-US/zh-TW/ja-JP)
- Fix login redirect loop caused by concurrent 401 responses

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 15:41:21 +08:00
diguaandClaude Sonnet 4.6 1b596d664f fix(ui): fix sidebar tooltip placement and API for Nuxt UI v4
Nuxt UI v4 废弃 :popper="{ placement }",改为 :content="{ side }",
旧写法被忽略导致 tooltip 一律显示在下方。

- 展开态按钮(收起、搜索、排序、管理)→ side: bottom
- 折叠态元素(会话项、SidebarButton)→ side: right
- SidebarButton 重构:UTooltip 只包折叠态 div,避免 Reka UI as-child
  在 v-if/v-else 切换时 trigger 引用错乱导致 tooltip 位置错误

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 16:56:08 +08:00
diguaandClaude Sonnet 4.6 69d887c7e2 fix(ui): fix TitleBar dark mode red background and z-index layering
1. 移除 :global(.dark) + 子选择器写法(Vue scoped 编译时选择器泄漏导致
   html.dark { background: #e81123 } 使网页外背景变红),改用 CSS 变量
   + 独立非 scoped <style> 块覆盖深色模式
2. 将 z-index 从 30 提升至 40,使 TitleBar 高于 PageHeader 的
   titlebar-drag-cover (z-30),同时低于 header-actions (z-40, 后挂载),
   三层层叠关系正确:drag-cover < TitleBar ≤ header-actions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 16:56:08 +08:00
digua d1637b41b8 feat(ui): optimize page header and toolbar layout 2026-05-31 16:56:08 +08:00
diguaandCursor 999ce58007 fix(ai): use active slot modelId for thinking level and context window computation
The supportedThinkingLevels, modelContextWindow, and model name display
were reading from config.model (static config value) instead of the
slot's modelId (actual user-selected model). This caused the thinking
selector to show/hide incorrectly when users switched models.

Also fix HTTP utils sending Content-Type: application/json with empty
body when body is null (e.g. setFastModel(null)), which caused Fastify
to return 400.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-31 10:28:29 +08:00
diguaandCursor 9bc0c4279d refactor(ui): simplify model button and optimize session index loading
- StatusBar model button: show model name instead of provider, click opens
  settings directly (scrolls to default model section), remove dropdown
- SessionIndexSection: replace N serial pluginQuery calls with single batch
  API (GET /_web/sessions/index-stats), add IntersectionObserver lazy loading
- Full-stack implementation: CLI route, Electron IPC/Worker, frontend adapters

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-31 10:28:29 +08:00
diguaandCursor 783d61f742 feat(ai): upgrade thinking level control with default/auto options and broader model coverage
- Add 'default' option (no reasoning params sent, model uses native behavior)
- Add 'auto' option for models that natively support it (deepseek_hybrid, kimi, doubao)
- Expand model recognition with regex coverage for 15+ model families
- Add Gemini 2.5+ thinking level support via native Google provider
- Simplify deepseek_hybrid options to ['default', 'off', 'auto'] aligned with Cherry Studio
- Use primary theme color for thinking selector instead of hardcoded blue
- Update docs with thinking control architecture section

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-31 10:28:29 +08:00
diguaandClaude Opus 4.8 a31c672474 feat(ai): add per-model thinking level selector in chat status bar
Adds a lightbulb button next to the model switcher in ChatStatusBar
that lets users choose the thinking intensity for each reasoning model,
with the choice remembered per model slot (configId:modelId).

Key changes:
- packages/core/src/ai/thinking.ts (new): per-model-type thinking level
  table inspired by cherry-studio's MODEL_SUPPORTED_REASONING_EFFORT.
  Covers Qwen/GLM (on/off), DeepSeek V4 (high/max), o-series
  (low/medium/high), gpt-5.x (minimal–xhigh), Kimi/Doubao/Grok and a
  default bucket. Exports getSupportedThinkingLevels, isReasoningModel,
  getThinkingCompat.
- packages/node-runtime/src/ai/llm-builder.ts: inferReasoning now calls
  getThinkingCompat() which sets compat.supportsReasoningEffort and
  compat.thinkingLevelMap so pi-ai can inject the correct request param
  (reasoning_effort for OpenAI/DeepSeek, enable_thinking for Qwen/GLM).
- packages/node-runtime/src/ai/agent/types.ts + core.ts: AgentCoreOptions
  gains an optional thinkingLevel; core.ts:93 uses clampThinkingLevel()
  (from pi-ai) to honour it safely.
- Full transparent pass-through: desktop Agent → IPC handler → preload
  → agentApi.runStream; CLI HTTP route → runServerAgent → runAgentCore.
- src/stores/prompt.ts: thinkingLevels Record<configId:modelId,
  ThinkingLevel> persisted in backendPersist; getThinkingLevel/
  setThinkingLevel helpers.
- src/stores/aiChat.ts: reads current model slot and passes remembered
  level to both sendMessage and editCurrentRoundOnly runStream calls.
- ChatStatusBar.vue: UPopover thinking selector appears only for
  reasoning models, shows only the levels that model supports, highlights
  current choice, hides for non-reasoning models.
- 46 tests passing (26 new in thinking.test.ts + 20 in llm-builder).

Scope: openai-completions path only (Qwen, DeepSeek, OpenAI, xAI, Kimi,
Doubao, SiliconFlow, OpenRouter…). Anthropic/Gemini native thinking is
out of scope for this version.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 10:28:29 +08:00
diguaandClaude Opus 4.8 1716cf392f refactor(ai): replace manual reasoning switches with auto-inference
Remove the "Reasoning Model" and "Disable Thinking Mode" toggles from
the model config dialog. These switches were injecting `enable_thinking`
(a Qwen/DashScope-specific request parameter) into all providers,
causing 400 errors on OpenAI, Anthropic, Gemini, and other official
services.

Replace with automatic inference in buildPiModel:
- reasoning: true when the model's catalog capabilities include
  'reasoning'; falls back to a model-name heuristic for unlisted
  custom/self-hosted models (qwen3, qwq, deepseek-r, o1/o3, etc.).
- compat.thinkingFormat 'qwen': only set when reasoning is true AND
  the model is from the qwen provider or the model id contains
  "qwen"/"qwq". All other providers get compat: undefined and will
  never receive enable_thinking.

This means official reasoning models (o3, deepseek-reasoner, etc.) now
automatically get thinkingLevel:'medium', and self-hosted Qwen3
models continue to work as before — without any manual toggle.

Behavior change: models with 'reasoning' in their catalog capabilities
now default to thinkingLevel:'medium' (previously always 'off' unless
the manual switch was enabled).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 10:28:29 +08:00
diguaandCursor 886642c1a4 feat: split message view into type/time analysis tabs with enriched profile cards
Split the monolithic MessageView into two focused modules:
- TypeAnalysisView: type distribution, text depth analysis, length distributions
- TimeAnalysisView: hourly/weekday/monthly/yearly distributions, member trend, heatmap, calendar

Each tab has a redesigned narrative profile card with rich insights:
- TypeProfileCard: date range, total messages, non-text breakdown pills, 4 metric cards
- TimeProfileCard: active days narrative, time personality labels (multi-dimensional), 4 metric cards

Also: reduce responseLatency font size in RelationshipView for better readability.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-31 10:28:29 +08:00
diguaandCursor 969406915f feat(ai): add confirmation dialog before regenerating all session indexes
Warn users that regeneration will clear all existing AI summaries.
Uses the same UModal pattern as other confirmation dialogs in settings.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 14:19:42 +08:00
diguaandCursor fdb6d8f648 feat(import): update demo data sources to 4 files
Switch from 2 demo files (group + private) to 4 files:
- demo-group.json
- demo-private-A-cuilan.json
- demo-private-B-wukong.json
- demo-private-C-spider.json

Update DemoImportResult.privateSessionId to privateSessionIds array
to support multiple private chat demos.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 14:19:42 +08:00
diguaandCursor b3c2b20a9f fix(ai): make message editing safe against data loss and stale state
- insertMessageAfter: update active_message_id when appending to tail
  so the new reply is on the active path after reload
- editAndOverwriteAll: add hasConfig + abort checks before
  deleteMessagesFrom to prevent data loss when LLM is unconfigured or
  a concurrent request starts
- editCurrentRoundOnly: defer all DB mutations until after stream
  completes; on abort/error only in-memory state is restored
- sync in-memory parentId after relinking so follow-up edits send the
  correct historyLeafMessageId

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 14:19:42 +08:00
digua ce1065e295 docs(api): rename API import to API push 2026-05-30 14:19:42 +08:00
digua e78c8f9368 feat(ai): add fork conversation UI button on AI replies 2026-05-30 14:19:42 +08:00
diguaandCursor 6224ca996e refactor(ai): replace branching with edit-and-regenerate model
Remove the message branching/tree system in favor of a simpler editing model:
- Default: edit a message and only regenerate the current round's AI response
- Optional: overwrite all subsequent messages when editing

Key changes:
- Backend: add updateMessageContent, deleteAndRelinkMessage, insertMessageAfter,
  deleteMessagesFrom, forkConversation; remove createMessageBranch, switchMessageBranch
- Platform layer: add IPC/HTTP handlers for new methods across Electron and CLI
- Frontend store: refactor editMessageAndRegenerate with two modes
- UI: replace branch navigation with "overwrite subsequent" checkbox,
  auto-resizing edit textarea
- Fix insertMessageAfter missing debug_context from pendingDebugContextMap
- Update tests to cover new editing methods

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 14:19:42 +08:00
CEQ151 d3c62c4f9d feat(ai): support editable message branches 2026-05-30 14:19:42 +08:00
diguaandClaude Sonnet 4.6 6cdc040ce8 feat(cli): replace serve/web commands with unified start command
- Add `chatlab start` with --headless (API-only) and --no-open flags
- Remove redundant `serve` and `web` commands
- Update fetch adapter comments to reference chatlab start
- Add chatlab start usage examples to quick-start docs (cn/en/tw)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 14:19:42 +08:00
digua 45dfa5026f fix(session-index): honor selected session IDs in CLI batch summary generation 2026-05-27 23:47:27 +08:00
digua 46204db9b8 fix(ai): revalidate credentials when base URL changes in openai-compat mode 2026-05-27 23:47:27 +08:00
digua 61380f53cc style(ui): optimize chat record list density and message bubble style 2026-05-27 23:47:27 +08:00
diguaandCursor 88ab0ae172 fix(ai): correct apiKeySet detection and prevent stale key reuse
- Fix apiKeySet reporting false positives for local no-key configs by
  resolving the actual key via resolveApiKey and excluding placeholders
- Prevent editing a config from reusing an incompatible API key when
  provider or connection mode has changed
- Pass summary strategy to single-session generation for consistency

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:47:27 +08:00
digua a9b8599417 refactor(i18n): move session index keys from storage to ai namespace 2026-05-27 23:47:27 +08:00
diguaandCursor 6faeee3042 fix(ui): make batch summary stop button respond immediately
Previously clicking stop would only take effect after the current LLM
request finished. Now the UI state updates instantly while the in-flight
request completes silently in the background.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:47:27 +08:00
diguaandCursor 6727ff609c feat(ai): add summary strategy with brief and standard detail levels
Support two summary strategies (brief/standard) for AI-generated session
summaries. Users can choose their preferred detail level in Settings > AI >
Session Index. Standard (default) produces richer summaries covering people,
events, and key details.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:47:27 +08:00
diguaandCursor eaff16d555 fix(cli): wire up batch summary generation in CLI Web to fix page freeze
- Implement generateSummary/checkCanGenerateSummary in FetchSessionIndexAdapter
  via existing HTTP endpoints instead of stubs that returned instantly
- Add checkCanGenerate service function in summary-service.ts
- Add POST /_web/sessions/:id/summaries/check-can-generate route

The page froze because stub methods returned synchronously, causing a tight
loop of hundreds of Vue reactive updates without any network delay.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:47:27 +08:00
diguaandCursor 63e101feb4 fix(cli): fix third-party service misidentified as local when editing in CLI Web
- Add apiKeySet field to GET /_web/ai/llm/configs response
- Allow saving in edit mode without re-entering API key when key already set
- Skip API key validation on save when editing with existing key unchanged
- Show edit-mode placeholder hint on API Key input
- Add missing customModels/disableThinking/isReasoningModel to CLI route types

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:47:27 +08:00
digua bc3871c9b1 fix(settings): remove broken web update action 2026-05-26 23:19:47 +08:00
digua 8a54568cd4 style(ui): optimize sidebar density and enhance dark mode contrast for tab selectors 2026-05-26 23:19:47 +08:00
digua 3565cad5a9 feat(sidebar): add logo and update toggle icon to panel-right 2026-05-26 23:19:47 +08:00
digua 44e0517890 fix(home): restore shared quick start buttons 2026-05-26 23:19:47 +08:00
diguaandClaude Sonnet 4.6 7738b47ab7 refactor: migrate documentation links from chatlab.fun to docs.chatlab.fun
Update links pointing to documentation pages (usage guides, format specs,
troubleshooting, API docs) across README, source code, and i18n files to
use docs.chatlab.fun. Main site links (homepage, roadmap, community,
assets) remain unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 23:19:47 +08:00
digua c736fdc93b fix(cli): disable web self update execution 2026-05-26 23:19:47 +08:00