PullEngine gains an onSessionImported hook (hook errors never fail the
pull), wired in both the CLI server and Electron main to silently fill
session owner from the stored platform profile. The chatlab import CLI
command does the same after a successful import.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Opening an unowned session first tries to auto-apply the platform
owner profile; only when that fails (and the session is not dismissed)
a lightweight searchable prompt pops up with Later / Don't remind /
Save actions. Member management now uses an entry card opening the
same modal, replacing the embedded OwnerSelector dropdown. Imports in
the session store silently retry profile application per session.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shared node-runtime service writes session owner, maintains the
per-platform profile in preferences.json, and batch-applies it to
other unowned same-platform sessions (unique match only, never
overriding an existing owner). Exposed via /_web/sessions/:id/owner/
{apply-profile,select,dismiss-prompt} for both Electron and CLI Web.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add deterministic owner matching in core (exact platformId first, then
normalized-name fallback limited to whatsapp/line/instagram), plus
OwnerProfile preferences fields shared across Electron and CLI Web.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AI was treating last_message_time as "when the group last had activity"
and drawing inferences like "the group has been quiet for two months,
maybe send a message to revive it." In reality, the timestamp only
reflects the end of imported data — the user may simply not have
imported newer records yet.
Add an inline parenthetical to the last_message_time field in all four
locale templates, and append a dedicated usage rule in
dataSnapshotUsageRules (zh-CN, en-US, zh-TW, ja-JP) explicitly
prohibiting inferences about group inactivity based on this value.
Also add the same note to formatDataSnapshotForPlanner's notes section
in data-snapshot.ts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Overview cache had no self-invalidation: once written it would return
stale lastMessageTs forever if the postImportHook failed silently.
Analysis query cache (17 chart/stats queries) was never cleared on
import, so charts showed stale data until the user triggered a manual
invalidate.
Add MAX(message.id) fingerprint to OverviewCache and introduce
getValidatedOverviewCache(), which recomputes automatically when new
messages are inserted. Update resolveOverview() in the Electron worker
to use this instead of bare getCache().
In both postImportHooks (incrementalImport, streamImport) also call
deleteSessionCache against the query cache directory so chart data is
fresh after every import.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Include assistant messages with tool content blocks in getHistoryForAgent
even when text content is empty, so multi-turn tool results are not lost
- Append Date.now() timestamp to export filenames to prevent silent overwrites
- Pass 600s timeout to exportFilterResultToFile worker call to match the
actual upper bound of large-session exports
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extend TokenUsage types across the full data pipeline to include
cacheReadTokens and cacheWriteTokens. The ChatStatusBar tooltip now
shows cache hit information when available. This is a generic
implementation that works with any API provider reporting cache metrics,
not limited to DeepSeek.
Co-authored-by: Cursor <cursoragent@cursor.com>
DeepSeek API requires reasoning_content to be retransmitted on assistant
messages that precede tool results. Add ReplayOptions to history replay
so thinking blocks are included as ThinkingContent when the model uses
DeepSeek-format thinking, preventing 400 errors in multi-turn tool-call
conversations.
Co-authored-by: Cursor <cursoragent@cursor.com>
Message-retrieval tools mirror rawMessages inside data, and the
preprocessing pipeline rendered that array into the tool result text as
"rawMessages: [object Object], [object Object], ..." — roughly 1.7KB of
junk per call (~400-500 wasted tokens) that also polluted the truncated
result text persisted for history replay.
- formatToolResultAsText skips the rawMessages key (raw message objects
are already rendered via the formatted messages list)
- CLI tool adapter strips rawMessages from extraDetails before invoking
the pipeline, matching the existing desktop adapter behavior
Regression tests fail without the fix at both the format layer and the
CLI adapter layer.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Multi-turn agent conversations rebuilt history as plain text, dropping
all tool calls and results. Later turns could not see what the model
had actually retrieved, so it imitated tool-free answers and
hallucinated chat records instead of re-querying (worse after
incremental imports and in long conversations).
- Persist provider-issued toolCallId, truncated result text and isError
on tool content blocks (written by the shared frontend store from
stream chunks; pi-agent-core events already carry these fields)
- Replay persisted tool blocks as real toolCall/toolResult message
pairs in toPiHistoryMessages: stable ids keep requests byte-identical
across turns (prompt cache friendly), unfinished blocks are skipped
so no toolCall is left unanswered, errors map to isError, results are
capped at 4000 chars, runtime-injected underscore params are stripped
- Legacy messages without persisted tool data fall back to the old
plain-text replay; no migration needed
Verified on a real CLI web session: 25+ replayed tool pairs accepted by
the provider across turns with zero API errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
In explicit chart auto mode, the filter at agent/index.ts removed
render_chart whenever the user message lacked chart keywords. This
caused failures when a user manually selected the built-in chart skill
with a message like "analyze message trends" — the skill prompt
instructed the AI to produce charts but the tool was unavailable.
Add an isExplicitChartSkill guard so the filter is skipped when
skillCtx.skillDef.id === CHART_CAPABILITY_SKILL_ID.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace `containLabel: true` with `outerBoundsMode: 'same'` in
EChartLine, EChartBar, EChartHeatmap to suppress the ECharts 6
deprecation warning; `outerBoundsMode: 'same'` is the semantic
equivalent (outer boundary equals the grid rect, labels fit inside)
- In EChartPie, auto-hide the right-side legend when outer labels
(indicator lines + text) are already visible, and center the chart
accordingly to avoid redundant information
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- AISettingsTab: move 对话偏好 above 工具设置 in left nav to match content order
- Rename i18n key skillSettings → chatPreferences across all locales and
components; the section covers general chat preferences, not just skills
- SubTabs: add whitespace-nowrap + shrink-0 to tab buttons and overflow-x-auto
to horizontal container so labels never wrap at narrow desktop widths
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- agent-stream-runner: add fallback allowedBuiltinTools in explicit chart
auto-skill path so unrestricted assistants still load analysis tools when
skill menu advertises skills that require them
- aiChat: guard updatePlanBlockStatus('done') with !hasStreamError in both
SSE and edit-stream handlers so failed plans stay visibly failed instead
of being overwritten by the terminal done event
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add optional `rows` parameter to render_chart so AI can pass pre-fetched
data arrays (e.g. from get_time_stats, member_stats) directly instead of
rewriting SQL from scratch. Update chart capability prompts and all locale
files to guide AI to check high-level tools first before falling back to SQL.
Remove debug console.debug log from agent-core thinkingLevel resolution.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sqlQueryTool (execute_sql) was listed in BUILTIN_TOOL_CATALOG and
available in the CLI AGENT_TOOL_REGISTRY, but was never imported or
registered in the Electron-specific TOOL_REGISTRY. Users who enabled
the tool via the assistant config panel would trigger a missing-tool
error at inference time.
Add sqlQueryTool to the Electron registry following the same
adaptSharedTool pattern used by all other analysis tools. Add a
catalog/registry drift guard test (name + category) covering all
BUILTIN_TOOL_CATALOG entries, enabled via
--experimental-test-module-mocks to mock Electron runtime deps.
Document the general-over-specific assertion rule in AGENTS.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
thinkingLevels was excluded from the mergeDefaults whitelist in
PreferencesManager, so user choices were silently dropped on every
save/load cycle and never written to preferences.json.
Add the field to the Preferences interface, DEFAULTS, and mergeDefaults
so the existing backendPersist → savePreferences pipeline can write and
restore it correctly. Adds regression tests covering the save/load
round-trip, multi-save merge, and legacy-file backward compatibility.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MCP server checks the gate at startup and exits before opening stdio if
the data directory requires a newer runtime. Desktop HTTP API maps
DataDirCompatibilityError (including wrapped causes) to a 409 response
so the renderer can surface a clear upgrade prompt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>