@lobehub/lobehub 2.0.1 → 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.
Files changed (34) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/changelog/v2.json +18 -0
  3. package/locales/ar/subscription.json +1 -0
  4. package/locales/bg-BG/subscription.json +1 -0
  5. package/locales/de-DE/subscription.json +1 -0
  6. package/locales/en-US/setting.json +2 -0
  7. package/locales/en-US/subscription.json +1 -0
  8. package/locales/es-ES/subscription.json +1 -0
  9. package/locales/fa-IR/subscription.json +1 -0
  10. package/locales/fr-FR/subscription.json +1 -0
  11. package/locales/it-IT/subscription.json +1 -0
  12. package/locales/ja-JP/subscription.json +1 -0
  13. package/locales/ko-KR/subscription.json +1 -0
  14. package/locales/nl-NL/subscription.json +1 -0
  15. package/locales/pl-PL/subscription.json +1 -0
  16. package/locales/pt-BR/subscription.json +1 -0
  17. package/locales/ru-RU/subscription.json +1 -0
  18. package/locales/tr-TR/subscription.json +1 -0
  19. package/locales/vi-VN/subscription.json +1 -0
  20. package/locales/zh-CN/setting.json +2 -0
  21. package/locales/zh-CN/subscription.json +1 -0
  22. package/locales/zh-TW/subscription.json +1 -0
  23. package/package.json +2 -2
  24. package/packages/agent-runtime/src/agents/GeneralChatAgent.ts +18 -14
  25. package/packages/agent-runtime/src/types/generalAgent.ts +5 -4
  26. package/src/features/ChatInput/ActionBar/Params/Controls.tsx +17 -1
  27. package/src/features/ModelSelect/index.tsx +1 -1
  28. package/src/locales/default/setting.ts +3 -0
  29. package/src/locales/default/subscription.ts +1 -0
  30. package/src/server/routers/lambda/topic.ts +3 -5
  31. package/src/server/services/agentRuntime/AgentRuntimeService.ts +4 -2
  32. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +3 -0
  33. package/src/store/chat/slices/message/selectors/displayMessage.test.ts +21 -0
  34. package/src/store/chat/slices/message/selectors/displayMessage.ts +7 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,57 @@
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
+
31
+ ### [Version 2.0.2](https://github.com/lobehub/lobe-chat/compare/v2.0.1...v2.0.2)
32
+
33
+ <sup>Released on **2026-01-27**</sup>
34
+
35
+ #### 🐛 Bug Fixes
36
+
37
+ - **misc**: Slove the recentTopicLinkError.
38
+
39
+ <br/>
40
+
41
+ <details>
42
+ <summary><kbd>Improvements and Fixes</kbd></summary>
43
+
44
+ #### What's fixed
45
+
46
+ - **misc**: Slove the recentTopicLinkError, closes [#11896](https://github.com/lobehub/lobe-chat/issues/11896) ([b358413](https://github.com/lobehub/lobe-chat/commit/b358413))
47
+
48
+ </details>
49
+
50
+ <div align="right">
51
+
52
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
53
+
54
+ </div>
55
+
5
56
  ### [Version 2.0.1](https://github.com/lobehub/lobe-chat/compare/v2.0.0...v2.0.1)
6
57
 
7
58
  <sup>Released on **2026-01-27**</sup>
package/changelog/v2.json CHANGED
@@ -1,4 +1,22 @@
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
+ },
11
+ {
12
+ "children": {
13
+ "fixes": [
14
+ "Slove the recentTopicLinkError."
15
+ ]
16
+ },
17
+ "date": "2026-01-27",
18
+ "version": "2.0.2"
19
+ },
2
20
  {
3
21
  "children": {},
4
22
  "date": "2026-01-27",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "تخزين الملفات والصور والبيانات الأخرى",
196
196
  "plans.free": "مجاني",
197
197
  "plans.freeTrail": "سجل للحصول على تجربة مجانية لـ {{name}}، لا حاجة لبطاقة ائتمان",
198
+ "plans.image.count": "حوالي {{number}} صورة",
198
199
  "plans.includes": "تشمل المزايا:",
199
200
  "plans.includesExtra": "جميع مزايا {{name}}، بالإضافة إلى:",
200
201
  "plans.knowledgeBase.desc": "استخدم الملفات وقاعدة المعرفة في المحادثات",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "Съхранение на файлове, изображения и други данни",
196
196
  "plans.free": "Безплатен",
197
197
  "plans.freeTrail": "Регистрирай се, за да получиш безплатен пробен период на {{name}}, без нужда от кредитна карта",
198
+ "plans.image.count": "Приблизително {{number}} изображения",
198
199
  "plans.includes": "Включва следните предимства:",
199
200
  "plans.includesExtra": "Всички предимства на {{name}}, плюс:",
200
201
  "plans.knowledgeBase.desc": "Използвай файлове и база знания в разговорите",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "Dateispeicher für Dateien, Bilder und andere Daten",
196
196
  "plans.free": "Kostenlos",
197
197
  "plans.freeTrail": "Registrieren Sie sich für eine kostenlose Testversion von {{name}}, keine Kreditkarte erforderlich",
198
+ "plans.image.count": "Ungefähr {{number}} Bilder",
198
199
  "plans.includes": "Enthaltene Vorteile:",
199
200
  "plans.includesExtra": "Alle Vorteile von {{name}}, plus:",
200
201
  "plans.knowledgeBase.desc": "Verwenden Sie Dateien und Wissensdatenbank in Gesprächen",
@@ -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.",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "File storage for storing files, images, and other data",
196
196
  "plans.free": "Free",
197
197
  "plans.freeTrail": "Register to get free trial of {{name}}, no credit card required",
198
+ "plans.image.count": "Approximately {{number}} images",
198
199
  "plans.includes": "Benefits include:",
199
200
  "plans.includesExtra": "All benefits in {{name}}, plus:",
200
201
  "plans.knowledgeBase.desc": "Use files and knowledge base in conversations",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "Almacenamiento para archivos, imágenes y otros datos",
196
196
  "plans.free": "Gratis",
197
197
  "plans.freeTrail": "Regístrate para obtener una prueba gratuita de {{name}}, sin necesidad de tarjeta de crédito",
198
+ "plans.image.count": "Aproximadamente {{number}} imágenes",
198
199
  "plans.includes": "Beneficios incluidos:",
199
200
  "plans.includesExtra": "Todos los beneficios de {{name}}, más:",
200
201
  "plans.knowledgeBase.desc": "Usa archivos y base de conocimientos en las conversaciones",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "ذخیره‌سازی فایل برای نگهداری فایل‌ها، تصاویر و سایر داده‌ها",
196
196
  "plans.free": "رایگان",
197
197
  "plans.freeTrail": "با ثبت‌نام، آزمایش رایگان {{name}} را دریافت کنید، بدون نیاز به کارت اعتباری",
198
+ "plans.image.count": "حدوداً {{number}} تصویر",
198
199
  "plans.includes": "مزایا شامل:",
199
200
  "plans.includesExtra": "همه مزایای {{name}}، به‌علاوه:",
200
201
  "plans.knowledgeBase.desc": "استفاده از فایل‌ها و پایگاه دانش در گفتگوها",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "Stockage de fichiers, images et autres données",
196
196
  "plans.free": "Gratuit",
197
197
  "plans.freeTrail": "Inscrivez-vous pour un essai gratuit de {{name}}, sans carte bancaire",
198
+ "plans.image.count": "Environ {{number}} images",
198
199
  "plans.includes": "Avantages inclus :",
199
200
  "plans.includesExtra": "Tous les avantages de {{name}}, plus :",
200
201
  "plans.knowledgeBase.desc": "Utilisez des fichiers et bases de connaissances dans les conversations",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "Archiviazione per file, immagini e altri dati",
196
196
  "plans.free": "Gratuito",
197
197
  "plans.freeTrail": "Registrati per una prova gratuita di {{name}}, senza carta di credito",
198
+ "plans.image.count": "Circa {{number}} immagini",
198
199
  "plans.includes": "I vantaggi includono:",
199
200
  "plans.includesExtra": "Tutti i vantaggi di {{name}}, più:",
200
201
  "plans.knowledgeBase.desc": "Usa file e base di conoscenza nelle conversazioni",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "ファイル、画像、その他データの保存用ストレージ",
196
196
  "plans.free": "無料",
197
197
  "plans.freeTrail": "登録で{{name}}の無料トライアルを利用可能。クレジットカード不要",
198
+ "plans.image.count": "約{{number}}枚の画像",
198
199
  "plans.includes": "主な特典:",
199
200
  "plans.includesExtra": "{{name}}のすべての特典に加えて:",
200
201
  "plans.knowledgeBase.desc": "会話でファイルやナレッジベースを使用可能",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "파일, 이미지 및 기타 데이터 저장용 공간",
196
196
  "plans.free": "무료",
197
197
  "plans.freeTrail": "{{name}} 무료 체험 등록, 신용카드 불필요",
198
+ "plans.image.count": "약 {{number}}개의 이미지",
198
199
  "plans.includes": "포함 혜택:",
199
200
  "plans.includesExtra": "{{name}}의 모든 혜택 포함, 추가로:",
200
201
  "plans.knowledgeBase.desc": "대화 중 파일 및 지식베이스 활용",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "Opslag voor bestanden, afbeeldingen en andere gegevens",
196
196
  "plans.free": "Gratis",
197
197
  "plans.freeTrail": "Registreer voor een gratis proefperiode van {{name}}, geen creditcard nodig",
198
+ "plans.image.count": "Ongeveer {{number}} afbeeldingen",
198
199
  "plans.includes": "Voordelen zijn onder andere:",
199
200
  "plans.includesExtra": "Alle voordelen van {{name}}, plus:",
200
201
  "plans.knowledgeBase.desc": "Gebruik bestanden en kennisbank in gesprekken",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "Przechowywanie plików, obrazów i innych danych",
196
196
  "plans.free": "Darmowy",
197
197
  "plans.freeTrail": "Zarejestruj się, aby otrzymać darmowy okres próbny {{name}}, bez potrzeby karty kredytowej",
198
+ "plans.image.count": "Około {{number}} obrazów",
198
199
  "plans.includes": "Korzyści obejmują:",
199
200
  "plans.includesExtra": "Wszystkie korzyści z {{name}}, plus:",
200
201
  "plans.knowledgeBase.desc": "Używaj plików i bazy wiedzy w rozmowach",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "Armazenamento para arquivos, imagens e outros dados",
196
196
  "plans.free": "Gratuito",
197
197
  "plans.freeTrail": "Cadastre-se para testar gratuitamente o {{name}}, sem necessidade de cartão de crédito",
198
+ "plans.image.count": "Aproximadamente {{number}} imagens",
198
199
  "plans.includes": "Benefícios incluem:",
199
200
  "plans.includesExtra": "Todos os benefícios do {{name}}, mais:",
200
201
  "plans.knowledgeBase.desc": "Use arquivos e base de conhecimento nas conversas",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "Хранение файлов, изображений и других данных",
196
196
  "plans.free": "Бесплатно",
197
197
  "plans.freeTrail": "Зарегистрируйтесь и получите бесплатный пробный доступ к {{name}}, без необходимости вводить карту",
198
+ "plans.image.count": "Примерно {{number}} изображений",
198
199
  "plans.includes": "Включает в себя:",
199
200
  "plans.includesExtra": "Все преимущества {{name}}, а также:",
200
201
  "plans.knowledgeBase.desc": "Используйте файлы и базы знаний в диалогах",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "Dosya, görsel ve diğer verileri depolamak için dosya depolama",
196
196
  "plans.free": "Ücretsiz",
197
197
  "plans.freeTrail": "{{name}} için ücretsiz deneme kaydı, kredi kartı gerekmez",
198
+ "plans.image.count": "Yaklaşık {{number}} görsel",
198
199
  "plans.includes": "Avantajlar şunları içerir:",
199
200
  "plans.includesExtra": "{{name}} planındaki tüm avantajlara ek olarak:",
200
201
  "plans.knowledgeBase.desc": "Sohbetlerde dosya ve bilgi tabanı kullanın",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "Lưu trữ tệp, hình ảnh và dữ liệu khác",
196
196
  "plans.free": "Miễn phí",
197
197
  "plans.freeTrail": "Đăng ký để dùng thử miễn phí {{name}}, không cần thẻ tín dụng",
198
+ "plans.image.count": "Khoảng {{number}} hình ảnh",
198
199
  "plans.includes": "Bao gồm các lợi ích:",
199
200
  "plans.includesExtra": "Tất cả lợi ích trong {{name}}, cộng thêm:",
200
201
  "plans.knowledgeBase.desc": "Sử dụng tệp và cơ sở tri thức trong hội thoại",
@@ -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": "值越大,用词越丰富多样;值越低,用词更朴实简单",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "用于存储文件、图片等数据的空间",
196
196
  "plans.free": "免费",
197
197
  "plans.freeTrail": "注册即可免费试用 {{name}},无需信用卡",
198
+ "plans.image.count": "约 {{number}} 张图",
198
199
  "plans.includes": "包含以下权益:",
199
200
  "plans.includesExtra": "包含 {{name}} 的所有权益,另加:",
200
201
  "plans.knowledgeBase.desc": "在对话中使用文件和知识库",
@@ -195,6 +195,7 @@
195
195
  "plans.fileStorage.tooltip": "用於儲存檔案、圖片及其他資料",
196
196
  "plans.free": "免費",
197
197
  "plans.freeTrail": "註冊即可免費試用 {{name}},無需信用卡",
198
+ "plans.image.count": "約有 {{number}} 張圖片",
198
199
  "plans.includes": "包含以下內容:",
199
200
  "plans.includesExtra": "包含 {{name}} 所有功能,並額外提供:",
200
201
  "plans.knowledgeBase.desc": "可於對話中使用檔案與知識庫",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.1",
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':
@@ -220,6 +220,7 @@ export default {
220
220
  'plans.fileStorage.tooltip': 'File storage for storing files, images, and other data',
221
221
  'plans.free': 'Free',
222
222
  'plans.freeTrail': 'Register to get free trial of {{name}}, no credit card required',
223
+ 'plans.image.count': 'Approximately {{number}} images',
223
224
  'plans.includes': 'Benefits include:',
224
225
  'plans.includesExtra': 'All benefits in {{name}}, plus:',
225
226
  'plans.knowledgeBase.desc': 'Use files and knowledge base in conversations',
@@ -417,11 +417,9 @@ export const topicRouter = router({
417
417
  const agentId = topicAgentIdMap.get(topic.id);
418
418
  const agentInfo = agentId ? agentInfoMap.get(agentId) : null;
419
419
 
420
- // Clean agent info - if avatar/title are all null, return null
421
- const cleanedAgent = agentInfo ? cleanObject(agentInfo) : null;
422
- // Only return agent if it has meaningful display info (avatar or title)
423
- const validAgent =
424
- cleanedAgent && (cleanedAgent.avatar || cleanedAgent.title) ? cleanedAgent : null;
420
+ // Always return agent with id if agentId exists (even if avatar/title are null)
421
+ // Frontend needs agent.id to generate links
422
+ const validAgent = agentInfo ? cleanObject(agentInfo) : null;
425
423
 
426
424
  return {
427
425
  agent: validAgent,
@@ -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