@lobehub/lobehub 2.0.0-next.353 → 2.0.0-next.355
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/add-provider-doc/SKILL.md +90 -0
- package/.agents/skills/add-setting-env/SKILL.md +106 -0
- package/.agents/skills/debug/SKILL.md +66 -0
- package/.agents/skills/desktop/SKILL.md +78 -0
- package/.agents/skills/desktop/references/feature-implementation.md +99 -0
- package/.agents/skills/desktop/references/local-tools.md +133 -0
- package/.agents/skills/desktop/references/menu-config.md +103 -0
- package/.agents/skills/desktop/references/window-management.md +143 -0
- package/.agents/skills/drizzle/SKILL.md +129 -0
- package/.agents/skills/drizzle/references/db-migrations.md +50 -0
- package/.agents/skills/hotkey/SKILL.md +90 -0
- package/{.cursor/rules/i18n.mdc → .agents/skills/i18n/SKILL.md} +14 -23
- package/.agents/skills/linear/SKILL.md +51 -0
- package/.agents/skills/microcopy/SKILL.md +83 -0
- package/.agents/skills/modal/SKILL.md +102 -0
- package/{.cursor/rules/project-structure.mdc → .agents/skills/project-overview/SKILL.md} +65 -37
- package/.agents/skills/react/SKILL.md +73 -0
- package/.agents/skills/react/references/layout-kit.md +100 -0
- package/.agents/skills/recent-data/SKILL.md +108 -0
- package/.agents/skills/testing/SKILL.md +89 -0
- package/.agents/skills/testing/references/agent-runtime-e2e.md +126 -0
- package/.agents/skills/testing/references/db-model-test.md +124 -0
- package/.agents/skills/testing/references/desktop-controller-test.md +124 -0
- package/.agents/skills/testing/references/electron-ipc-test.md +63 -0
- package/.agents/skills/testing/references/zustand-store-action-test.md +150 -0
- package/.agents/skills/typescript/SKILL.md +52 -0
- package/.agents/skills/zustand/SKILL.md +78 -0
- package/.agents/skills/zustand/references/action-patterns.md +125 -0
- package/.agents/skills/zustand/references/slice-organization.md +125 -0
- package/AGENTS.md +42 -55
- package/CHANGELOG.md +60 -0
- package/CLAUDE.md +57 -46
- package/GEMINI.md +47 -39
- package/changelog/v1.json +18 -0
- package/locales/en-US/plugin.json +3 -0
- package/locales/zh-CN/plugin.json +3 -0
- package/package.json +1 -1
- package/packages/builtin-tool-memory/src/client/Render/SearchUserMemory/index.tsx +3 -11
- package/packages/context-engine/src/engine/messages/MessagesEngine.ts +0 -13
- package/packages/context-engine/src/engine/messages/__tests__/MessagesEngine.test.ts +0 -25
- package/packages/database/src/models/__tests__/topics/topic.create.test.ts +3 -3
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/List/Item/index.tsx +1 -0
- package/src/app/[variants]/(main)/agent/features/Conversation/ConversationArea.tsx +4 -0
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/List/Item/index.tsx +1 -0
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentItem/index.tsx +1 -1
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/InboxItem.tsx +19 -29
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/List.tsx +1 -1
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/ModalProvider.tsx +1 -1
- package/src/features/FileViewer/Renderer/PDF/index.tsx +2 -3
- package/src/features/ShareModal/SharePdf/PdfPreview.tsx +1 -2
- package/src/libs/pdfjs/index.tsx +25 -0
- package/src/locales/default/plugin.ts +3 -0
- package/src/server/modules/Mecha/ContextEngineering/__tests__/serverMessagesEngine.test.ts +0 -25
- package/src/services/chat/chat.test.ts +19 -19
- package/src/services/chat/index.ts +8 -3
- package/src/services/chat/mecha/agentConfigResolver.test.ts +72 -55
- package/src/services/chat/mecha/agentConfigResolver.ts +28 -4
- package/src/services/chat/mecha/contextEngineering.test.ts +21 -14
- package/src/services/chat/mecha/contextEngineering.ts +12 -0
- package/src/services/chat/types.ts +7 -1
- package/src/store/chat/agents/createAgentExecutors.ts +15 -4
- package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +1 -0
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +6 -2
- package/src/store/test-coverage.md +5 -5
- package/.cursor/rules/add-provider-doc.mdc +0 -183
- package/.cursor/rules/add-setting-env.mdc +0 -175
- package/.cursor/rules/cursor-rules.mdc +0 -28
- package/.cursor/rules/db-migrations.mdc +0 -46
- package/.cursor/rules/debug-usage.mdc +0 -86
- package/.cursor/rules/desktop-controller-tests.mdc +0 -189
- package/.cursor/rules/desktop-feature-implementation.mdc +0 -155
- package/.cursor/rules/desktop-local-tools-implement.mdc +0 -81
- package/.cursor/rules/desktop-menu-configuration.mdc +0 -209
- package/.cursor/rules/desktop-window-management.mdc +0 -301
- package/.cursor/rules/drizzle-schema-style-guide.mdc +0 -218
- package/.cursor/rules/hotkey.mdc +0 -162
- package/.cursor/rules/linear.mdc +0 -53
- package/.cursor/rules/microcopy-cn.mdc +0 -158
- package/.cursor/rules/microcopy-en.mdc +0 -148
- package/.cursor/rules/modal-imperative.mdc +0 -162
- package/.cursor/rules/packages/react-layout-kit.mdc +0 -122
- package/.cursor/rules/project-introduce.mdc +0 -36
- package/.cursor/rules/react.mdc +0 -169
- package/.cursor/rules/recent-data-usage.mdc +0 -139
- package/.cursor/rules/rules-index.mdc +0 -44
- package/.cursor/rules/testing-guide/agent-runtime-e2e.mdc +0 -285
- package/.cursor/rules/testing-guide/db-model-test.mdc +0 -455
- package/.cursor/rules/testing-guide/electron-ipc-test.mdc +0 -80
- package/.cursor/rules/testing-guide/testing-guide.mdc +0 -534
- package/.cursor/rules/testing-guide/zustand-store-action-test.mdc +0 -574
- package/.cursor/rules/typescript.mdc +0 -55
- package/.cursor/rules/zustand-action-patterns.mdc +0 -328
- package/.cursor/rules/zustand-slice-organization.mdc +0 -308
- package/src/libs/pdfjs/pdf.worker.ts +0 -1
- package/src/libs/pdfjs/worker.ts +0 -12
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/AGENTS.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/SKILL.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/advanced-event-handler-refs.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/advanced-use-latest.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-api-routes.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-defer-await.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-dependencies.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-parallel.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/async-suspense-boundaries.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-barrel-imports.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-conditional.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-defer-third-party.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-dynamic-imports.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/bundle-preload.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-event-listeners.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-localstorage-schema.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-passive-event-listeners.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/client-swr-dedup.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-batch-dom-css.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-cache-function-results.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-cache-property-access.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-cache-storage.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-combine-iterations.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-early-exit.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-hoist-regexp.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-index-maps.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-length-check-first.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-min-max-loop.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-set-map-lookups.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/js-tosorted-immutable.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-activity.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-animate-svg-wrapper.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-conditional-render.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-content-visibility.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-hoist-jsx.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-hydration-no-flicker.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rendering-svg-precision.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-defer-reads.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-dependencies.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-derived-state.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-functional-setstate.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-lazy-state-init.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-memo.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/rerender-transitions.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-after-nonblocking.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-cache-lru.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-cache-react.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-parallel-fetching.md +0 -0
- /package/.agents/{vercel-react-best-practices → skills/vercel-react-best-practices}/rules/server-serialization.md +0 -0
package/GEMINI.md
CHANGED
|
@@ -1,64 +1,72 @@
|
|
|
1
1
|
# GEMINI.md
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Guidelines for using Gemini CLI in this LobeChat repository.
|
|
4
4
|
|
|
5
5
|
## Tech Stack
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
- Next.js 16 + React 19 + TypeScript
|
|
8
|
+
- SPA inside Next.js with `react-router-dom`
|
|
9
|
+
- `@lobehub/ui`, antd for components; antd-style for CSS-in-JS
|
|
10
|
+
- react-i18next for i18n; zustand for state management
|
|
11
|
+
- SWR for data fetching; TRPC for type-safe backend
|
|
12
|
+
- Drizzle ORM with PostgreSQL; Vitest for testing
|
|
13
|
+
|
|
14
|
+
## Project Structure
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
lobe-chat/
|
|
18
|
+
├── apps/desktop/ # Electron desktop app
|
|
19
|
+
├── packages/ # Shared packages (@lobechat/*)
|
|
20
|
+
│ ├── database/ # Database schemas, models, repositories
|
|
21
|
+
│ ├── agent-runtime/ # Agent runtime
|
|
22
|
+
│ └── ...
|
|
23
|
+
├── src/
|
|
24
|
+
│ ├── app/ # Next.js app router
|
|
25
|
+
│ ├── store/ # Zustand stores
|
|
26
|
+
│ ├── services/ # Client services
|
|
27
|
+
│ ├── server/ # Server services and routers
|
|
28
|
+
│ └── ...
|
|
29
|
+
└── e2e/ # E2E tests (Cucumber + Playwright)
|
|
30
|
+
```
|
|
12
31
|
|
|
13
32
|
## Development
|
|
14
33
|
|
|
15
34
|
### Git Workflow
|
|
16
35
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
- PR titles starting with `✨ feat/` or `🐛 fix` will trigger the release workflow upon merge. Only use these prefixes for significant user-facing feature changes or bug fixes
|
|
36
|
+
- Use rebase for `git pull`
|
|
37
|
+
- Commit messages: prefix with gitmoji
|
|
38
|
+
- Branch format: `<type>/<feature-name>`
|
|
39
|
+
- PR titles with `✨ feat/` or `🐛 fix` trigger releases
|
|
22
40
|
|
|
23
41
|
### Package Management
|
|
24
42
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
- Use `bun` to run npm scripts
|
|
29
|
-
- Use `bunx` to run executable npm packages
|
|
30
|
-
|
|
31
|
-
### TypeScript Code Style Guide
|
|
32
|
-
|
|
33
|
-
see @.cursor/rules/typescript.mdc
|
|
43
|
+
- `pnpm` for dependency management
|
|
44
|
+
- `bun` to run npm scripts
|
|
45
|
+
- `bunx` for executable npm packages
|
|
34
46
|
|
|
35
47
|
### Testing
|
|
36
48
|
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
- packages(eg: database): `cd packages/database && bunx vitest run --silent='passed-only' '[file-path-pattern]'`
|
|
41
|
-
|
|
42
|
-
**Important**:
|
|
43
|
-
|
|
44
|
-
- wrap the file path in single quotes to avoid shell expansion
|
|
45
|
-
- Never run `bun run test` etc to run tests, this will run all tests and cost about 10mins
|
|
46
|
-
- If trying to fix the same test twice, but still failed, stop and ask for help.
|
|
49
|
+
```bash
|
|
50
|
+
# Run specific test (NEVER run `bun run test` - takes ~10 minutes)
|
|
51
|
+
bunx vitest run --silent='passed-only' '[file-path]'
|
|
47
52
|
|
|
48
|
-
|
|
53
|
+
# Database package
|
|
54
|
+
cd packages/database && bunx vitest run --silent='passed-only' '[file]'
|
|
55
|
+
```
|
|
49
56
|
|
|
50
|
-
-
|
|
57
|
+
- Tests must pass type check: `bun run type-check`
|
|
58
|
+
- After 2 failed fix attempts, stop and ask for help
|
|
51
59
|
|
|
52
60
|
### i18n
|
|
53
61
|
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
62
|
+
- Add keys to `src/locales/default/namespace.ts`
|
|
63
|
+
- For dev preview: translate `locales/zh-CN/` and `locales/en-US/`
|
|
64
|
+
- Don't run `pnpm i18n` - CI handles it
|
|
57
65
|
|
|
58
|
-
##
|
|
66
|
+
## Quality Checks
|
|
59
67
|
|
|
60
|
-
**MANDATORY**: After completing code changes,
|
|
68
|
+
**MANDATORY**: After completing code changes, run diagnostics on modified files to identify and fix any errors.
|
|
61
69
|
|
|
62
|
-
##
|
|
70
|
+
## Skills (Auto-loaded)
|
|
63
71
|
|
|
64
|
-
|
|
72
|
+
Skills are available in `.agents/skills/` directory. See CLAUDE.md for the full list.
|
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {
|
|
4
|
+
"fixes": [
|
|
5
|
+
"Fix favorite refresh bug and group topic refresh issue."
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
"date": "2026-01-23",
|
|
9
|
+
"version": "2.0.0-next.355"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"children": {
|
|
13
|
+
"improvements": [
|
|
14
|
+
"Migrate AI Rules to Claude Code Skills."
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"date": "2026-01-23",
|
|
18
|
+
"version": "2.0.0-next.354"
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"children": {},
|
|
4
22
|
"date": "2026-01-23",
|
|
@@ -177,6 +177,9 @@
|
|
|
177
177
|
"builtins.lobe-user-memory.apiName.searchUserMemory": "Search memory",
|
|
178
178
|
"builtins.lobe-user-memory.apiName.updateIdentityMemory": "Update identity memory",
|
|
179
179
|
"builtins.lobe-user-memory.inspector.noResults": "No results",
|
|
180
|
+
"builtins.lobe-user-memory.render.contexts": "Contexts",
|
|
181
|
+
"builtins.lobe-user-memory.render.experiences": "Experiences",
|
|
182
|
+
"builtins.lobe-user-memory.render.preferences": "Preferences",
|
|
180
183
|
"builtins.lobe-user-memory.title": "Memory",
|
|
181
184
|
"builtins.lobe-web-browsing.apiName.crawlMultiPages": "Read multiple pages",
|
|
182
185
|
"builtins.lobe-web-browsing.apiName.crawlSinglePage": "Read page content",
|
|
@@ -177,6 +177,9 @@
|
|
|
177
177
|
"builtins.lobe-user-memory.apiName.searchUserMemory": "搜索记忆",
|
|
178
178
|
"builtins.lobe-user-memory.apiName.updateIdentityMemory": "更新身份记忆",
|
|
179
179
|
"builtins.lobe-user-memory.inspector.noResults": "无结果",
|
|
180
|
+
"builtins.lobe-user-memory.render.contexts": "情境",
|
|
181
|
+
"builtins.lobe-user-memory.render.experiences": "经验",
|
|
182
|
+
"builtins.lobe-user-memory.render.preferences": "偏好",
|
|
180
183
|
"builtins.lobe-user-memory.title": "记忆",
|
|
181
184
|
"builtins.lobe-web-browsing.apiName.crawlMultiPages": "读取多个页面内容",
|
|
182
185
|
"builtins.lobe-web-browsing.apiName.crawlSinglePage": "读取页面内容",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/lobehub",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.355",
|
|
4
4
|
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -6,8 +6,6 @@ import { createStaticStyles } from 'antd-style';
|
|
|
6
6
|
import { memo } from 'react';
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
8
8
|
|
|
9
|
-
import { highlightTextStyles } from '@/styles';
|
|
10
|
-
|
|
11
9
|
import type { SearchMemoryParams, SearchUserMemoryState } from '../../../types';
|
|
12
10
|
|
|
13
11
|
const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
@@ -120,9 +118,7 @@ const SearchUserMemoryRender = memo<BuiltinRenderProps<SearchMemoryParams, Searc
|
|
|
120
118
|
paddingInline={12}
|
|
121
119
|
title={
|
|
122
120
|
<Text className={styles.sectionHeader}>
|
|
123
|
-
<span
|
|
124
|
-
{t('builtins.lobe-user-memory.render.contexts' as any)}
|
|
125
|
-
</span>
|
|
121
|
+
<span>{t('builtins.lobe-user-memory.render.contexts')}</span>
|
|
126
122
|
<Text as={'span'} type={'secondary'}>
|
|
127
123
|
{' '}
|
|
128
124
|
({contexts.length})
|
|
@@ -152,9 +148,7 @@ const SearchUserMemoryRender = memo<BuiltinRenderProps<SearchMemoryParams, Searc
|
|
|
152
148
|
paddingInline={12}
|
|
153
149
|
title={
|
|
154
150
|
<Text className={styles.sectionHeader}>
|
|
155
|
-
<span
|
|
156
|
-
{t('builtins.lobe-user-memory.render.experiences' as any)}
|
|
157
|
-
</span>
|
|
151
|
+
<span>{t('builtins.lobe-user-memory.render.experiences')}</span>
|
|
158
152
|
<Text as={'span'} type={'secondary'}>
|
|
159
153
|
{' '}
|
|
160
154
|
({experiences.length})
|
|
@@ -184,9 +178,7 @@ const SearchUserMemoryRender = memo<BuiltinRenderProps<SearchMemoryParams, Searc
|
|
|
184
178
|
paddingInline={12}
|
|
185
179
|
title={
|
|
186
180
|
<Text className={styles.sectionHeader}>
|
|
187
|
-
<span
|
|
188
|
-
{t('builtins.lobe-user-memory.render.preferences' as any)}
|
|
189
|
-
</span>
|
|
181
|
+
<span>{t('builtins.lobe-user-memory.render.preferences')}</span>
|
|
190
182
|
<Text as={'span'} type={'secondary'}>
|
|
191
183
|
{' '}
|
|
192
184
|
({preferences.length})
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
GroupMessageFlattenProcessor,
|
|
10
10
|
GroupOrchestrationFilterProcessor,
|
|
11
11
|
GroupRoleTransformProcessor,
|
|
12
|
-
HistoryTruncateProcessor,
|
|
13
12
|
InputTemplateProcessor,
|
|
14
13
|
MessageCleanupProcessor,
|
|
15
14
|
MessageContentProcessor,
|
|
@@ -113,8 +112,6 @@ export class MessagesEngine {
|
|
|
113
112
|
provider,
|
|
114
113
|
systemRole,
|
|
115
114
|
inputTemplate,
|
|
116
|
-
enableHistoryCount,
|
|
117
|
-
historyCount,
|
|
118
115
|
historySummary,
|
|
119
116
|
formatHistorySummary,
|
|
120
117
|
knowledge,
|
|
@@ -145,16 +142,6 @@ export class MessagesEngine {
|
|
|
145
142
|
const isGTDTodoEnabled = gtd?.enabled && gtd?.todos;
|
|
146
143
|
|
|
147
144
|
return [
|
|
148
|
-
// =============================================
|
|
149
|
-
// Phase 1: History Management
|
|
150
|
-
// =============================================
|
|
151
|
-
|
|
152
|
-
// 1. History truncation (MUST be first, before any message injection)
|
|
153
|
-
new HistoryTruncateProcessor({
|
|
154
|
-
enableHistoryCount,
|
|
155
|
-
historyCount,
|
|
156
|
-
}),
|
|
157
|
-
|
|
158
145
|
// =============================================
|
|
159
146
|
// Phase 2: System Role Injection
|
|
160
147
|
// =============================================
|
|
@@ -113,31 +113,6 @@ describe('MessagesEngine', () => {
|
|
|
113
113
|
expect(result.messages[0].content).toBe(systemRole);
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
-
it('should truncate history when enabled', async () => {
|
|
117
|
-
const messages: UIChatMessage[] = [];
|
|
118
|
-
for (let i = 0; i < 20; i++) {
|
|
119
|
-
messages.push({
|
|
120
|
-
content: `Message ${i}`,
|
|
121
|
-
createdAt: Date.now(),
|
|
122
|
-
id: `msg-${i}`,
|
|
123
|
-
role: i % 2 === 0 ? 'user' : 'assistant',
|
|
124
|
-
updatedAt: Date.now(),
|
|
125
|
-
} as UIChatMessage);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const params = createBasicParams({
|
|
129
|
-
enableHistoryCount: true,
|
|
130
|
-
historyCount: 5,
|
|
131
|
-
messages,
|
|
132
|
-
});
|
|
133
|
-
const engine = new MessagesEngine(params);
|
|
134
|
-
|
|
135
|
-
const result = await engine.process();
|
|
136
|
-
|
|
137
|
-
// Should have truncated to 5 messages
|
|
138
|
-
expect(result.messages.length).toBeLessThanOrEqual(5);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
116
|
it('should inject history summary when provided', async () => {
|
|
142
117
|
const historySummary = 'We discussed AI and machine learning';
|
|
143
118
|
const params = createBasicParams({ historySummary });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { eq, inArray } from 'drizzle-orm';
|
|
1
|
+
import { asc, eq, inArray } from 'drizzle-orm';
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
3
3
|
|
|
4
4
|
import { getTestDB } from '../../../core/getTestDB';
|
|
@@ -188,12 +188,12 @@ describe('TopicModel - Create', () => {
|
|
|
188
188
|
userId,
|
|
189
189
|
});
|
|
190
190
|
|
|
191
|
-
const items = await serverDB.select().from(topics);
|
|
191
|
+
const items = await serverDB.select().from(topics).orderBy(asc(topics.title));
|
|
192
192
|
expect(items).toHaveLength(2);
|
|
193
193
|
expect(items[0]).toMatchObject({ title: 'Topic 1', favorite: true, sessionId, userId });
|
|
194
194
|
expect(items[1]).toMatchObject({ title: 'Topic 2', favorite: false, sessionId, userId });
|
|
195
195
|
|
|
196
|
-
const updatedMessages = await serverDB.select().from(messages);
|
|
196
|
+
const updatedMessages = await serverDB.select().from(messages).orderBy(asc(messages.id));
|
|
197
197
|
expect(updatedMessages).toHaveLength(3);
|
|
198
198
|
expect(updatedMessages[0].topicId).toBe(createdTopics[0].id);
|
|
199
199
|
expect(updatedMessages[1].topicId).toBe(createdTopics[0].id);
|
|
@@ -110,6 +110,7 @@ const TopicItem = memo<TopicItemProps>(({ id, title, fav, active, threadId }) =>
|
|
|
110
110
|
fill={fav ? cssVar.colorWarning : 'transparent'}
|
|
111
111
|
icon={Star}
|
|
112
112
|
onClick={(e) => {
|
|
113
|
+
e.preventDefault();
|
|
113
114
|
e.stopPropagation();
|
|
114
115
|
favoriteTopic(id, !fav);
|
|
115
116
|
}}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { Flexbox } from '@lobehub/ui';
|
|
4
|
+
import debug from 'debug';
|
|
4
5
|
import { Suspense, memo, useMemo } from 'react';
|
|
5
6
|
|
|
6
7
|
import ChatMiniMap from '@/features/ChatMiniMap';
|
|
@@ -18,6 +19,8 @@ import ThreadHydration from './ThreadHydration';
|
|
|
18
19
|
import { useActionsBarConfig } from './useActionsBarConfig';
|
|
19
20
|
import { useAgentContext } from './useAgentContext';
|
|
20
21
|
|
|
22
|
+
const log = debug('lobe-render:agent:ConversationArea');
|
|
23
|
+
|
|
21
24
|
/**
|
|
22
25
|
* ConversationArea
|
|
23
26
|
*
|
|
@@ -35,6 +38,7 @@ const Conversation = memo(() => {
|
|
|
35
38
|
);
|
|
36
39
|
const replaceMessages = useChatStore((s) => s.replaceMessages);
|
|
37
40
|
const messages = useChatStore((s) => s.dbMessagesMap[chatKey]);
|
|
41
|
+
log('contextKey %s: %o', chatKey, messages);
|
|
38
42
|
|
|
39
43
|
// Get operation state from ChatStore for reactive updates
|
|
40
44
|
const operationState = useOperationState(context);
|
|
@@ -111,6 +111,7 @@ const TopicItem = memo<TopicItemProps>(({ id, title, fav, active, threadId }) =>
|
|
|
111
111
|
fill={fav ? cssVar.colorWarning : 'transparent'}
|
|
112
112
|
icon={Star}
|
|
113
113
|
onClick={(e) => {
|
|
114
|
+
e.preventDefault();
|
|
114
115
|
e.stopPropagation();
|
|
115
116
|
favoriteTopic(id, !fav);
|
|
116
117
|
}}
|
|
@@ -106,7 +106,7 @@ const AgentItem = memo<AgentItemProps>(({ item, style, className }) => {
|
|
|
106
106
|
|
|
107
107
|
return (
|
|
108
108
|
<>
|
|
109
|
-
<Link aria-label={
|
|
109
|
+
<Link aria-label={displayTitle} to={agentUrl}>
|
|
110
110
|
<NavItem
|
|
111
111
|
actions={<Actions dropdownMenu={dropdownMenu} />}
|
|
112
112
|
className={className}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { DEFAULT_INBOX_AVATAR, SESSION_CHAT_URL } from '@lobechat/const';
|
|
4
4
|
import { Avatar } from '@lobehub/ui';
|
|
5
|
-
import { type CSSProperties, memo
|
|
6
|
-
import {
|
|
5
|
+
import { type CSSProperties, memo } from 'react';
|
|
6
|
+
import { Link } from 'react-router-dom';
|
|
7
7
|
|
|
8
8
|
import NavItem from '@/features/NavPanel/components/NavItem';
|
|
9
9
|
import { useAgentStore } from '@/store/agent';
|
|
@@ -17,38 +17,28 @@ interface InboxItemProps {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const InboxItem = memo<InboxItemProps>(({ className, style }) => {
|
|
20
|
-
const navigate = useNavigate();
|
|
21
|
-
|
|
22
20
|
const inboxAgentId = useAgentStore(builtinAgentSelectors.inboxAgentId);
|
|
23
|
-
const activeAgentId = useAgentStore((s) => s.activeAgentId);
|
|
24
|
-
const isActive = !!inboxAgentId && activeAgentId === inboxAgentId;
|
|
25
21
|
|
|
26
|
-
const isLoading = useChatStore(
|
|
27
|
-
useCallback(
|
|
28
|
-
(s) => (isActive ? operationSelectors.isAgentRuntimeRunning(s) : false),
|
|
29
|
-
[isActive],
|
|
30
|
-
),
|
|
31
|
-
);
|
|
22
|
+
const isLoading = useChatStore(operationSelectors.isAgentRuntimeRunning);
|
|
32
23
|
const inboxAgentTitle = 'Lobe AI';
|
|
33
24
|
|
|
34
|
-
const handleClick = useCallback(() => {
|
|
35
|
-
if (inboxAgentId) {
|
|
36
|
-
navigate(SESSION_CHAT_URL(inboxAgentId, false));
|
|
37
|
-
}
|
|
38
|
-
}, [inboxAgentId, navigate]);
|
|
39
|
-
|
|
40
25
|
return (
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
26
|
+
<Link aria-label={inboxAgentTitle} to={SESSION_CHAT_URL(inboxAgentId, false)}>
|
|
27
|
+
<NavItem
|
|
28
|
+
className={className}
|
|
29
|
+
icon={
|
|
30
|
+
<Avatar
|
|
31
|
+
avatar={DEFAULT_INBOX_AVATAR}
|
|
32
|
+
emojiScaleWithBackground
|
|
33
|
+
shape={'square'}
|
|
34
|
+
size={24}
|
|
35
|
+
/>
|
|
36
|
+
}
|
|
37
|
+
loading={isLoading}
|
|
38
|
+
style={style}
|
|
39
|
+
title={inboxAgentTitle}
|
|
40
|
+
/>
|
|
41
|
+
</Link>
|
|
52
42
|
);
|
|
53
43
|
});
|
|
54
44
|
|
|
@@ -4,6 +4,7 @@ import { MoreHorizontal } from 'lucide-react';
|
|
|
4
4
|
import { type CSSProperties, memo, useMemo } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
|
+
import EmptyNavItem from '@/features/NavPanel/components/EmptyNavItem';
|
|
7
8
|
import NavItem from '@/features/NavPanel/components/NavItem';
|
|
8
9
|
import { useGlobalStore } from '@/store/global';
|
|
9
10
|
import { systemStatusSelectors } from '@/store/global/selectors';
|
|
@@ -11,7 +12,6 @@ import { useHomeStore } from '@/store/home';
|
|
|
11
12
|
import { homeAgentListSelectors } from '@/store/home/selectors';
|
|
12
13
|
import { SessionDefaultGroup } from '@/types/session';
|
|
13
14
|
|
|
14
|
-
import EmptyNavItem from '../../../../../../../../features/NavPanel/components/EmptyNavItem';
|
|
15
15
|
import { useCreateMenuItems } from '../../../hooks';
|
|
16
16
|
import GroupItem from './AgentGroupItem';
|
|
17
17
|
import AgentItem from './AgentItem';
|
|
@@ -5,8 +5,8 @@ import { type ReactNode, createContext, memo, useContext, useMemo, useState } fr
|
|
|
5
5
|
import { ChatGroupWizard } from '@/components/ChatGroupWizard';
|
|
6
6
|
import { MemberSelectionModal } from '@/components/MemberSelectionModal';
|
|
7
7
|
|
|
8
|
-
import CreateGroupModal from '../../CreateGroupModal';
|
|
9
8
|
import ConfigGroupModal from './Modals/ConfigGroupModal';
|
|
9
|
+
import CreateGroupModal from './Modals/CreateGroupModal';
|
|
10
10
|
|
|
11
11
|
interface AgentModalContextValue {
|
|
12
12
|
closeAllModals: () => void;
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { Flexbox } from '@lobehub/ui';
|
|
4
4
|
import { Fragment, memo, useCallback, useState } from 'react';
|
|
5
|
-
import { Document, Page, pdfjs } from 'react-pdf';
|
|
6
5
|
import 'react-pdf/dist/Page/AnnotationLayer.css';
|
|
7
6
|
import 'react-pdf/dist/Page/TextLayer.css';
|
|
8
7
|
|
|
9
8
|
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
|
10
|
-
import '@/libs/pdfjs
|
|
9
|
+
import { Document, Page, pdfjs } from '@/libs/pdfjs';
|
|
11
10
|
import { lambdaQuery } from '@/libs/trpc/client';
|
|
12
11
|
|
|
13
12
|
import HighlightLayer from './HighlightLayer';
|
|
@@ -71,7 +70,7 @@ const PDFViewer = memo<PDFViewerProps>(({ url, fileId }) => {
|
|
|
71
70
|
onLoadSuccess={onDocumentLoadSuccess}
|
|
72
71
|
options={options}
|
|
73
72
|
>
|
|
74
|
-
{Array.from({ length: numPages }, (
|
|
73
|
+
{Array.from({ length: numPages }, (_, index) => {
|
|
75
74
|
const width = containerWidth ? Math.min(containerWidth, maxWidth) : maxWidth;
|
|
76
75
|
|
|
77
76
|
return (
|
|
@@ -7,10 +7,9 @@ import { createStaticStyles, cx } from 'antd-style';
|
|
|
7
7
|
import { ChevronLeft, ChevronRight, Expand, FileText } from 'lucide-react';
|
|
8
8
|
import { memo, useState } from 'react';
|
|
9
9
|
import { useTranslation } from 'react-i18next';
|
|
10
|
-
import { Document, Page } from 'react-pdf';
|
|
11
10
|
|
|
12
11
|
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
13
|
-
import '@/libs/pdfjs
|
|
12
|
+
import { Document, Page } from '@/libs/pdfjs';
|
|
14
13
|
|
|
15
14
|
import { containerStyles } from '../style';
|
|
16
15
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { ComponentProps } from 'react';
|
|
4
|
+
import { Document as PdfDocument, Page as PdfPage, pdfjs } from 'react-pdf';
|
|
5
|
+
|
|
6
|
+
const workerSrc = `https://registry.npmmirror.com/pdfjs-dist/${pdfjs.version}/files/build/pdf.worker.min.mjs`;
|
|
7
|
+
|
|
8
|
+
function ensureWorker() {
|
|
9
|
+
if (!pdfjs.GlobalWorkerOptions.workerSrc) {
|
|
10
|
+
pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type DocumentProps = ComponentProps<typeof PdfDocument>;
|
|
15
|
+
export type PageProps = ComponentProps<typeof PdfPage>;
|
|
16
|
+
|
|
17
|
+
export const Document = (props: DocumentProps) => {
|
|
18
|
+
ensureWorker();
|
|
19
|
+
return <PdfDocument {...props} />;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
export {Page, pdfjs} from 'react-pdf';
|
|
@@ -178,6 +178,9 @@ export default {
|
|
|
178
178
|
'builtins.lobe-user-memory.apiName.searchUserMemory': 'Search memory',
|
|
179
179
|
'builtins.lobe-user-memory.apiName.updateIdentityMemory': 'Update identity memory',
|
|
180
180
|
'builtins.lobe-user-memory.inspector.noResults': 'No results',
|
|
181
|
+
'builtins.lobe-user-memory.render.contexts': 'Contexts',
|
|
182
|
+
'builtins.lobe-user-memory.render.experiences': 'Experiences',
|
|
183
|
+
'builtins.lobe-user-memory.render.preferences': 'Preferences',
|
|
181
184
|
'builtins.lobe-user-memory.title': 'Memory',
|
|
182
185
|
'builtins.lobe-web-browsing.apiName.crawlMultiPages': 'Read multiple pages',
|
|
183
186
|
'builtins.lobe-web-browsing.apiName.crawlSinglePage': 'Read page content',
|
|
@@ -68,31 +68,6 @@ describe('serverMessagesEngine', () => {
|
|
|
68
68
|
});
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
describe('history truncation', () => {
|
|
72
|
-
it('should truncate history when enabled', async () => {
|
|
73
|
-
const messages: UIChatMessage[] = [];
|
|
74
|
-
for (let i = 0; i < 20; i++) {
|
|
75
|
-
messages.push({
|
|
76
|
-
content: `Message ${i}`,
|
|
77
|
-
createdAt: Date.now(),
|
|
78
|
-
id: `msg-${i}`,
|
|
79
|
-
role: i % 2 === 0 ? 'user' : 'assistant',
|
|
80
|
-
updatedAt: Date.now(),
|
|
81
|
-
} as UIChatMessage);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const result = await serverMessagesEngine({
|
|
85
|
-
enableHistoryCount: true,
|
|
86
|
-
historyCount: 5,
|
|
87
|
-
messages,
|
|
88
|
-
model: 'gpt-4',
|
|
89
|
-
provider: 'openai',
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
expect(result.length).toBeLessThanOrEqual(5);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
71
|
describe('knowledge injection', () => {
|
|
97
72
|
it('should inject file contents', async () => {
|
|
98
73
|
const messages = createBasicMessages();
|