@lobehub/lobehub 2.0.0-next.137 → 2.0.0-next.139
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 +50 -0
- package/CLAUDE.md +38 -0
- package/changelog/v1.json +14 -0
- package/locales/ar/modelProvider.json +2 -0
- package/locales/bg-BG/modelProvider.json +2 -0
- package/locales/de-DE/modelProvider.json +2 -0
- package/locales/en-US/modelProvider.json +2 -0
- package/locales/es-ES/modelProvider.json +2 -0
- package/locales/fa-IR/modelProvider.json +2 -0
- package/locales/fr-FR/modelProvider.json +2 -0
- package/locales/it-IT/modelProvider.json +2 -0
- package/locales/ja-JP/modelProvider.json +2 -0
- package/locales/ko-KR/modelProvider.json +2 -0
- package/locales/nl-NL/modelProvider.json +2 -0
- package/locales/pl-PL/modelProvider.json +2 -0
- package/locales/pt-BR/modelProvider.json +2 -0
- package/locales/ru-RU/modelProvider.json +2 -0
- package/locales/tr-TR/modelProvider.json +2 -0
- package/locales/vi-VN/modelProvider.json +2 -0
- package/locales/zh-CN/modelProvider.json +2 -0
- package/locales/zh-TW/modelProvider.json +2 -0
- package/package.json +1 -1
- package/packages/conversation-flow/src/transformation/BranchResolver.ts +24 -14
- package/packages/conversation-flow/src/transformation/ContextTreeBuilder.ts +6 -1
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +15 -0
- package/packages/conversation-flow/src/transformation/__tests__/BranchResolver.test.ts +66 -3
- package/packages/conversation-flow/src/transformation/__tests__/ContextTreeBuilder.test.ts +64 -0
- package/packages/conversation-flow/src/transformation/__tests__/FlatListBuilder.test.ts +47 -0
- package/packages/database/src/models/__tests__/agent.test.ts +102 -3
- package/packages/database/src/models/__tests__/document.test.ts +163 -0
- package/packages/database/src/models/__tests__/embedding.test.ts +294 -0
- package/packages/database/src/models/__tests__/oauthHandoff.test.ts +261 -0
- package/packages/database/src/models/__tests__/thread.test.ts +327 -0
- package/packages/database/src/models/__tests__/user.test.ts +372 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.139](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.138...v2.0.0-next.139)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2025-12-01**</sup>
|
|
8
|
+
|
|
9
|
+
#### 💄 Styles
|
|
10
|
+
|
|
11
|
+
- **misc**: Update i18n.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Styles
|
|
19
|
+
|
|
20
|
+
- **misc**: Update i18n, closes [#10519](https://github.com/lobehub/lobe-chat/issues/10519) ([bd9a38c](https://github.com/lobehub/lobe-chat/commit/bd9a38c))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
## [Version 2.0.0-next.138](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.137...v2.0.0-next.138)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2025-11-30**</sup>
|
|
33
|
+
|
|
34
|
+
#### 🐛 Bug Fixes
|
|
35
|
+
|
|
36
|
+
- **conversation-flow**: Support optimistic update for activeBranchIndex.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### What's fixed
|
|
44
|
+
|
|
45
|
+
- **conversation-flow**: Support optimistic update for activeBranchIndex, closes [#10517](https://github.com/lobehub/lobe-chat/issues/10517) ([9b5b234](https://github.com/lobehub/lobe-chat/commit/9b5b234))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
## [Version 2.0.0-next.137](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.136...v2.0.0-next.137)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2025-11-30**</sup>
|
package/CLAUDE.md
CHANGED
|
@@ -55,6 +55,44 @@ see @.cursor/rules/typescript.mdc
|
|
|
55
55
|
- **Dev**: Translate `locales/zh-CN/namespace.json` and `locales/en-US/namespace.json` locales file only for dev preview
|
|
56
56
|
- DON'T run `pnpm i18n`, let CI auto handle it
|
|
57
57
|
|
|
58
|
+
## Linear Issue Management
|
|
59
|
+
|
|
60
|
+
When working with Linear issues:
|
|
61
|
+
|
|
62
|
+
1. **Retrieve issue details** before starting work using `mcp__linear-server__get_issue`
|
|
63
|
+
2. **Check for sub-issues**: If the issue has sub-issues, retrieve and review ALL sub-issues using `mcp__linear-server__list_issues` with `parentId` filter before starting work
|
|
64
|
+
3. **Update issue status** when completing tasks using `mcp__linear-server__update_issue`
|
|
65
|
+
4. **MUST add completion comment** using `mcp__linear-server__create_comment`
|
|
66
|
+
|
|
67
|
+
### Completion Comment (REQUIRED)
|
|
68
|
+
|
|
69
|
+
**Every time you complete an issue, you MUST add a comment summarizing the work done.** This is critical for:
|
|
70
|
+
|
|
71
|
+
- Team visibility and knowledge sharing
|
|
72
|
+
- Code review context
|
|
73
|
+
- Future reference and debugging
|
|
74
|
+
|
|
75
|
+
### IMPORTANT: Per-Issue Completion Rule
|
|
76
|
+
|
|
77
|
+
**When working on multiple issues (e.g., parent issue with sub-issues), you MUST update status and add comment for EACH issue IMMEDIATELY after completing it.** Do NOT wait until all issues are done to update them in batch.
|
|
78
|
+
|
|
79
|
+
**Workflow for EACH individual issue:**
|
|
80
|
+
|
|
81
|
+
1. Complete the implementation for this specific issue
|
|
82
|
+
2. Run type check: `bun run type-check`
|
|
83
|
+
3. Run related tests if applicable
|
|
84
|
+
4. **IMMEDIATELY** update issue status to "Done": `mcp__linear-server__update_issue`
|
|
85
|
+
5. **IMMEDIATELY** add completion comment: `mcp__linear-server__create_comment`
|
|
86
|
+
6. Only then move on to the next issue
|
|
87
|
+
|
|
88
|
+
**❌ Wrong approach:**
|
|
89
|
+
|
|
90
|
+
- Complete Issue A → Complete Issue B → Complete Issue C → Update all statuses → Add all comments
|
|
91
|
+
|
|
92
|
+
**✅ Correct approach:**
|
|
93
|
+
|
|
94
|
+
- Complete Issue A → Update A status → Add A comment → Complete Issue B → Update B status → Add B comment → ...
|
|
95
|
+
|
|
58
96
|
## Rules Index
|
|
59
97
|
|
|
60
98
|
Some useful project rules are listed in @.cursor/rules/rules-index.mdc
|
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {
|
|
4
|
+
"improvements": [
|
|
5
|
+
"Update i18n."
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
"date": "2025-12-01",
|
|
9
|
+
"version": "2.0.0-next.139"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"children": {},
|
|
13
|
+
"date": "2025-11-30",
|
|
14
|
+
"version": "2.0.0-next.138"
|
|
15
|
+
},
|
|
2
16
|
{
|
|
3
17
|
"children": {
|
|
4
18
|
"fixes": [
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "لم يتم تفعيل مزود الخدمة المخصص",
|
|
193
194
|
"disabled": "مزود الخدمة غير مفعل",
|
|
194
195
|
"enabled": "مزود الخدمة مفعل"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "إضافة مزود خدمة مخصص",
|
|
199
200
|
"all": "الكل",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "المزود المخصص غير مفعل",
|
|
201
203
|
"disabled": "غير مفعل",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "طريقة الترتيب",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Персонализираният доставчик на услуги не е активиран",
|
|
193
194
|
"disabled": "Неактивен доставчик",
|
|
194
195
|
"enabled": "Активен доставчик"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Добавяне на персонализиран доставчик",
|
|
199
200
|
"all": "Всички",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Персонализираният не е активиран",
|
|
201
203
|
"disabled": "Неактивиран",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Сортиране",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Benutzerdefinierter Anbieter nicht aktiviert",
|
|
193
194
|
"disabled": "Dienstanbieter nicht aktiviert",
|
|
194
195
|
"enabled": "Dienstanbieter aktiviert"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Benutzerdefinierten Anbieter hinzufügen",
|
|
199
200
|
"all": "Alle",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Benutzerdefiniert nicht aktiviert",
|
|
201
203
|
"disabled": "Nicht aktiviert",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Sortieroptionen",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Custom provider not enabled",
|
|
193
194
|
"disabled": "Disabled",
|
|
194
195
|
"enabled": "Enabled"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Add Custom Provider",
|
|
199
200
|
"all": "All",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Custom not enabled",
|
|
201
203
|
"disabled": "Disabled",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Sort By",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Proveedor personalizado no habilitado",
|
|
193
194
|
"disabled": "Proveedor no habilitado",
|
|
194
195
|
"enabled": "Proveedor habilitado"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Agregar proveedor personalizado",
|
|
199
200
|
"all": "Todo",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Personalización no habilitada",
|
|
201
203
|
"disabled": "No habilitado",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Ordenar por",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "ارائهدهنده سفارشی فعال نشده است",
|
|
193
194
|
"disabled": "سرویسدهنده غیرفعال",
|
|
194
195
|
"enabled": "سرویسدهنده فعال"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "اضافه کردن ارائهدهنده سفارشی",
|
|
199
200
|
"all": "همه",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "سفارشیسازی فعال نشده است",
|
|
201
203
|
"disabled": "غیرفعال",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "نحوه مرتبسازی",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Fournisseur personnalisé non activé",
|
|
193
194
|
"disabled": "Fournisseur non activé",
|
|
194
195
|
"enabled": "Fournisseur activé"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Ajouter un fournisseur personnalisé",
|
|
199
200
|
"all": "Tout",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Personnalisation non activée",
|
|
201
203
|
"disabled": "Non activé",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Méthode de tri",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Fornitore personalizzato non abilitato",
|
|
193
194
|
"disabled": "Fornitore non attivato",
|
|
194
195
|
"enabled": "Fornitore attivato"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Aggiungi fornitore personalizzato",
|
|
199
200
|
"all": "Tutti",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Personalizzazione non abilitata",
|
|
201
203
|
"disabled": "Non attivato",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Ordina per",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "カスタムプロバイダーは有効化されていません",
|
|
193
194
|
"disabled": "サービスプロバイダーは無効です",
|
|
194
195
|
"enabled": "サービスプロバイダーは有効です"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "カスタムサービスプロバイダーを追加",
|
|
199
200
|
"all": "すべて",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "カスタムは無効です",
|
|
201
203
|
"disabled": "未使用",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "並び替え方法",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "사용자 지정 서비스 제공자가 활성화되지 않았습니다",
|
|
193
194
|
"disabled": "비활성화된 서비스 제공자",
|
|
194
195
|
"enabled": "활성화된 서비스 제공자"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "사용자 지정 서비스 제공자 추가",
|
|
199
200
|
"all": "전체",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "사용자 지정이 활성화되지 않았습니다",
|
|
201
203
|
"disabled": "비활성화됨",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "정렬 방식",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Aangepaste provider niet ingeschakeld",
|
|
193
194
|
"disabled": "Dienstverlener niet ingeschakeld",
|
|
194
195
|
"enabled": "Dienstverlener ingeschakeld"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Voeg aangepaste provider toe",
|
|
199
200
|
"all": "Alles",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Aangepaste provider niet ingeschakeld",
|
|
201
203
|
"disabled": "Niet ingeschakeld",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Sorteervolgorde",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Niestandardowy dostawca nie został włączony",
|
|
193
194
|
"disabled": "Usługa nieaktywna",
|
|
194
195
|
"enabled": "Usługa aktywna"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Dodaj niestandardowego dostawcę",
|
|
199
200
|
"all": "Wszystko",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Niestandardowy nie został włączony",
|
|
201
203
|
"disabled": "Nieaktywny",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Sposób sortowania",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Serviço personalizado não ativado",
|
|
193
194
|
"disabled": "Fornecedor não habilitado",
|
|
194
195
|
"enabled": "Fornecedor habilitado"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Adicionar Provedor Personalizado",
|
|
199
200
|
"all": "Todos",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Personalização não ativada",
|
|
201
203
|
"disabled": "Desativado",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Ordenar por",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Пользовательский поставщик не активирован",
|
|
193
194
|
"disabled": "Поставщик не активирован",
|
|
194
195
|
"enabled": "Поставщик активирован"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Добавить пользовательского провайдера",
|
|
199
200
|
"all": "Все",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Пользовательский не активирован",
|
|
201
203
|
"disabled": "Не активирован",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Сортировка",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Özel hizmet sağlayıcısı etkin değil",
|
|
193
194
|
"disabled": "Hizmet sağlayıcı devre dışı",
|
|
194
195
|
"enabled": "Hizmet sağlayıcı etkin"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Özel Hizmet Sağlayıcı Ekle",
|
|
199
200
|
"all": "Tümü",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Özel ayar etkin değil",
|
|
201
203
|
"disabled": "Devre Dışı",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Sıralama Yöntemi",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "Chưa kích hoạt nhà cung cấp tùy chỉnh",
|
|
193
194
|
"disabled": "Nhà cung cấp chưa được kích hoạt",
|
|
194
195
|
"enabled": "Nhà cung cấp đã được kích hoạt"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "Thêm nhà cung cấp tùy chỉnh",
|
|
199
200
|
"all": "Tất cả",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "Tùy chỉnh chưa được kích hoạt",
|
|
201
203
|
"disabled": "Chưa kích hoạt",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "Cách sắp xếp",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "未启用自定义服务商",
|
|
193
194
|
"disabled": "未启用服务商",
|
|
194
195
|
"enabled": "已启用服务商"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "添加自定义服务商",
|
|
199
200
|
"all": "全部",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "自定义未启用",
|
|
201
203
|
"disabled": "未启用",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "排序方式",
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
},
|
|
191
191
|
"list": {
|
|
192
192
|
"title": {
|
|
193
|
+
"custom": "未啟用自訂服務商",
|
|
193
194
|
"disabled": "未啟用服務商",
|
|
194
195
|
"enabled": "已啟用服務商"
|
|
195
196
|
}
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"addCustomProvider": "添加自定義服務商",
|
|
199
200
|
"all": "全部",
|
|
200
201
|
"list": {
|
|
202
|
+
"custom": "自訂未啟用",
|
|
201
203
|
"disabled": "未啟用",
|
|
202
204
|
"disabledActions": {
|
|
203
205
|
"sort": "排序方式",
|
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.139",
|
|
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",
|
|
@@ -11,16 +11,21 @@ import type { IdNode, Message } from '../types';
|
|
|
11
11
|
export class BranchResolver {
|
|
12
12
|
/**
|
|
13
13
|
* Get active branch ID from IdNode structure (used in contextTree building)
|
|
14
|
+
* Returns undefined for optimistic updates when the branch hasn't been created yet
|
|
14
15
|
*/
|
|
15
|
-
getActiveBranchId(message: Message, idNode: IdNode): string {
|
|
16
|
+
getActiveBranchId(message: Message, idNode: IdNode): string | undefined {
|
|
16
17
|
// Priority 1: Try to get from metadata.activeBranchIndex (index-based)
|
|
17
18
|
const activeBranchIndex = (message.metadata as any)?.activeBranchIndex;
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
activeBranchIndex
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
if (typeof activeBranchIndex === 'number' && activeBranchIndex >= 0) {
|
|
20
|
+
// If index is within bounds, return the branch at that index
|
|
21
|
+
if (activeBranchIndex < idNode.children.length) {
|
|
22
|
+
return idNode.children[activeBranchIndex].id;
|
|
23
|
+
}
|
|
24
|
+
// Optimistic update: index === children.length means branch is being created
|
|
25
|
+
if (activeBranchIndex === idNode.children.length) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
// Invalid index (> children.length), ignore and continue to other strategies
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
// Priority 2: Infer from which branch has children
|
|
@@ -36,20 +41,25 @@ export class BranchResolver {
|
|
|
36
41
|
|
|
37
42
|
/**
|
|
38
43
|
* Get active branch ID from flat list (used in flatList building)
|
|
44
|
+
* Returns undefined for optimistic updates when the branch hasn't been created yet
|
|
39
45
|
*/
|
|
40
46
|
getActiveBranchIdFromMetadata(
|
|
41
47
|
message: Message,
|
|
42
48
|
childIds: string[],
|
|
43
49
|
childrenMap: Map<string | null, string[]>,
|
|
44
|
-
): string {
|
|
50
|
+
): string | undefined {
|
|
45
51
|
// Priority 1: Try to get from metadata.activeBranchIndex (index-based)
|
|
46
52
|
const activeBranchIndex = (message.metadata as any)?.activeBranchIndex;
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
activeBranchIndex
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
if (typeof activeBranchIndex === 'number' && activeBranchIndex >= 0) {
|
|
54
|
+
// If index is within bounds, return the branch at that index
|
|
55
|
+
if (activeBranchIndex < childIds.length) {
|
|
56
|
+
return childIds[activeBranchIndex];
|
|
57
|
+
}
|
|
58
|
+
// Optimistic update: index === childIds.length means branch is being created
|
|
59
|
+
if (activeBranchIndex === childIds.length) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
// Invalid index (> childIds.length), ignore and continue to other strategies
|
|
53
63
|
}
|
|
54
64
|
|
|
55
65
|
// Priority 2: Infer from which child has descendants
|
|
@@ -185,7 +185,12 @@ export class ContextTreeBuilder {
|
|
|
185
185
|
*/
|
|
186
186
|
private createBranchNode(message: Message, idNode: IdNode): BranchNode {
|
|
187
187
|
const activeBranchId = this.branchResolver.getActiveBranchId(message, idNode);
|
|
188
|
-
|
|
188
|
+
|
|
189
|
+
// For optimistic update (activeBranchId is undefined), use children.length as the index
|
|
190
|
+
// This indicates the branch is being created but doesn't exist yet
|
|
191
|
+
const activeBranchIndex = activeBranchId
|
|
192
|
+
? idNode.children.findIndex((child) => child.id === activeBranchId)
|
|
193
|
+
: idNode.children.length;
|
|
189
194
|
|
|
190
195
|
// Each branch is a tree starting from that child
|
|
191
196
|
const branches = idNode.children.map((child) => {
|
|
@@ -165,6 +165,15 @@ export class FlatListBuilder {
|
|
|
165
165
|
childMessages,
|
|
166
166
|
this.childrenMap,
|
|
167
167
|
);
|
|
168
|
+
|
|
169
|
+
// Optimistic update: activeBranchId is undefined when branch is being created
|
|
170
|
+
// In this case, just add user message without branch info and continue
|
|
171
|
+
if (!activeBranchId) {
|
|
172
|
+
flatList.push(message);
|
|
173
|
+
processedIds.add(message.id);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
168
177
|
const activeBranchIndex = childMessages.indexOf(activeBranchId);
|
|
169
178
|
const userWithBranches = this.createUserMessageWithBranches(
|
|
170
179
|
message,
|
|
@@ -248,6 +257,12 @@ export class FlatListBuilder {
|
|
|
248
257
|
flatList.push(message);
|
|
249
258
|
processedIds.add(message.id);
|
|
250
259
|
|
|
260
|
+
// Optimistic update: activeBranchId is undefined when branch is being created
|
|
261
|
+
// In this case, just add assistant message and continue (no active branch yet)
|
|
262
|
+
if (!activeBranchId) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
|
|
251
266
|
// Continue with active branch and process its message
|
|
252
267
|
const activeBranchMsg = this.messageMap.get(activeBranchId);
|
|
253
268
|
if (activeBranchMsg) {
|
|
@@ -71,13 +71,13 @@ describe('BranchResolver', () => {
|
|
|
71
71
|
expect(resolver.getActiveBranchId(message, idNode)).toBe('msg-2');
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
-
it('should
|
|
74
|
+
it('should return undefined for optimistic update (activeBranchIndex === children.length)', () => {
|
|
75
75
|
const message: Message = {
|
|
76
76
|
content: 'test',
|
|
77
77
|
createdAt: 0,
|
|
78
78
|
id: 'msg-1',
|
|
79
79
|
meta: {},
|
|
80
|
-
metadata: { activeBranchIndex:
|
|
80
|
+
metadata: { activeBranchIndex: 2 }, // index = children.length (optimistic update)
|
|
81
81
|
role: 'user',
|
|
82
82
|
updatedAt: 0,
|
|
83
83
|
};
|
|
@@ -90,7 +90,31 @@ describe('BranchResolver', () => {
|
|
|
90
90
|
id: 'msg-1',
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
-
//
|
|
93
|
+
// When activeBranchIndex === children.length, it's an optimistic update
|
|
94
|
+
// The branch hasn't been created yet, so return undefined
|
|
95
|
+
expect(resolver.getActiveBranchId(message, idNode)).toBeUndefined();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should ignore activeBranchIndex when it exceeds optimistic update range', () => {
|
|
99
|
+
const message: Message = {
|
|
100
|
+
content: 'test',
|
|
101
|
+
createdAt: 0,
|
|
102
|
+
id: 'msg-1',
|
|
103
|
+
meta: {},
|
|
104
|
+
metadata: { activeBranchIndex: 5 }, // > children.length (invalid)
|
|
105
|
+
role: 'user',
|
|
106
|
+
updatedAt: 0,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const idNode: IdNode = {
|
|
110
|
+
children: [
|
|
111
|
+
{ children: [], id: 'msg-2' },
|
|
112
|
+
{ children: [], id: 'msg-3' },
|
|
113
|
+
],
|
|
114
|
+
id: 'msg-1',
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// activeBranchIndex > children.length should be ignored, fallback to default
|
|
94
118
|
expect(resolver.getActiveBranchId(message, idNode)).toBe('msg-2');
|
|
95
119
|
});
|
|
96
120
|
});
|
|
@@ -147,5 +171,44 @@ describe('BranchResolver', () => {
|
|
|
147
171
|
|
|
148
172
|
expect(resolver.getActiveBranchIdFromMetadata(message, childIds, childrenMap)).toBe('msg-2');
|
|
149
173
|
});
|
|
174
|
+
|
|
175
|
+
it('should return undefined for optimistic update (activeBranchIndex === childIds.length)', () => {
|
|
176
|
+
const message: Message = {
|
|
177
|
+
content: 'test',
|
|
178
|
+
createdAt: 0,
|
|
179
|
+
id: 'msg-1',
|
|
180
|
+
meta: {},
|
|
181
|
+
metadata: { activeBranchIndex: 2 }, // index = childIds.length (optimistic update)
|
|
182
|
+
role: 'user',
|
|
183
|
+
updatedAt: 0,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const childIds = ['msg-2', 'msg-3'];
|
|
187
|
+
const childrenMap = new Map<string | null, string[]>();
|
|
188
|
+
|
|
189
|
+
// When activeBranchIndex === childIds.length, it's an optimistic update
|
|
190
|
+
// The branch hasn't been created yet, so return undefined
|
|
191
|
+
expect(
|
|
192
|
+
resolver.getActiveBranchIdFromMetadata(message, childIds, childrenMap),
|
|
193
|
+
).toBeUndefined();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should ignore activeBranchIndex when it exceeds optimistic update range', () => {
|
|
197
|
+
const message: Message = {
|
|
198
|
+
content: 'test',
|
|
199
|
+
createdAt: 0,
|
|
200
|
+
id: 'msg-1',
|
|
201
|
+
meta: {},
|
|
202
|
+
metadata: { activeBranchIndex: 5 }, // > childIds.length (invalid)
|
|
203
|
+
role: 'user',
|
|
204
|
+
updatedAt: 0,
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const childIds = ['msg-2', 'msg-3'];
|
|
208
|
+
const childrenMap = new Map<string | null, string[]>();
|
|
209
|
+
|
|
210
|
+
// activeBranchIndex > childIds.length should be ignored, fallback to default
|
|
211
|
+
expect(resolver.getActiveBranchIdFromMetadata(message, childIds, childrenMap)).toBe('msg-2');
|
|
212
|
+
});
|
|
150
213
|
});
|
|
151
214
|
});
|