@lobehub/lobehub 2.0.2 → 2.0.3

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/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 2.0.3](https://github.com/lobehub/lobe-chat/compare/v2.0.2...v2.0.3)
6
+
7
+ <sup>Released on **2026-01-27**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Fixed compressed group message & open the switch config to control compression config enabled, fixed the onboarding crash problem.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Fixed compressed group message & open the switch config to control compression config enabled, closes [#11901](https://github.com/lobehub/lobe-chat/issues/11901) ([dc51838](https://github.com/lobehub/lobe-chat/commit/dc51838))
21
+ - **misc**: Fixed the onboarding crash problem, closes [#11905](https://github.com/lobehub/lobe-chat/issues/11905) ([439e4ee](https://github.com/lobehub/lobe-chat/commit/439e4ee))
22
+
23
+ </details>
24
+
25
+ <div align="right">
26
+
27
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
28
+
29
+ </div>
30
+
5
31
  ### [Version 2.0.2](https://github.com/lobehub/lobe-chat/compare/v2.0.1...v2.0.2)
6
32
 
7
33
  <sup>Released on **2026-01-27**</sup>
package/changelog/v2.json CHANGED
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "fixes": [
5
+ "Fixed compressed group message & open the switch config to control compression config enabled, fixed the onboarding crash problem."
6
+ ]
7
+ },
8
+ "date": "2026-01-27",
9
+ "version": "2.0.3"
10
+ },
2
11
  {
3
12
  "children": {
4
13
  "fixes": [
@@ -446,6 +446,8 @@
446
446
  "settingImage.defaultCount.desc": "Set the default number of images generated when creating a new task in the image generation panel.",
447
447
  "settingImage.defaultCount.label": "Default Image Count",
448
448
  "settingImage.defaultCount.title": "AI Art",
449
+ "settingModel.enableContextCompression.desc": "Automatically compress historical messages into summaries when conversation exceeds 64,000 tokens, saving 60-80% token usage",
450
+ "settingModel.enableContextCompression.title": "Enable Auto Context Compression",
449
451
  "settingModel.enableMaxTokens.title": "Enable Max Tokens Limit",
450
452
  "settingModel.enableReasoningEffort.title": "Enable Reasoning Effort Adjustment",
451
453
  "settingModel.frequencyPenalty.desc": "The higher the value, the more diverse and rich the vocabulary; the lower the value, the simpler and more straightforward the language.",
@@ -446,6 +446,8 @@
446
446
  "settingImage.defaultCount.desc": "设置图像生成面板在创建新任务时的默认图片数量。",
447
447
  "settingImage.defaultCount.label": "默认图片数量",
448
448
  "settingImage.defaultCount.title": "AI 绘画设置",
449
+ "settingModel.enableContextCompression.desc": "当对话消息超过 64,000 tokens 时,自动将历史消息压缩为摘要,节省 60-80% 的 token 用量",
450
+ "settingModel.enableContextCompression.title": "开启自动上下文压缩",
449
451
  "settingModel.enableMaxTokens.title": "开启单次回复限制",
450
452
  "settingModel.enableReasoningEffort.title": "开启推理强度调整",
451
453
  "settingModel.frequencyPenalty.desc": "值越大,用词越丰富多样;值越低,用词更朴实简单",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
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",
@@ -328,7 +328,7 @@
328
328
  "remark-gfm": "^4.0.1",
329
329
  "remark-html": "^16.0.1",
330
330
  "remove-markdown": "^0.6.3",
331
- "resend": "^6.8.0",
331
+ "resend": "6.8.0",
332
332
  "resolve-accept-language": "^3.1.15",
333
333
  "rtl-detect": "^1.1.2",
334
334
  "semver": "^7.7.3",
@@ -283,21 +283,25 @@ export class GeneralChatAgent implements Agent {
283
283
  switch (context.phase) {
284
284
  case 'init':
285
285
  case 'user_input': {
286
- // Check if context compression is needed before calling LLM
287
- const compressionCheck = shouldCompress(state.messages, {
288
- maxWindowToken: this.config.compressionConfig?.maxWindowToken,
289
- });
286
+ // Check if context compression is enabled and needed before calling LLM
287
+ const compressionEnabled = this.config.compressionConfig?.enabled ?? true; // Default to enabled
290
288
 
291
- if (compressionCheck.needsCompression) {
292
- // Context exceeds threshold, compress ALL messages into a single summary
293
- return {
294
- payload: {
295
- currentTokenCount: compressionCheck.currentTokenCount,
296
- existingSummary: this.findExistingSummary(state.messages),
297
- messages: state.messages,
298
- },
299
- type: 'compress_context',
300
- } as AgentInstructionCompressContext;
289
+ if (compressionEnabled) {
290
+ const compressionCheck = shouldCompress(state.messages, {
291
+ maxWindowToken: this.config.compressionConfig?.maxWindowToken,
292
+ });
293
+
294
+ if (compressionCheck.needsCompression) {
295
+ // Context exceeds threshold, compress ALL messages into a single summary
296
+ return {
297
+ payload: {
298
+ currentTokenCount: compressionCheck.currentTokenCount,
299
+ existingSummary: this.findExistingSummary(state.messages),
300
+ messages: state.messages,
301
+ },
302
+ type: 'compress_context',
303
+ } as AgentInstructionCompressContext;
304
+ }
301
305
  }
302
306
 
303
307
  // User input received, call LLM to generate response
@@ -69,16 +69,15 @@ export interface GeneralAgentConfig {
69
69
  };
70
70
  /**
71
71
  * Context compression configuration
72
- * Note: Compression checking is always enabled to prevent context overflow.
73
- * When triggered, ALL messages are compressed into a single MessageGroup summary.
72
+ * When enabled and triggered, ALL messages are compressed into a single MessageGroup summary.
74
73
  */
75
74
  compressionConfig?: {
75
+ /** Whether context compression is enabled (default: true) */
76
+ enabled?: boolean;
76
77
  /** Model's max context window token count (default: 128k) */
77
78
  maxWindowToken?: number;
78
79
  };
79
80
  modelRuntimeConfig?: {
80
- model: string;
81
- provider: string;
82
81
  /**
83
82
  * Compression model configuration
84
83
  * Used for context compression tasks
@@ -87,6 +86,8 @@ export interface GeneralAgentConfig {
87
86
  model: string;
88
87
  provider: string;
89
88
  };
89
+ model: string;
90
+ provider: string;
90
91
  };
91
92
  operationId: string;
92
93
  userId?: string;
@@ -320,7 +320,23 @@ const Controls = memo<ControlsProps>(({ setUpdating }) => {
320
320
  : []),
321
321
  ];
322
322
 
323
- const allItems = [...baseItems, ...maxTokensItems];
323
+ // Context Compression items
324
+ const contextCompressionItems: FormItemProps[] = [
325
+ {
326
+ children: <Switch />,
327
+ label: (
328
+ <Flexbox align={'center'} className={styles.label} gap={8} horizontal>
329
+ {t('settingModel.enableContextCompression.title')}
330
+ <InfoTooltip title={t('settingModel.enableContextCompression.desc')} />
331
+ </Flexbox>
332
+ ),
333
+ name: ['chatConfig', 'enableContextCompression'],
334
+ tag: 'compression',
335
+ valuePropName: 'checked',
336
+ },
337
+ ];
338
+
339
+ const allItems = [...baseItems, ...maxTokensItems, ...contextCompressionItems];
324
340
 
325
341
  return (
326
342
  <Form
@@ -113,7 +113,7 @@ const ModelSelect = memo<ModelSelectProps>(
113
113
  <ModelItemRender
114
114
  displayName={data.displayName}
115
115
  id={data.id}
116
- showInfoTag
116
+ showInfoTag={false}
117
117
  {...data.abilities}
118
118
  />
119
119
  );
@@ -501,6 +501,9 @@ export default {
501
501
  'Set the default number of images generated when creating a new task in the image generation panel.',
502
502
  'settingImage.defaultCount.label': 'Default Image Count',
503
503
  'settingImage.defaultCount.title': 'AI Art',
504
+ 'settingModel.enableContextCompression.desc':
505
+ 'Automatically compress historical messages into summaries when conversation exceeds 64,000 tokens, saving 60-80% token usage',
506
+ 'settingModel.enableContextCompression.title': 'Enable Auto Context Compression',
504
507
  'settingModel.enableMaxTokens.title': 'Enable Max Tokens Limit',
505
508
  'settingModel.enableReasoningEffort.title': 'Enable Reasoning Effort Adjustment',
506
509
  'settingModel.frequencyPenalty.desc':
@@ -126,8 +126,7 @@ export class AgentRuntimeService {
126
126
  */
127
127
  private stepCallbacks: Map<string, StepLifecycleCallbacks> = new Map();
128
128
  private get baseURL() {
129
- const baseUrl =
130
- process.env.AGENT_RUNTIME_BASE_URL || appEnv.APP_URL || 'http://localhost:3010';
129
+ const baseUrl = process.env.AGENT_RUNTIME_BASE_URL || appEnv.APP_URL || 'http://localhost:3010';
131
130
 
132
131
  return urlJoin(baseUrl, '/api/agent');
133
132
  }
@@ -840,6 +839,9 @@ export class AgentRuntimeService {
840
839
  // Create Durable Agent instance
841
840
  const agent = new GeneralChatAgent({
842
841
  agentConfig: metadata?.agentConfig,
842
+ compressionConfig: {
843
+ enabled: metadata?.agentConfig?.chatConfig?.enableContextCompression ?? true,
844
+ },
843
845
  modelRuntimeConfig: metadata?.modelRuntimeConfig,
844
846
  operationId,
845
847
  userId: metadata?.userId,
@@ -702,6 +702,9 @@ export const streamingExecutor: StateCreator<
702
702
 
703
703
  const agent = new GeneralChatAgent({
704
704
  agentConfig: { maxSteps: 1000 },
705
+ compressionConfig: {
706
+ enabled: agentConfigData.chatConfig?.enableContextCompression ?? true, // Default to enabled
707
+ },
705
708
  operationId: `${messageKey}/${params.parentMessageId}`,
706
709
  modelRuntimeConfig,
707
710
  });
@@ -833,5 +833,26 @@ describe('displayMessageSelectors', () => {
833
833
  const result = displayMessageSelectors.findLastMessageId('msg-1')(state as ChatStore);
834
834
  expect(result).toBe('tool-result-id');
835
835
  });
836
+
837
+ it('should return lastMessageId for compressedGroup instead of group id', () => {
838
+ const compressedGroupMessage = {
839
+ id: 'mg_123456',
840
+ role: 'compressedGroup',
841
+ content: 'Compressed summary',
842
+ lastMessageId: 'msg-999',
843
+ compressedMessages: [],
844
+ pinnedMessages: [],
845
+ } as unknown as UIChatMessage;
846
+
847
+ const state: Partial<ChatStore> = {
848
+ activeAgentId: 'test-id',
849
+ messagesMap: {
850
+ [messageMapKey({ agentId: 'test-id' })]: [compressedGroupMessage],
851
+ },
852
+ };
853
+
854
+ const result = displayMessageSelectors.findLastMessageId('mg_123456')(state as ChatStore);
855
+ expect(result).toBe('msg-999');
856
+ });
836
857
  });
837
858
  });
@@ -247,7 +247,7 @@ const findLastBlockId = (block: AssistantContentBlock | undefined): string | und
247
247
 
248
248
  /**
249
249
  * Recursively finds the last message ID in a message tree
250
- * Priority: children > tools > self
250
+ * Priority: children > tools > compressedGroup.lastMessageId > self
251
251
  */
252
252
  const findLastMessageIdRecursive = (node: UIChatMessage | undefined): string | undefined => {
253
253
  if (!node) return undefined;
@@ -264,7 +264,12 @@ const findLastMessageIdRecursive = (node: UIChatMessage | undefined): string | u
264
264
  return lastTool?.result_msg_id;
265
265
  }
266
266
 
267
- // Priority 3: Return self ID
267
+ // Priority 3: For compressedGroup, return lastMessageId instead of group ID
268
+ if (node.role === 'compressedGroup' && 'lastMessageId' in node) {
269
+ return (node as any).lastMessageId;
270
+ }
271
+
272
+ // Priority 4: Return self ID
268
273
  return node.id;
269
274
  };
270
275