Send-side machinery for mobile push notifications (LOBE-8771), stacked
on top of the schema PR (#15186).
### tRPC
- `pushToken.register` / `pushToken.unregister` exposed on both
`MobileRouter` and `LambdaRouter`.
### `PushChannel`
- Structurally compatible with cloud's `NotificationChannel` so cloud
can register it without casts.
- Fans a single notification out to all of a user's tokens, chunks via
`expo-server-sdk`, respects the 600 msg/sec project limit with 100ms
throttle between chunks.
- Embeds `(ticketId, expoToken)` pairs in `providerMessageId` for
receipt reconciliation.
- Returns `no_tokens` / `invalid_tokens` / `rate_limited` /
`all_send_failed` so callers can distinguish.
### `processPushReceipts`
- Pure helper to be called by cloud's Vercel cron (companion PR).
- Polls Expo receipts in parallel (`Promise.all` across chunks),
updates `notification_deliveries` in bulk, prunes `push_tokens` rows
flagged `DeviceNotRegistered`.
- Configurable lookback window + min-age guard (default: 24h / 15min).
### Dev tooling
- `/api/dev/test-push` (404s in production) lets you fire a real push
directly to a user's registered tokens, bypassing `NotificationService`.
Useful for end-to-end verification before cloud submodule sync.
### Types
- `NotificationSettings` gains an optional `push` channel.
Tests: 21 added (router 7, PushChannel 7, processPushReceipts 7).
Linear: https://linear.app/lobehub/issue/LOBE-8771
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔥 chore(agent-config): drop dead enableAutoCreateTopic feature
Drop enableAutoCreateTopic + autoCreateTopicThreshold end-to-end. No
business code consumed these fields anymore — only types, defaults,
locale copy, UI form items, agent-builder LLM prompts, and test
fixtures kept the dead config alive.
Sweep:
- types & zod schema (LobeAgentChatConfig, AgentChatConfigSchema, openapi)
- DEFAULT_AGENT_CHAT_CONFIG constant
- locale keys in default + 18 translations
- agent-builder system prompts & tool manifests
- AgentChat form items (auto-topic switch + threshold slider)
- test fixtures & integration tests (replaced sample boolean key in
parser tests with enableHistoryCount)
- docs/self-hosting env-var examples
- settings.test snapshot
dataImporter JSON fixtures keep the legacy keys on purpose — they
simulate historical user exports and the zod schema strips unknowns.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(chat-input): move inputTemplate + autoScroll into Params popover
Surface the User Input Preprocessing template (inputTemplate) and
Auto-scroll During AI Response toggle (enableAutoScrollOnStreaming) in
the chat-input Params popover, alongside compression / history /
max_tokens. Drop the matching form items from AgentChat — the popover
is now the single entry point for these two agent-level preferences.
ControlRow's action prop becomes optional so inputTemplate can render
as a label + TextArea without a Switch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔥 refactor(agent-settings): drop AgentChat tab in favor of Params popover
Remove the now-redundant Chat Preferences tab from agent settings:
- delete src/features/AgentSetting/AgentChat/
- drop ChatSettingsTabs.Chat enum and its three registrations
(useCategory, AgentSettingsContent, profile Content)
- drop agentTab.chat locale key in default + 18 translations
- drop MessagesSquare / MessagesSquareIcon imports that became unused
History/compression/auto-scroll/inputTemplate already live in the
chat-input Params popover, so this tab carried no unique
functionality.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(chat-input): surface enableStreaming + reasoning_effort + disabledParams in Params popover
Bring the Model tab's controls into the chat-input Params popover so the
popover can become the single entry point for agent-level params.
- enableStreaming Switch at the top of Advanced (treats undefined as on,
matching `chatConfig.enableStreaming !== false` in chat service)
- reasoning_effort row after max_tokens (Select tied to
chatConfig.enableReasoningEffort / params.reasoning_effort, matching
the agentConfigResolver gating)
- per-model disabledParams filter on the 4 sampling sliders (e.g. Claude
Opus 4.7 hides temperature/top_p), via aiModelSelectors.modelDisabledParams
- max_tokens defaults to 4096 on toggle-on (parity with AgentModal),
matching the AgentModal UX
- drop the !enableAgentMode gate on Advanced so agent-mode users still
reach the model params once the Model tab is gone
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔥 refactor(agent-settings): drop AgentModal tab in favor of Params popover
Now that the chat-input Params popover surfaces enableStreaming,
reasoning_effort, the 4 sampling params (model-aware via
disabledParams), and max_tokens, the Model Settings tab carries no
unique behavior. Remove it:
- delete src/features/AgentSetting/AgentModal/ (index + ModelSelect)
- drop ChatSettingsTabs.Modal enum and its three registrations
(useCategory, AgentSettingsContent, profile Content)
- drop agentTab.modal locale key in default + 18 translations
- drop BrainCog / BrainIcon imports that became unused
- simplify the profile Content inbox-default fallback to Opening
(Content menu no longer carried Modal at all)
settingModel.* locale keys are kept — Controls still reads them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🐛 fix(chat-input): keep !enableAgentMode gate on Advanced sampling params
Walk back the gate removal from the prior commit. Agent mode is meant
to manage temperature / top_p / penalties / reasoning_effort itself;
exposing user overrides there contradicts the design.
- Move enableStreaming out of Advanced into the common section so it
stays visible in both modes (streaming is a UI behavior, not a
sampling param).
- Re-wrap the SectionHeader + sampling sliders + max_tokens +
reasoning_effort with `{!enableAgentMode && (...)}`, restoring the
prior visibility rule.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(conversation): persist per-topic chat scroll position to localStorage
Restores scroll position when switching back to a topic, keyed by
messageMapKey(context). Falls back to scroll-to-bottom for new topics or
when the user was already at the bottom. Storage is capped at 500 entries
with 30-day expiry and silent fallback on quota errors.
Fixes LOBE-8251
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔨 chore(conversation): rename scroll snapshot storage prefix to LOBEHUB
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔨 chore(conversation): use LOBEHUB_SCROLL as scroll snapshot key prefix
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🐛 fix(conversation): preserve scroll across draft-to-topic key transition
When a draft conversation (`*_new` key) gets promoted to a real topic via
onTopicCreated, the contextKey changes mid-stream for the same logical
conversation. Treating it as a topic switch loaded a missing snapshot and
fell back to scrollToIndex(end), yanking users away from content they
were reading.
Now we detect the draft-promotion shape, migrate the snapshot to the new
key, and skip the restore pass while data is already on screen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🔥 chore(settings): remove queryRewrite system agent
Removes the unused knowledge-base query rewrite system agent: settings UI in agent/service-model pages, type definition, default config, store selector, server env parser, locale strings across 18 languages, env-variable docs, and the now-orphan chainRewriteQuery prompt chain.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ✨ feat(desktop): embed CLI in app and PATH install
Made-with: Cursor
* ✨ feat(desktop): add CLI command execution feature and UI integration
- Implemented `runCliCommand` method in `ElectronSystemService` to execute CLI commands.
- Added `CliTestSection` component for testing CLI commands within the app.
- Updated `SystemCtr` to include CLI command execution functionality.
- Enhanced `generateCliWrapper` to create short aliases for CLI commands.
- Integrated CLI testing UI in the system tools settings page.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: enhance working directory handling for desktop
- Updated working directory logic to prioritize topic-level settings over agent-level.
- Introduced local storage management for agent working directories.
- Modified tests to reflect changes in working directory behavior.
- Added checks to ensure working directory retrieval is only performed on desktop environments.
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(desktop): implement CLI command routing and cleanup
- Introduced `CliCtr` for executing CLI commands, enhancing the desktop application with CLI capabilities.
- Updated `ShellCommandCtr` to route specific commands to `CliCtr`, improving command handling.
- Removed legacy CLI path installation methods from `SystemCtr` and related services.
- Cleaned up localization files by removing obsolete entries related to CLI path installation.
Signed-off-by: Innei <tukon479@gmail.com>
* 🚸 settings(system-tools): show CLI embedded test only in dev mode
Made-with: Cursor
---------
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat(settings): improve tool detector display layout
- Move version to left side with Name, display as Tag
- Right side: two lines (Available status + path), right-aligned
- Unavailable: single line centered
- Add runtime environment detectors (Node, Python, npm)
- Add i18n for system tools settings
Made-with: Cursor
* 🔧 fix(toolDetectors): ensure successful version check for Python runtime
- Update pythonDetector to enforce successful invocation of `--version` for confirming usable runtime.
- Removed redundant version handling logic to streamline the detection process.
Signed-off-by: Innei <tukon479@gmail.com>
---------
Signed-off-by: Innei <tukon479@gmail.com>
* ✨ feat: add GPT-5.4 model support and fix reasoning payload pruning
- Add GPT-5.4 model card to model-bank
- Update planCardModels to use gpt-5.4
- Add gpt-5.4 to responsesAPIModels
- Fix pruneReasoningPayload to strip logprobs/top_logprobs for reasoning models
- Add logprobs, top_logprobs to ChatStreamPayload type
- Extend reasoning_effort to include none and xhigh
- Add success log for non-fallback requests in RouterRuntime
- Fix log parameter mismatch in RouterRuntime
Fixes LOBE-5735
* 🐛 fix: match gpt-5.4 to gpt5_2ReasoningEffort in openrouter and vercelaigateway
* 🐛 fix: update OpenRouterReasoning effort type to include none and xhigh
* 🐛 fix: use tiered pricing for gpt-5.4 based on 272K token threshold
* 🌐 chore: update i18n translations
* 🐛 fix: update claude-sonnet model version to 4-6 in planCardModels
* ✨ feat: add GPT-5.4 Pro model support
* 🐛 fix: remove dated snapshot for gpt-5.4-pro in responsesAPIModels
* 🐛 fix: add tierBy support for cross-unit tiered pricing threshold
OpenAI charges output at 1.5x when INPUT exceeds 272K tokens.
The tiered strategy previously only checked the unit's own quantity
to select a tier. Added optional tierBy field to TieredPricingUnit
so output/cacheRead tiers can reference input quantity for selection.
* 🐛 fix: use totalInputTokens for tiered pricing tier selection
Tiered pricing tiers should be determined by total prompt size
(totalInputTokens), not each unit's own quantity. This fixes output
and cacheRead being charged at the wrong tier rate when the prompt
exceeds the threshold but the individual unit quantity does not.
* ✨ feat(skillStore): add "Want more skills?" prompt with feedback integration
- Add WantMoreSkills component below CommunityList
- Extend useFeedbackModal to support preset initial values
- Update FeedbackModal to accept and display initial form values
- Add i18n translations for zh-CN and en-US
Closes LOBE-4163
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* 🔧 fix(skillStore): show skill request prompt at list end instead of fixed footer
- Move WantMoreSkills to VirtuosoGrid Footer, shown only when list ends
- Update text to "已经到底了,未找到所需技能?提交申请 →"
- Use Typography.Link for hyperlink style on action text
- Update feedback form template with structured format
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: initial values not set
* chore: remove skill install banner shadow
* chore: use same list height
* chore: update i18n files
* fix: klavis disconnected style
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: add the pending review tag in profile pages
* fix: add lost i18n files
* fix: add the pending review tag in group-agents profiles
* chore: update lost i18n files