Commit Graph
1042 Commits
Author SHA1 Message Date
digua 5bb01966fa release: v0.27.1 v0.27.1 2026-06-23 14:39:53 +08:00
diguaandClaude Sonnet 4.6 35b5e720d4 fix(test): fix type errors in worker-runtime and core-data-provider tests
Cast FakeSemanticIndexRuntime via unknown to satisfy the full
SemanticIndexRuntime interface in the factory return type.

Enable allowImportingTsExtensions in tsconfig.web.json so test files
importing .mts helpers pass vue-tsc type checking.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 00:21:18 +08:00
diguaandClaude Sonnet 4.6 f8079d9031 fix(sync): fold initial empty-page cursor before entering retry loop
When the first small response is empty with hasMore=false and carries
sync.nextSince, the file was deleted before that cursor value was saved.
If retry pages also omit nextSince, nextPullSince stays at the old
lastPullAt and the next poll re-fetches the same completed tail window.

Fold sync0.nextSince into nextPullSince immediately after cleanupTempFile,
before the retry loop, matching the existing pattern for retry pages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 14:18:32 +08:00
diguaandClaude Sonnet 4.6 f69f419192 fix(semantic-index): make insertOne idempotent to survive mid-batch crash
With API batched embeddings, insertChunks() and stateStore.updateProgress()
write to two separate SQLite databases, so they cannot be atomic. If the
worker is terminated between the two writes, the next resume attempts to
re-insert the same chunk_ids and hits the UNIQUE constraint, leaving the
session stuck in 'failed' state.

