Harden the startup migration path: fail fast and show an error dialog if
schema migration cannot complete. Repair the gate retroactively for
databases that were already migrated before the gate system existed.
Raise the gate after every import path (full import, incremental import,
stream import) and after opening any database that already carries a
current-segment schema. Centralise gate-raising inside DatabaseManager so
call sites cannot accidentally skip it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use the packaged app version (not Electron's dev-mode 0.0.0) across all
compatibility checks. Make DatabaseManager require a RuntimeIdentity so
every gate write carries a verified version and kind.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After incremental import via Electron IPC, the sidebar session list
showed stale message counts. Three contributing gaps:
1. The chat:incrementalImport IPC handler did not notify the renderer
to refresh the session list (unlike the API route which calls
notifySessionListChanged). Added win.webContents.send('api:importCompleted')
to trigger the Sidebar's existing onImportCompleted listener.
2. The postImportHook in worker adapters was async (due to dynamic
import()) but the caller did not await it, causing a race condition
where loadSessions() could read stale overview cache before
computeAndSetOverviewCache() finished. Converted to static import
making the hook synchronous, and updated the type to void | Promise<void>
with await at call sites in both incremental-importer and
streaming-importer.
3. The @imported handlers on group-chat and private-chat pages only
refreshed local analysis data without calling sessionStore.loadSessions().
Added the call so the sidebar updates immediately on the client side.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Enable esbuild minification for main/preload (was renderer-only by default),
reducing main process bundle by ~55%. Extract cl100k_base BPE rank table out
of the synchronous startup path via dynamic import — it now lands in its own
chunk and is loaded on first agent run instead of at app startup.
Also fix Windows CI step to use PowerShell syntax for version injection.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
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>
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>
- 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>
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>
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>
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>
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>
Restructure import components into dedicated import/ directory with new
ImportTabSelector, ApiImportCard, and AutoSyncCard components. Add demo
import, entry animation, and tutorial links to home page. Update i18n
translations for all locales. Add chatApi init guard in registry and
defaultPath to DataDirInfo preload interface.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace @mariozechner/pi-ai and pi-agent-core with @earendil-works scope
- Adapt to AgentTool.execute() params type change (Record → unknown)
- Migrate Agent constructor to use initialState for systemPrompt/tools/messages
- Update onPayload callback signature to include model parameter
- Filter finalMessages with isPiMessage() for new AgentMessage union type
- Use state.errorMessage instead of deprecated state.error
Co-authored-by: Cursor <cursoragent@cursor.com>
The unified directory migration (needsUnifiedDirMigration) would
re-trigger after a user changed their data directory, overwriting
config.toml back to the old Electron path.
Root cause: no persistent flag tracking whether the migration had
already completed. If old databases remained (cleanup failure or
timing), it would re-detect and re-run.
Fix:
- Add `electron_migration_done` flag to config.toml [data] section
- Set flag after migrateToUnifiedDirs succeeds and in setCustomDataDir
- Check flag at start of needsUnifiedDirMigration to skip if done
- Add "migrate to default" button when data is at non-default path
- Fix NLP directory path: move from userDataDir to systemDir (~/.chatlab/nlp)
Co-authored-by: Cursor <cursoragent@cursor.com>
After pull-sync imports new messages, generate session index incrementally
instead of full regeneration. This preserves existing sessions and their
summaries, only processing newly imported (unindexed) messages.
Adds generateIncremental method across the full stack:
- core: already had generateIncrementalSessionIndex
- node-runtime: expose generateIncrementalIndex
- CLI: add POST /_web/sessions/:id/generate-incremental-index route
- Electron: add session:generateIncremental IPC handler
- Frontend: add generateIncremental to SessionIndexAdapter interface
- Show confirmation dialog with two choices: keep data or delete imported chats
- Backend supports deleteData param across CLI routes and Electron IPC
- DataSourceManager.removeSession now returns the removed session info
- Add i18n strings for the delete confirmation dialog (zh-CN/en-US/ja-JP/zh-TW)
- Add multi-retry (3 attempts, 2s/3s/5s delays) for cold-start empty responses
- Remove unused offset/end parameters from fetch URL construction
- Fix Accept header to application/json only (avoids content negotiation issues)
- Add PullProgress type and progress tracking in PullEngine
- Export progress via getProgress() for frontend polling