@lobehub/lobehub 2.0.0-next.360 → 2.0.0-next.362

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.
Files changed (76) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/Dockerfile +2 -1
  3. package/changelog/v1.json +14 -0
  4. package/locales/en-US/chat.json +3 -1
  5. package/locales/zh-CN/chat.json +2 -0
  6. package/package.json +1 -1
  7. package/packages/const/src/userMemory.ts +1 -0
  8. package/packages/context-engine/src/base/BaseEveryUserContentProvider.ts +204 -0
  9. package/packages/context-engine/src/base/BaseLastUserContentProvider.ts +1 -8
  10. package/packages/context-engine/src/base/__tests__/BaseEveryUserContentProvider.test.ts +354 -0
  11. package/packages/context-engine/src/base/constants.ts +20 -0
  12. package/packages/context-engine/src/engine/messages/MessagesEngine.ts +27 -23
  13. package/packages/context-engine/src/engine/messages/__tests__/MessagesEngine.test.ts +364 -0
  14. package/packages/context-engine/src/providers/PageEditorContextInjector.ts +17 -13
  15. package/packages/context-engine/src/providers/PageSelectionsInjector.ts +65 -0
  16. package/packages/context-engine/src/providers/__tests__/PageSelectionsInjector.test.ts +333 -0
  17. package/packages/context-engine/src/providers/index.ts +3 -1
  18. package/packages/database/src/models/userMemory/model.ts +178 -3
  19. package/packages/database/src/models/userMemory/sources/benchmarkLoCoMo.ts +1 -1
  20. package/packages/memory-user-memory/package.json +2 -1
  21. package/packages/memory-user-memory/promptfoo/evals/activity/basic/buildMessages.ts +40 -0
  22. package/packages/memory-user-memory/promptfoo/evals/activity/basic/eval.yaml +13 -0
  23. package/packages/memory-user-memory/promptfoo/evals/activity/basic/prompt.ts +5 -0
  24. package/packages/memory-user-memory/promptfoo/evals/activity/basic/tests/cases.ts +106 -0
  25. package/packages/memory-user-memory/promptfoo/evals/activity/locomo/buildMessages.ts +104 -0
  26. package/packages/memory-user-memory/promptfoo/evals/activity/locomo/eval.yaml +13 -0
  27. package/packages/memory-user-memory/promptfoo/evals/activity/locomo/prompt.ts +5 -0
  28. package/packages/memory-user-memory/promptfoo/evals/activity/locomo/tests/benchmark-locomo-payload-conv-26.json +149 -0
  29. package/packages/memory-user-memory/promptfoo/evals/activity/locomo/tests/cases.ts +72 -0
  30. package/packages/memory-user-memory/promptfoo/response-formats/activity.json +370 -0
  31. package/packages/memory-user-memory/promptfoo/response-formats/experience.json +14 -0
  32. package/packages/memory-user-memory/promptfoo/response-formats/identity.json +281 -255
  33. package/packages/memory-user-memory/promptfooconfig.yaml +1 -0
  34. package/packages/memory-user-memory/scripts/generate-response-formats.ts +26 -2
  35. package/packages/memory-user-memory/src/extractors/activity.ts +44 -0
  36. package/packages/memory-user-memory/src/extractors/gatekeeper.test.ts +2 -1
  37. package/packages/memory-user-memory/src/extractors/gatekeeper.ts +2 -1
  38. package/packages/memory-user-memory/src/extractors/index.ts +1 -0
  39. package/packages/memory-user-memory/src/prompts/gatekeeper.ts +3 -3
  40. package/packages/memory-user-memory/src/prompts/index.ts +7 -1
  41. package/packages/memory-user-memory/src/prompts/layers/activity.ts +90 -0
  42. package/packages/memory-user-memory/src/prompts/layers/index.ts +1 -0
  43. package/packages/memory-user-memory/src/providers/existingUserMemory.test.ts +25 -1
  44. package/packages/memory-user-memory/src/providers/existingUserMemory.ts +113 -0
  45. package/packages/memory-user-memory/src/schemas/activity.ts +315 -0
  46. package/packages/memory-user-memory/src/schemas/experience.ts +5 -5
  47. package/packages/memory-user-memory/src/schemas/gatekeeper.ts +1 -0
  48. package/packages/memory-user-memory/src/schemas/index.ts +1 -0
  49. package/packages/memory-user-memory/src/services/extractExecutor.ts +29 -0
  50. package/packages/memory-user-memory/src/types.ts +7 -0
  51. package/packages/prompts/src/agents/index.ts +1 -0
  52. package/packages/prompts/src/agents/pageSelectionContext.ts +28 -0
  53. package/packages/types/src/aiChat.ts +4 -0
  54. package/packages/types/src/message/common/index.ts +1 -0
  55. package/packages/types/src/message/common/metadata.ts +8 -0
  56. package/packages/types/src/message/common/pageSelection.ts +36 -0
  57. package/packages/types/src/message/ui/params.ts +16 -0
  58. package/packages/types/src/serverConfig.ts +1 -1
  59. package/packages/types/src/userMemory/layers.ts +52 -0
  60. package/packages/types/src/userMemory/list.ts +20 -2
  61. package/packages/types/src/userMemory/shared.ts +22 -1
  62. package/packages/types/src/userMemory/trace.ts +1 -0
  63. package/packages/types/src/util.ts +9 -1
  64. package/scripts/prebuild.mts +1 -0
  65. package/src/features/ChatInput/Desktop/ContextContainer/ContextList.tsx +1 -1
  66. package/src/features/Conversation/ChatInput/index.tsx +9 -1
  67. package/src/features/Conversation/Messages/User/components/MessageContent.tsx +7 -1
  68. package/src/features/Conversation/Messages/User/components/PageSelections.tsx +62 -0
  69. package/src/features/PageEditor/EditorCanvas/useAskCopilotItem.tsx +5 -1
  70. package/src/libs/next/proxy/define-config.ts +1 -0
  71. package/src/locales/default/chat.ts +3 -2
  72. package/src/server/globalConfig/parseMemoryExtractionConfig.ts +7 -1
  73. package/src/server/routers/lambda/aiChat.ts +7 -0
  74. package/src/server/services/memory/userMemory/__tests__/extract.runtime.test.ts +2 -0
  75. package/src/server/services/memory/userMemory/extract.ts +108 -7
  76. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +5 -19
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 2.0.0-next.362](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.361...v2.0.0-next.362)
6
+
7
+ <sup>Released on **2026-01-24**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Fix page selection not display correctly.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Fix page selection not display correctly, closes [#11765](https://github.com/lobehub/lobe-chat/issues/11765) ([7ae5f68](https://github.com/lobehub/lobe-chat/commit/7ae5f68))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ## [Version 2.0.0-next.361](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.360...v2.0.0-next.361)
31
+
32
+ <sup>Released on **2026-01-24**</sup>
33
+
34
+ #### ✨ Features
35
+
36
+ - **userMemories**: Added memory layer activity.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### What's improved
44
+
45
+ - **userMemories**: Added memory layer activity, closes [#11747](https://github.com/lobehub/lobe-chat/issues/11747) ([2021b1c](https://github.com/lobehub/lobe-chat/commit/2021b1c))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ## [Version 2.0.0-next.360](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.359...v2.0.0-next.360)
6
56
 
7
57
  <sup>Released on **2026-01-24**</sup>
package/Dockerfile CHANGED
@@ -47,7 +47,8 @@ ENV NEXT_PUBLIC_BASE_PATH="${NEXT_PUBLIC_BASE_PATH}" \
47
47
  ENV APP_URL="http://app.com" \
48
48
  DATABASE_DRIVER="node" \
49
49
  DATABASE_URL="postgres://postgres:password@localhost:5432/postgres" \
50
- KEY_VAULTS_SECRET="use-for-build"
50
+ KEY_VAULTS_SECRET="use-for-build" \
51
+ AUTH_SECRET="use-for-build"
51
52
 
52
53
  # Sentry
53
54
  ENV NEXT_PUBLIC_SENTRY_DSN="${NEXT_PUBLIC_SENTRY_DSN}" \
package/changelog/v1.json CHANGED
@@ -1,4 +1,18 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "fixes": [
5
+ "Fix page selection not display correctly."
6
+ ]
7
+ },
8
+ "date": "2026-01-24",
9
+ "version": "2.0.0-next.362"
10
+ },
11
+ {
12
+ "children": {},
13
+ "date": "2026-01-24",
14
+ "version": "2.0.0-next.361"
15
+ },
2
16
  {
3
17
  "children": {
4
18
  "fixes": [
@@ -208,7 +208,9 @@
208
208
  "operation.sendMessage": "Sending message",
209
209
  "owner": "Group owner",
210
210
  "pageCopilot.title": "Page Agent",
211
- "pageCopilot.welcome": "**Clearer, sharper writing**\n\nDraft, rewrite, or polish—tell me your intent and Ill refine the rest.",
211
+ "pageCopilot.welcome": "**Clearer, sharper writing**\n\nDraft, rewrite, or polish—tell me your intent and I'll refine the rest.",
212
+ "pageSelection.lines": "Lines {{start}}-{{end}}",
213
+ "pageSelection.reference": "Selected Text",
212
214
  "pin": "Pin",
213
215
  "pinOff": "Unpin",
214
216
  "prompts.summaryExpert": "As a summary expert, please summarize the following content based on the system prompts above:",
@@ -209,6 +209,8 @@
209
209
  "owner": "群主",
210
210
  "pageCopilot.title": "文稿助理",
211
211
  "pageCopilot.welcome": "**让文字更清晰、更到位**\n\n起草、改写、润色都可以。你把意图说清楚,其余交给我打磨",
212
+ "pageSelection.lines": "第 {{start}}-{{end}} 行",
213
+ "pageSelection.reference": "选中文本",
212
214
  "pin": "置顶",
213
215
  "pinOff": "取消置顶",
214
216
  "prompts.summaryExpert": "作为一名总结专家,请结合以上系统提示词,将以下内容进行总结:",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.360",
3
+ "version": "2.0.0-next.362",
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",
@@ -3,6 +3,7 @@ import { DEFAULT_EMBEDDING_PROVIDER } from '@lobechat/business-const';
3
3
  import { DEFAULT_EMBEDDING_MODEL } from './settings';
4
4
 
5
5
  export const DEFAULT_SEARCH_USER_MEMORY_TOP_K = {
6
+ activities: 3,
6
7
  contexts: 0,
7
8
  experiences: 0,
8
9
  preferences: 3,
@@ -0,0 +1,204 @@
1
+ import type { Message, PipelineContext, ProcessorOptions } from '../types';
2
+ import { BaseProcessor } from './BaseProcessor';
3
+ import { CONTEXT_INSTRUCTION, SYSTEM_CONTEXT_END, SYSTEM_CONTEXT_START } from './constants';
4
+
5
+ /**
6
+ * Base Provider for appending content to every user message
7
+ * Used for injecting context that should be attached to each user message individually
8
+ * (e.g., page selections that are specific to each message)
9
+ *
10
+ * Features:
11
+ * - Iterates through all user messages
12
+ * - For each message, calls buildContentForMessage to get content to inject
13
+ * - Wraps content with SYSTEM CONTEXT markers (or reuses existing wrapper)
14
+ * - Runs BEFORE BaseLastUserContentProvider so that the last user message
15
+ * can reuse the SYSTEM CONTEXT wrapper created here
16
+ */
17
+ export abstract class BaseEveryUserContentProvider extends BaseProcessor {
18
+ constructor(options: ProcessorOptions = {}) {
19
+ super(options);
20
+ }
21
+
22
+ /**
23
+ * Build the content to inject for a specific user message
24
+ * Subclasses must implement this method
25
+ * @param message - The user message to build content for
26
+ * @param index - The index of the message in the messages array
27
+ * @param isLastUser - Whether this is the last user message
28
+ * @returns Object with content and contextType, or null to skip injection for this message
29
+ */
30
+ protected abstract buildContentForMessage(
31
+ message: Message,
32
+ index: number,
33
+ isLastUser: boolean,
34
+ ): { content: string; contextType: string } | null;
35
+
36
+ /**
37
+ * Get the text content from a message (handles both string and array content)
38
+ */
39
+ private getTextContent(content: string | any[]): string {
40
+ if (typeof content === 'string') {
41
+ return content;
42
+ }
43
+ if (Array.isArray(content)) {
44
+ const lastTextPart = content.findLast((part: any) => part.type === 'text');
45
+ return lastTextPart?.text || '';
46
+ }
47
+ return '';
48
+ }
49
+
50
+ /**
51
+ * Check if the content already has a system context wrapper
52
+ */
53
+ protected hasSystemContextWrapper(content: string | any[]): boolean {
54
+ const textContent = this.getTextContent(content);
55
+ return textContent.includes(SYSTEM_CONTEXT_START) && textContent.includes(SYSTEM_CONTEXT_END);
56
+ }
57
+
58
+ /**
59
+ * Wrap content with system context markers
60
+ */
61
+ protected wrapWithSystemContext(content: string, contextType: string): string {
62
+ return `${SYSTEM_CONTEXT_START}
63
+ ${CONTEXT_INSTRUCTION}
64
+ <${contextType}>
65
+ ${content}
66
+ </${contextType}>
67
+ ${SYSTEM_CONTEXT_END}`;
68
+ }
69
+
70
+ /**
71
+ * Insert content into existing system context wrapper (before the END marker)
72
+ */
73
+ private insertIntoExistingWrapper(existingContent: string, newContextBlock: string): string {
74
+ const endMarkerIndex = existingContent.lastIndexOf(SYSTEM_CONTEXT_END);
75
+ if (endMarkerIndex === -1) {
76
+ return existingContent + '\n\n' + newContextBlock;
77
+ }
78
+
79
+ const beforeEnd = existingContent.slice(0, endMarkerIndex);
80
+ const afterEnd = existingContent.slice(endMarkerIndex);
81
+
82
+ return beforeEnd + newContextBlock + '\n' + afterEnd;
83
+ }
84
+
85
+ /**
86
+ * Create a context block without the full wrapper (for inserting into existing wrapper)
87
+ */
88
+ protected createContextBlock(content: string, contextType: string): string {
89
+ return `<${contextType}>
90
+ ${content}
91
+ </${contextType}>`;
92
+ }
93
+
94
+ /**
95
+ * Append content to a message with SYSTEM CONTEXT wrapper
96
+ */
97
+ protected appendToMessage(message: Message, content: string, contextType: string): Message {
98
+ const currentContent = message.content;
99
+
100
+ // Handle string content
101
+ if (typeof currentContent === 'string') {
102
+ let newContent: string;
103
+
104
+ if (this.hasSystemContextWrapper(currentContent)) {
105
+ // Insert into existing wrapper
106
+ const contextBlock = this.createContextBlock(content, contextType);
107
+ newContent = this.insertIntoExistingWrapper(currentContent, contextBlock);
108
+ } else {
109
+ // Create new wrapper
110
+ newContent = currentContent + '\n\n' + this.wrapWithSystemContext(content, contextType);
111
+ }
112
+
113
+ return {
114
+ ...message,
115
+ content: newContent,
116
+ };
117
+ }
118
+
119
+ // Handle array content (multimodal messages)
120
+ if (Array.isArray(currentContent)) {
121
+ const lastTextIndex = currentContent.findLastIndex((part: any) => part.type === 'text');
122
+
123
+ if (lastTextIndex !== -1) {
124
+ const newContent = [...currentContent];
125
+ const existingText = newContent[lastTextIndex].text;
126
+ let updatedText: string;
127
+
128
+ if (this.hasSystemContextWrapper(existingText)) {
129
+ // Insert into existing wrapper
130
+ const contextBlock = this.createContextBlock(content, contextType);
131
+ updatedText = this.insertIntoExistingWrapper(existingText, contextBlock);
132
+ } else {
133
+ // Create new wrapper
134
+ updatedText = existingText + '\n\n' + this.wrapWithSystemContext(content, contextType);
135
+ }
136
+
137
+ newContent[lastTextIndex] = {
138
+ ...newContent[lastTextIndex],
139
+ text: updatedText,
140
+ };
141
+ return {
142
+ ...message,
143
+ content: newContent,
144
+ };
145
+ } else {
146
+ // No text part found, add a new one with wrapper
147
+ return {
148
+ ...message,
149
+ content: [
150
+ ...currentContent,
151
+ { text: this.wrapWithSystemContext(content, contextType), type: 'text' },
152
+ ],
153
+ };
154
+ }
155
+ }
156
+
157
+ return message;
158
+ }
159
+
160
+ /**
161
+ * Find the index of the last user message
162
+ */
163
+ protected findLastUserMessageIndex(messages: Message[]): number {
164
+ for (let i = messages.length - 1; i >= 0; i--) {
165
+ if (messages[i].role === 'user') {
166
+ return i;
167
+ }
168
+ }
169
+ return -1;
170
+ }
171
+
172
+ /**
173
+ * Process the context by injecting content to every user message
174
+ */
175
+ protected async doProcess(context: PipelineContext): Promise<PipelineContext> {
176
+ const clonedContext = this.cloneContext(context);
177
+ const lastUserIndex = this.findLastUserMessageIndex(clonedContext.messages);
178
+ let injectCount = 0;
179
+
180
+ // Iterate through all messages
181
+ for (let i = 0; i < clonedContext.messages.length; i++) {
182
+ const message = clonedContext.messages[i];
183
+
184
+ // Only process user messages
185
+ if (message.role !== 'user') continue;
186
+
187
+ const isLastUser = i === lastUserIndex;
188
+ const result = this.buildContentForMessage(message, i, isLastUser);
189
+
190
+ if (!result) continue;
191
+
192
+ // Append to this user message with SYSTEM CONTEXT wrapper
193
+ clonedContext.messages[i] = this.appendToMessage(message, result.content, result.contextType);
194
+ injectCount++;
195
+ }
196
+
197
+ // Update metadata with injection count
198
+ if (injectCount > 0) {
199
+ clonedContext.metadata[`${this.name}InjectedCount`] = injectCount;
200
+ }
201
+
202
+ return this.markAsExecuted(clonedContext);
203
+ }
204
+ }
@@ -1,13 +1,6 @@
1
1
  import type { Message, PipelineContext, ProcessorOptions } from '../types';
2
2
  import { BaseProcessor } from './BaseProcessor';
3
-
4
- const SYSTEM_CONTEXT_START = '<!-- SYSTEM CONTEXT (NOT PART OF USER QUERY) -->';
5
- const SYSTEM_CONTEXT_END = '<!-- END SYSTEM CONTEXT -->';
6
- const CONTEXT_INSTRUCTION = `<context.instruction>following part contains context information injected by the system. Please follow these instructions:
7
-
8
- 1. Always prioritize handling user-visible content.
9
- 2. the context is only required when user's queries rely on it.
10
- </context.instruction>`;
3
+ import { CONTEXT_INSTRUCTION, SYSTEM_CONTEXT_END, SYSTEM_CONTEXT_START } from './constants';
11
4
 
12
5
  /**
13
6
  * Base Provider for appending content to the last user message