Use INSERT OR IGNORE on chunk_vector_index and skip the vec-table insert
when changes === 0. Duplicate inserts during resume are now silently
discarded instead of throwing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 14:18:32 +08:00
digua dc1c236cc0 fix: address semantic worker and pull review bugs 2026-06-23 14:18:32 +08:00
digua 434334b203 feat(semantic-index): run local embeddings in lazy worker 2026-06-23 14:18:32 +08:00
digua f14f139ec6 feat(semantic-index): batch API embedding warmup 2026-06-23 14:18:32 +08:00
digua 35c260ac33 fix(sync): repair pull pagination cursor(#237) 2026-06-23 14:18:32 +08:00
diguaandClaude Sonnet 4.6 7df673f62f test: add openTestSqliteDatabase helper to fix native binding mismatch
Centralise the better-sqlite3 native-binding selection for tests in
tests/helpers/sqlite.mts so test files consistently use the CLI-side
binding (apps/cli/native/better_sqlite3.node) rather than the default
one, which may be compiled for a different Node.js ABI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 14:18:32 +08:00
diguaandClaude Sonnet 4.6 39393cf38d refactor: remove dead code and simplify over-engineered abstractions
- Delete NotificationBus interface (no implementations, no callers)
- Delete useAsyncData/useMultipleAsyncData composables (zero import sites)
- Inline CHART_CAPABILITY_SKILL_ID into tool-catalog.ts (was a single-constant file)
- Inline AsyncSqlExecutor into message-query-functions.ts (was a single-interface file)
- Rename tools TimeFilter → ToolTimeRange to eliminate name collision with shared-types
- Shrink useToast wrapper: two interfaces → one type, 40 lines → 17 lines
- Simplify deepMerge: remove recursion, config is at most 1 level deep

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 14:18:32 +08:00
digua 835985fbf6 fix(ai): enable exporting visible AI conversations (#231) 2026-06-23 14:18:32 +08:00
digua 307b0380bd release: v0.27.0 v0.27.0 2026-06-22 13:56:43 +08:00
digua 66c8eeeef4 fix(desktop): allow prerelease runtime compatibility checks 2026-06-21 23:34:22 +08:00
diguaandCursor 2bfae1db93 fix(ai): complete desktop semantic index parity and local embedding packaging
Bring the Electron desktop client to parity with CLI web for semantic
index, and package the local embedding runtime correctly.

- Inject semanticIndexService into the desktop AI tool debug executor so
  manual tool runs reach semantic search tools, matching the Agent stream.
  Extract a platform-agnostic tool-executor-core with unit tests.
- Persist the API key by reference in the degraded semantic-index config
  route (vector service unavailable) so API mode keys are not dropped;
  make auth-profile read/write injectable and add route + unit regression
  tests that never touch the real ~/.chatlab.
- Package desktop local embedding deps: declare @huggingface/transformers,
  asarUnpack onnxruntime-node / @img native libs, and trim onnxruntime-node
  binaries to the build target platform/arch to avoid shipping ~175M of
  unrelated Linux/Windows binaries.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 23:09:31 +08:00
digua 114049876f fix(ai): stub GET/POST status routes when semantic index service is unavailable 2026-06-21 22:18:46 +08:00
digua 386c0bd315 fix(ai): support config read/write when semantic index vector service is unavailable
When sqlite-vec fails to load, use SemanticIndexConfigStore directly to
back the GET/PUT /_web/ai/semantic-index/config routes so users can still
configure the vector model from settings. Session management routes (enable,
build, search, etc.) remain unavailable since they require the vector store.

Export SemanticIndexConfigStore, SEMANTIC_INDEX_CONFIG_FILE, and
isSemanticIndexConfigured from node-runtime and semantic-index packages.
2026-06-21 21:52:14 +08:00
digua 8f01a8d3b9 fix(ai): register stub semantic index routes when service is unavailable
When sqlite-vec fails to load (e.g. native binding not found), the service
is null and routes were silently skipped, causing 404 errors in the
settings UI. Register read-only stubs for /config and /enabled so the
settings tab can open without errors when the service is unavailable.

Also export defaultSemanticIndexConfig from the node-runtime package root.
2026-06-21 21:24:37 +08:00
diguaandClaude Sonnet 4.6 0c2b50277f fix(electron): unpack sqlite-vec native extension for packaged builds
sqlite-vec loads its native .dylib/.dll/.so via require.resolve(), which
in a packaged Electron app resolves to a path inside app.asar where native
extensions cannot be loaded. Adds sqlite-vec* to asarUnpack so the extension
lands in app.asar.unpacked and require.resolve() returns the correct path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 16:18:39 +08:00
digua c9288c8069 fix(ai): detect message count changes in completed semantic indexes
When buildAllPending finds a completed session whose live message count
has shrunk (e.g. after member deletion), enqueue rebuild instead of
skipping it, to remove stale vectors for deleted messages.

Expose hasNewMessages in listEnabledStatuses so the Settings UI pendingCount
correctly reflects sessions with appended messages, unblocking the
"Build Pending" button that was otherwise disabled for stale-completed sessions.
2026-06-21 16:18:39 +08:00
digua 0897fe7b62 fix(ai): avoid persisting full tool display results
Store only the tool result payload needed for re-rendering, not the full
pre-processed display content, to prevent unbounded growth of the chat
state serialized to disk.
2026-06-21 16:18:39 +08:00
digua 0d20039741 fix(ai): keyless Ollama embedding support
Allow API-mode semantic index configs without an API key when the base
URL does not require one (e.g. local Ollama); update settings UI to
reflect the keyless-allowed state and enable the session modal when a
keyless config is fully configured.
2026-06-21 16:18:39 +08:00
digua abd05981c6 fix(ai): semantic index core reliability and evidence text
Prevent stale semantic index writes by checking write guard before
persisting chunks; make rebuild detection explicit on app restart via
reactivate() path; preserve full evidence snippet text without truncation;
add regression test for same-second chunk tie-breaking in mapMessageToChunk.
2026-06-21 16:18:39 +08:00
diguaandClaude Sonnet 4.6 88dea48ec6 fix(cli): forward session context and apply preprocessing in tool adapter
agent-stream-runner: pass timeFilter and maxMessagesLimit from request
params into the tool context so evidence and retrieval tools respect the
active session time range in CLI Web sessions, matching the desktop runner.

tool-adapter: pass preprocessConfig, anonymizeNames and ownerPlatformId to
applyPreprocessingPipeline in the rawMessages branch so desensitization and
name anonymization apply to search_messages / recent_messages results,
matching the desktop adapter behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 16:18:39 +08:00
diguaandClaude Sonnet 4.6 69ac64791e fix(ai): fix evidence tool classification and semantic search time filter
retrieve-chat-evidence:
- repair semantic cleanup and keyword time filter; pass context timeFilter
  (seconds→ms) when no explicit date params are provided
- classifyGroup: skip Chinese keyword matching for non-Chinese locales and
  update the English LLM instruction to allow judgment on uncertain groups,
  so English-language chats are not permanently stuck at "cannot confirm"
- mergeCandidates: replace ID-range overlap check with timestamp overlap
  so keyword hits are not incorrectly dropped after incremental imports
  backfill older messages with non-monotonic IDs

semantic-search-current-chat:
- forward context.timeFilter (seconds→ms) to searchForTool so the tool
  respects session time range the same way other retrieval tools do

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 16:18:39 +08:00
diguaandClaude Sonnet 4.6 5a9f44fac5 fix(ai): overhaul semantic index session lifecycle and retrieval accuracy
Session management:
- buildAllPending: recheck completed sessions against live message count
  to enqueue rebuild when new messages arrived since last index run
- runner: detect non-append-only backfills and force full re-index instead
  of resuming from a stale cursor that would skip the backfilled messages
- service/session-state-store: add reactivate() and use it when re-enabling
  a stale session so the old model identity is preserved in the state row;
  on restart buildAllPending() can still detect isStale() and enqueue rebuild
- chunker-config: use sessionId (not absolute path) as the stable key for
  db_path_hash so migrating userDataDir does not orphan existing indexes
- cleanupUnused: cross-check state rows against listSessionIds() to detect
  sessions whose DB was deleted and mark them pending cleanup

Retrieval accuracy:
- hasApiKey: guard against missing authProfile to avoid false positives
- FtsSearcher interface: return {id, ts} pairs; fts-searcher fetches ts from
  message table so chunk mapping has the correct millisecond timestamp
- store.mapMessageToChunk: use (start_ts, start_message_id) composite ordering
  and end-boundary check to break same-second ties deterministically
- message-range-reader: use (ts, id) composite bounds on both sides so
  same-second messages at chunk boundaries are not attributed to wrong parents
- evidence.ts: add startTs/endTs to EvidenceHit; locate core evidence
  boundaries by hit message IDs to avoid same-second ambiguity
- hybrid-search: expand ANN candidate pool to 10× when time filter is active
  to reduce chance of missing in-range chunks in long conversations

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 16:18:39 +08:00
digua a98b9b55bf feat(ai): fold assistant process segments 2026-06-21 16:18:39 +08:00
digua 47177b8038 feat(ai): redesign semantic index model selection 2026-06-21 16:18:39 +08:00
digua 8f9433bf62 chore(i18n): prune unused locale keys 2026-06-21 16:18:39 +08:00
digua 2ec99e5880 feat(ai): streamline agent tool results 2026-06-21 16:18:39 +08:00
digua 5d20429af7 fix(tools): support multi-keyword message search 2026-06-21 16:18:39 +08:00
diguaandCursor 25df662579 fix(ai): route enumeration/topic questions to semantic search
For "what X did we discuss / which ones / what did we talk about" style
enumeration and topic-discovery questions, the model was brute-forcing
search_messages across many keyword-guess rounds instead of using vector
search. Strengthen the semantic-search guidance to send these questions to
semantic_search_current_chat and explicitly discourage multi-round keyword
guessing; restrict search_messages to known exact word/quote/sender/time.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor d58168a029 fix(ai): correct evidence snippet time unit and strip per-message times
Evidence messages carry millisecond timestamps but the preprocessing pipeline
renders times assuming seconds (multiplies by 1000), producing absurd years
(e.g. 56150) inside semantic snippets. Convert ms back to seconds before
rendering. Also strip the per-line time prefix from semantic snippets so the
evidence block shows a single group time instead of a time on every message,
and drop the redundant time span in the group header. Adds regression tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor a23bb1b937 feat(ai): simplify evidence source rows
Drop the per-source timestamp line and show a single overall time per group
(falling back to the source min/max when no group range is set). Each source
now renders as a compact sender + snippet line, reducing visual clutter.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor 62d55d12d6 feat(ai): make evidence block collapsible to reduce footprint
The evidence block is now collapsed by default, showing only a compact header
with per-status group counts and the retrieval mode. Expanding reveals query,
criteria, warnings, grouped sources and a total-sources footnote. Tightens
spacing throughout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor 402b78b683 feat(ai): render evidence content block with click-through tracing
Add a structured "evidence" content block produced by retrieve_chat_evidence:
extract the payload from tool results, persist it in AI chat history, and
render grouped, desensitized sources in EvidenceBlock.vue. Sources open the
chat record drawer at the matched message for traceability. Evidence payload
types move to @openchatlab/core so tools, node-runtime and the frontend share
one definition. Includes zh-CN/en-US/ja-JP/zh-TW i18n.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor b248e48787 feat(ai): route evidence questions to retrieve_chat_evidence via planner
Add an "evidence" planner intent and tiered retrieval guidance so
fact/occurrence/count questions are routed to retrieve_chat_evidence
instead of a single low-level search path.

- planner: new evidence intent + prompt strategy suggesting only
  retrieve_chat_evidence for that step
- semantic-search guidance: three-tier tool selection (evidence > semantic > keyword)
- expose retrieve_chat_evidence as an always-on Agent tool (desktop special
  append; CLI via AGENT_TOOL_REGISTRY core), semantic tool stays dynamic
- export evidence tool + payload types from @openchatlab/tools
- TDD: planner evidence-intent test

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor 27a5bbf9bf feat(ai): apply millisecond time-range filter to semantic retrieval
Thread an optional timeFilter through SemanticSearchToolOptions →
searchForTool → search → hybridSearch so evidence retrieval no longer
mixes time ranges between semantic and keyword paths.

- hybridSearch filters dense + FTS-mapped chunks by startTs/endTs overlap
  (millisecond, single-sided supported) and amplifies the candidate pool
  when filtering to avoid under-recall
- retrieve_chat_evidence now passes its parsed ms range to the semantic path
- TDD: hybrid-search overlap unit tests + service wiring test

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor 6886eb3dc6 feat(ai): add retrieve_chat_evidence tool with evidence payload protocol
Introduce a high-level evidence retrieval tool for fact/occurrence/count
questions. It resolves auto mode, runs semantic + keyword paths, de-identifies
keyword snippets via an injected desensitizeMessages callback, applies a
tool-layer millisecond time-range fallback (keyword path can't rely on the CLI
provider's timeFilter), and merges/dedupes candidates into conservative groups.

- Add ChatEvidencePayload / group / source types and EvidenceTimeRangeMs to tools
- Register tool in AGENT_TOOL_REGISTRY only (Agent-only, excluded from MCP)
- Inject desensitizeMessages (preprocessMessages) in desktop + CLI adapters
- TDD: tool + registry unit tests

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor 509f7b4262 fix(database): add missing i18n for v8 migration
Add the missing translations for the v8 database migration across the
desktop locales and cover them with a regression assertion.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor d0f6972202 feat(semantic-index): add index management UI, conversation picker and i18n
Add the frontend semantic-index service layer and the index management UI:
a settings section for vector model selection and index lifecycle with live
build-progress polling, a conversation picker plus current-conversation
entry, a session-scoped modal, and the tool-block summary rendering in the
chat message flow. Include the en/ja/zh-CN/zh-TW translations.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor b9599da1c8 feat(semantic-index): expose semantic search via routes, agent tool and pipeline
Add shared /_web/ai/semantic-index HTTP routes and wire the service into
CLI web and Electron internal API. Introduce the semantic_search_current_chat
agent tool (AGENT-only, not MCP) with desensitized output and a narrowed
service interface, forward the semantic-search context through the CLI and
Desktop tool adapters, and integrate on-demand semantic search into the
agent pipeline with guidance and a max-result-token evidence budget.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor e3f38cfb8b refactor(ai): replace legacy RAG with semantic-index core infrastructure
Remove the deprecated always-on RAG system and introduce the new
semantic-index core: parent/child chunker with version/hash derivation,
embedding providers (local + OpenAI-compatible) and profiles, sqlite-vec
vector store, dense+FTS+RRF hybrid retrieval, evidence assembly, serial
warmup job queue and single-session runner, session business-state store,
and the SemanticIndexService that ties them together. Add an independent
config store and a dedicated vector directory via the path providers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandCursor fede744758 chore(deps): add sqlite-vec and transformers for semantic index P0
为语义索引 Phase 1 的 P0 前置验证引入 sqlite-vec(vec0 向量存储)
和 @huggingface/transformers(本地 ONNX embedding 推理)依赖。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-21 16:18:39 +08:00
diguaandClaude Sonnet 4.6 0ba08bd8de fix(electron): address post-review issues from #229
- capture worker reference in sendToWorkerWithProgress to match
  sendToWorker and avoid stale-closure risk on worker restart
- replace `as any` casts with typed SupportedLocale / BatchSegmentOptions
  assertions in debug-executor
- destructure params.params as toolParams to remove unused testId binding

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 09:43:13 +08:00
LeoandLeo 28fedbd815 fix(ai): recover from analysis tool timeouts (#229)
Co-authored-by: Leo <jxy0811@users.noreply.github.com>
2026-06-16 11:30:02 +08:00
diguaandClaude Sonnet 4.6 2dba862c49 fix(wordcloud): fix UX regressions for word cloud dictionary loading (#228)
Switching to a different session left allWords/topicMiniWords/stats
populated with the previous session's data. With the earlier fix that
skips isLoading when allWords is non-empty, users could see and interact
with stale words until the new request resolved.

Extend the sessionId watcher to also clear all word cloud state so the
loading indicator triggers correctly for cross-session navigation while
still keeping old data visible for same-session filter refinements.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 23:11:06 +08:00
LeoandClaude a89d6f7429 fix(wordcloud): allow word cloud analysis without external dictionary (#221)
Co-authored-by: Claude <noreply@anthropic.com>
2026-06-15 22:52:27 +08:00
diguaandClaude Sonnet 4.6 4d03d6cf54 docs: rewrite quick-start, intro, and index pages
- quick-start: simplify download links, add clb alias tip, improve copy
- intro: expand with features, supported platforms table, and next steps
- index: optimize title and descriptions for GEO/SEO

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 19:57:43 +08:00
diguaandClaude Sonnet 4.6 7abb7bd782 docs: add acknowledgments pages and EN protocol translations
- Add CN/EN acknowledgments pages with Leo Oliveira story
- Add English translations of Push and Pull protocol docs
- Register acknowledgments in sidebar as top-level entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 19:51:08 +08:00
diguaandClaude Sonnet 4.6 0bdc198303 docs: update READMEs and contributing guidelines
- Mark iMessage as supported, remove WeChat from EN README
- Update dev setup to reflect interactive target selector
- Add docs site links to docs/README.md
- Remove single-PR rule, highlight feature discussion requirement

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 19:43:52 +08:00