Compare commits

...

9 Commits

Author SHA1 Message Date
semantic-release-bot df0886ebf3 🔖 chore(release): v1.70.0 [skip ci]
## [Version 1.70.0](https://github.com/lobehub/lobe-chat/compare/v1.69.6...v1.70.0)
<sup>Released on **2025-03-09**</sup>

####  Features

- **misc**: Support no-fc models like deepseek r1 with online search.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's improved

* **misc**: Support no-fc models like deepseek r1 with online search, closes [#6842](https://github.com/lobehub/lobe-chat/issues/6842) ([f284c25](https://github.com/lobehub/lobe-chat/commit/f284c25))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2025-03-09 18:44:41 +00:00
Arvin Xu f284c25606 feat: support no-fc models like deepseek r1 with online search (#6842)
* update crawler rule

* feat: 完成联网集成

* update i18n

* update tests

* update tests

* fix tests

* improve performance

* fix error issue

* fix signal issue and improve implement

* fix pricing in CNY

* fix tests

* filter empty providers

* fix tests

* improve search crawler env

* fix search crawler env

* fix documents
2025-03-10 02:35:52 +08:00
lobehubbot 23a26a9563 📝 docs(bot): Auto sync agents & plugin to readme 2025-03-09 14:01:53 +00:00
semantic-release-bot 8039186493 🔖 chore(release): v1.69.6 [skip ci]
### [Version&nbsp;1.69.6](https://github.com/lobehub/lobe-chat/compare/v1.69.5...v1.69.6)
<sup>Released on **2025-03-09**</sup>

#### 🐛 Bug Fixes

- **misc**: Fix context cache control and model builtin search switch.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Fix context cache control and model builtin search switch, closes [#6831](https://github.com/lobehub/lobe-chat/issues/6831) ([5c6b8ea](https://github.com/lobehub/lobe-chat/commit/5c6b8ea))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2025-03-09 14:00:43 +00:00
Arvin Xu 5c6b8eaf8a 🐛 fix: fix context cache control and model builtin search switch (#6831)
* upgrade readability

* improve openai performance

* improve model select

* upgrade pglite to 0.2.17

* fix google builtin search config

* fix tests

* fix claude max output tokens and context caching config

* fix context caching config

* update i18n

* fix tests
2025-03-09 21:52:12 +08:00
renovate[bot] dde299312e Update pnpm to v9.15.7 (#6819)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-09 21:19:05 +08:00
lobehubbot 0aa47d024c 📝 docs(bot): Auto sync agents & plugin to readme 2025-03-09 11:18:04 +00:00
semantic-release-bot b86d86782a 🔖 chore(release): v1.69.5 [skip ci]
### [Version&nbsp;1.69.5](https://github.com/lobehub/lobe-chat/compare/v1.69.4...v1.69.5)
<sup>Released on **2025-03-09**</sup>

#### 💄 Styles

- **chat**: Auto send message from URL.
- **misc**: Support openrouter claude 3.7 sonnet reasoning.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Styles

* **chat**: Auto send message from URL, closes [#6497](https://github.com/lobehub/lobe-chat/issues/6497) ([30b2639](https://github.com/lobehub/lobe-chat/commit/30b2639))
* **misc**: Support openrouter claude 3.7 sonnet reasoning, closes [#6806](https://github.com/lobehub/lobe-chat/issues/6806) ([f1ffc2c](https://github.com/lobehub/lobe-chat/commit/f1ffc2c))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2025-03-09 11:16:40 +00:00
Eridanus Sora 6006175c5d ️ perf: improve performace of refreshModelProviderList (#6672) 2025-03-09 19:07:42 +08:00
108 changed files with 1153 additions and 662 deletions
+77
View File
@@ -2,6 +2,83 @@
# Changelog
## [Version 1.70.0](https://github.com/lobehub/lobe-chat/compare/v1.69.6...v1.70.0)
<sup>Released on **2025-03-09**</sup>
#### ✨ Features
- **misc**: Support no-fc models like deepseek r1 with online search.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's improved
- **misc**: Support no-fc models like deepseek r1 with online search, closes [#6842](https://github.com/lobehub/lobe-chat/issues/6842) ([f284c25](https://github.com/lobehub/lobe-chat/commit/f284c25))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 1.69.6](https://github.com/lobehub/lobe-chat/compare/v1.69.5...v1.69.6)
<sup>Released on **2025-03-09**</sup>
#### 🐛 Bug Fixes
- **misc**: Fix context cache control and model builtin search switch.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **misc**: Fix context cache control and model builtin search switch, closes [#6831](https://github.com/lobehub/lobe-chat/issues/6831) ([5c6b8ea](https://github.com/lobehub/lobe-chat/commit/5c6b8ea))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 1.69.5](https://github.com/lobehub/lobe-chat/compare/v1.69.4...v1.69.5)
<sup>Released on **2025-03-09**</sup>
#### 💄 Styles
- **chat**: Auto send message from URL.
- **misc**: Support openrouter claude 3.7 sonnet reasoning.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### Styles
- **chat**: Auto send message from URL, closes [#6497](https://github.com/lobehub/lobe-chat/issues/6497) ([30b2639](https://github.com/lobehub/lobe-chat/commit/30b2639))
- **misc**: Support openrouter claude 3.7 sonnet reasoning, closes [#6806](https://github.com/lobehub/lobe-chat/issues/6806) ([f1ffc2c](https://github.com/lobehub/lobe-chat/commit/f1ffc2c))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 1.69.4](https://github.com/lobehub/lobe-chat/compare/v1.69.3...v1.69.4)
<sup>Released on **2025-03-09**</sup>
+14
View File
@@ -1,4 +1,18 @@
[
{
"children": {
"fixes": ["Fix context cache control and model builtin search switch."]
},
"date": "2025-03-09",
"version": "1.69.6"
},
{
"children": {
"improvements": ["Support openrouter claude 3.7 sonnet reasoning."]
},
"date": "2025-03-09",
"version": "1.69.5"
},
{
"children": {
"fixes": ["Fix mistral can not chat."]
@@ -36,7 +36,7 @@ tags:
<Image alt={'Clerk 添加 Webhooks 端点'} src={'https://github.com/lobehub/lobe-chat/assets/28616219/f50f47fb-5e8e-4930-bf4e-8cf6f5b8afb9'} />
在 endppint 中填写你的项目 URL,如 `https://your-project.com/api/webhooks/clerk`。然后在订阅事件(Subscribe to events)中,勾选 user 的三个事件(`user.created` 、`user.deleted`、`user.updated`),然后点击创建。
在 endpoint 中填写你的项目 URL,如 `https://your-project.com/api/webhooks/clerk`。然后在订阅事件(Subscribe to events)中,勾选 user 的三个事件(`user.created` 、`user.deleted`、`user.updated`),然后点击创建。
<Callout type={'warning'}>URL 的`https://`不可缺失,须保持 URL 的完整性</Callout>
@@ -140,7 +140,7 @@ tags:
<Image alt={'Clerk 添加 Webhooks 端点'} src={'https://github.com/lobehub/lobe-chat/assets/28616219/f50f47fb-5e8e-4930-bf4e-8cf6f5b8afb9'} />
在 endppint 中填写你的 Vercel 项目的 URL,如 `https://your-project.vercel.app/api/webhooks/clerk`。然后在订阅事件(Subscribe to events)中,勾选 user 的三个事件(`user.created` 、`user.deleted`、`user.updated`),然后点击创建。
在 endpoint 中填写你的 Vercel 项目的 URL,如 `https://your-project.vercel.app/api/webhooks/clerk`。然后在订阅事件(Subscribe to events)中,勾选 user 的三个事件(`user.created` 、`user.deleted`、`user.updated`),然后点击创建。
<Callout type={'warning'}>URL 的`https://`不可缺失,须保持 URL 的完整性</Callout>
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "توقف",
"warp": "تغيير السطر"
},
"intentUnderstanding": {
"title": "جارٍ تحليل وفهم نواياك..."
},
"knowledgeBase": {
"all": "جميع المحتويات",
"allFiles": "جميع الملفات",
@@ -144,7 +147,6 @@
"desc": "تحديد ما إذا كان من الضروري البحث بناءً على محتوى المحادثة",
"title": "الاتصال الذكي"
},
"disable": "النموذج الحالي لا يدعم استدعاء الوظائف، لذا لا يمكن استخدام وظيفة الاتصال الذكي",
"off": {
"desc": "استخدام المعرفة الأساسية للنموذج فقط، دون إجراء بحث عبر الإنترنت",
"title": "إيقاف الاتصال"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "استخدام محرك البحث المدمج في النموذج"
},
"searchModel": {
"desc": "النموذج الحالي لا يدعم استدعاء الدوال، لذا يجب استخدام نموذج يدعم استدعاء الدوال للبحث عبر الإنترنت",
"title": "نموذج البحث المساعد"
},
"title": "بحث عبر الإنترنت"
},
"searchAgentPlaceholder": "مساعد البحث...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "لا توجد نماذج ممكن تمكينها، يرجى الانتقال إلى الإعدادات لتمكينها",
"emptyProvider": "لا توجد مزودات مفعلة، يرجى الذهاب إلى الإعدادات لتفعيلها",
"goToSettings": "اذهب إلى الإعدادات",
"provider": "مزود"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet يقدم قدرات تتجاوز Opus وسرعة أكبر من Sonnet، مع الحفاظ على نفس السعر. يتميز Sonnet بمهارات خاصة في البرمجة وعلوم البيانات ومعالجة الصور والمهام الوكيلة."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet هو أكثر النماذج ذكاءً من Anthropic حتى الآن، وهو أيضًا أول نموذج مختلط للتفكير في السوق. يمكن لـ Claude 3.7 Sonnet إنتاج استجابات شبه فورية أو تفكير تدريجي ممتد، حيث يمكن للمستخدمين رؤية هذه العمليات بوضوح. يتميز Sonnet بشكل خاص في البرمجة، وعلوم البيانات، ومعالجة الصور، والمهام الوكيلة."
},
"aya": {
"description": "Aya 23 هو نموذج متعدد اللغات أطلقته Cohere، يدعم 23 لغة، مما يسهل التطبيقات اللغوية المتنوعة."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Спри",
"warp": "Нов ред"
},
"intentUnderstanding": {
"title": "Анализирам и разбирам вашето намерение..."
},
"knowledgeBase": {
"all": "Всички съдържания",
"allFiles": "Всички файлове",
@@ -144,7 +147,6 @@
"desc": "Интелигентно определяне на необходимостта от търсене въз основа на съдържанието на разговора",
"title": "Интелигентно свързване"
},
"disable": "Текущият модел не поддържа извикване на функции, затова не може да се използва интелигентно свързване",
"off": {
"desc": "Използва само основните знания на модела, без интернет търсене",
"title": "Изключване на свързването"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Използване на вградената търсачка на модела"
},
"searchModel": {
"desc": "Текущият модел не поддържа извикване на функции, затова е необходимо да се комбинира с модел, който поддържа извикване на функции, за да се извърши търсене в интернет",
"title": "Модел за търсене на помощ"
},
"title": "Търсене в интернет"
},
"searchAgentPlaceholder": "Търсач на помощ...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "Няма активирани модели, моля, посетете настройките и ги активирайте",
"emptyProvider": "Няма активиран доставчик на услуги, моля, отидете в настройките, за да го активирате",
"goToSettings": "Отидете в настройките",
"provider": "Доставчик"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet предлага способности, надхвърлящи Opus, и по-бърза скорост в сравнение с Sonnet, като същевременно запазва същата цена. Sonnet е особено силен в програмирането, науката за данни, визуалната обработка и агентските задачи."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet е най-интелигентният модел на Anthropic до момента и е първият хибриден модел за разсъждение на пазара. Claude 3.7 Sonnet може да генерира почти мигновени отговори или удължено стъпково мислене, което позволява на потребителите ясно да видят тези процеси. Sonnet е особено добър в програмирането, науката за данни, визуалната обработка и агентските задачи."
},
"aya": {
"description": "Aya 23 е многозначен модел, представен от Cohere, поддържащ 23 езика, предоставяйки удобство за многоезични приложения."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Stoppen",
"warp": "Zeilenumbruch"
},
"intentUnderstanding": {
"title": "Analysiere und verstehe Ihre Absicht..."
},
"knowledgeBase": {
"all": "Alle Inhalte",
"allFiles": "Alle Dateien",
@@ -144,7 +147,6 @@
"desc": "Intelligente Beurteilung, ob eine Suche basierend auf dem Gesprächsinhalt erforderlich ist",
"title": "Intelligente Vernetzung"
},
"disable": "Das aktuelle Modell unterstützt keine Funktionsaufrufe, daher kann die intelligente Vernetzungsfunktion nicht verwendet werden",
"off": {
"desc": "Verwendet nur das Grundwissen des Modells, ohne Netzsuche",
"title": "Vernetzung deaktivieren"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Verwenden Sie die integrierte Suchmaschine des Modells"
},
"searchModel": {
"desc": "Das aktuelle Modell unterstützt keine Funktionsaufrufe, daher muss es mit einem Modell kombiniert werden, das Funktionsaufrufe unterstützt, um online zu suchen",
"title": "Suchunterstützungsmodell"
},
"title": "Netzwerksuche"
},
"searchAgentPlaceholder": "Suchassistent...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "Kein aktiviertes Modell. Bitte gehen Sie zu den Einstellungen, um es zu aktivieren.",
"emptyProvider": "Es sind keine aktiven Anbieter vorhanden, bitte gehen Sie zu den Einstellungen, um sie zu aktivieren",
"goToSettings": "Zu den Einstellungen gehen",
"provider": "Anbieter"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet bietet Fähigkeiten, die über Opus hinausgehen, und eine schnellere Geschwindigkeit als Sonnet, während es den gleichen Preis wie Sonnet beibehält. Sonnet ist besonders gut in Programmierung, Datenwissenschaft, visueller Verarbeitung und Agentenaufgaben."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet ist das intelligenteste Modell von Anthropic bis heute und das erste hybride Inferenzmodell auf dem Markt. Claude 3.7 Sonnet kann nahezu sofortige Antworten oder verlängerte, schrittweise Überlegungen erzeugen, wobei die Benutzer diesen Prozess klar nachvollziehen können. Sonnet ist besonders gut in den Bereichen Programmierung, Datenwissenschaft, visuelle Verarbeitung und Agentenaufgaben."
},
"aya": {
"description": "Aya 23 ist ein mehrsprachiges Modell von Cohere, das 23 Sprachen unterstützt und die Anwendung in einer Vielzahl von Sprachen erleichtert."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Stop",
"warp": "New Line"
},
"intentUnderstanding": {
"title": "Analyzing and understanding your intent..."
},
"knowledgeBase": {
"all": "All Content",
"allFiles": "All Files",
@@ -144,7 +147,6 @@
"desc": "Intelligently determine whether a search is needed based on the conversation content",
"title": "Smart Online Search"
},
"disable": "The current model does not support function calls, so the smart online search feature is unavailable",
"off": {
"desc": "Use only the model's basic knowledge without performing a web search",
"title": "Disable Online Search"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Use the model's built-in search engine"
},
"searchModel": {
"desc": "The current model does not support function calls, so it needs to be paired with a model that does support function calls for online searching.",
"title": "Search Assistant Model"
},
"title": "Online Search"
},
"searchAgentPlaceholder": "Search assistants...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "No enabled model. Please go to settings to enable.",
"emptyProvider": "No enabled providers. Please go to settings to enable one.",
"goToSettings": "Go to settings",
"provider": "Provider"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet offers capabilities that surpass Opus and faster speeds than Sonnet, while maintaining the same pricing as Sonnet. Sonnet excels particularly in programming, data science, visual processing, and agent tasks."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet is Anthropic's most advanced model to date and the first hybrid reasoning model on the market. Claude 3.7 Sonnet can generate near-instant responses or extended step-by-step reasoning, allowing users to clearly observe these processes. Sonnet excels particularly in programming, data science, visual processing, and agent tasks."
},
"aya": {
"description": "Aya 23 is a multilingual model launched by Cohere, supporting 23 languages, facilitating diverse language applications."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Detener",
"warp": "Salto de línea"
},
"intentUnderstanding": {
"title": "Analizando y comprendiendo su intención..."
},
"knowledgeBase": {
"all": "Todo el contenido",
"allFiles": "Todos los archivos",
@@ -144,7 +147,6 @@
"desc": "Determina inteligentemente si se necesita buscar según el contenido de la conversación",
"title": "Conexión inteligente"
},
"disable": "El modelo actual no admite llamadas a funciones, por lo que no se puede utilizar la función de conexión inteligente",
"off": {
"desc": "Utiliza solo el conocimiento básico del modelo, sin realizar búsquedas en línea",
"title": "Desactivar conexión"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Utilizar el motor de búsqueda integrado del modelo"
},
"searchModel": {
"desc": "El modelo actual no admite llamadas a funciones, por lo que se necesita combinarlo con un modelo que admita llamadas a funciones para realizar búsquedas en línea",
"title": "Modelo de búsqueda auxiliar"
},
"title": "Búsqueda en línea"
},
"searchAgentPlaceholder": "Asistente de búsqueda...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "No hay modelos habilitados. Vaya a la configuración para habilitarlos.",
"emptyProvider": "No hay proveedores habilitados, por favor ve a la configuración para activarlos",
"goToSettings": "Ir a la configuración",
"provider": "Proveedor"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet ofrece capacidades que superan a Opus y una velocidad más rápida que Sonnet, manteniendo el mismo precio que Sonnet. Sonnet es especialmente hábil en programación, ciencia de datos, procesamiento visual y tareas de agente."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet es el modelo más inteligente de Anthropic hasta la fecha y el primer modelo de razonamiento híbrido en el mercado. Claude 3.7 Sonnet puede generar respuestas casi instantáneas o un pensamiento prolongado y gradual, permitiendo a los usuarios observar claramente estos procesos. Sonnet es especialmente hábil en programación, ciencia de datos, procesamiento visual y tareas de agente."
},
"aya": {
"description": "Aya 23 es un modelo multilingüe lanzado por Cohere, que admite 23 idiomas, facilitando aplicaciones de lenguaje diversas."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "توقف",
"warp": "خط جدید"
},
"intentUnderstanding": {
"title": "در حال تحلیل و درک نیت شما..."
},
"knowledgeBase": {
"all": "همه محتوا",
"allFiles": "همه فایل‌ها",
@@ -144,7 +147,6 @@
"desc": "به طور هوشمندانه بر اساس محتوای گفتگو تشخیص می‌دهد که آیا نیاز به جستجو است",
"title": "اتصال هوشمند"
},
"disable": "مدل فعلی از فراخوانی توابع پشتیبانی نمی‌کند، بنابراین نمی‌توان از ویژگی اتصال هوشمند استفاده کرد",
"off": {
"desc": "فقط از دانش پایه مدل استفاده می‌کند و جستجوی اینترنتی انجام نمی‌دهد",
"title": "قطع اتصال"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "استفاده از موتور جستجوی داخلی مدل"
},
"searchModel": {
"desc": "مدل فعلی از فراخوانی توابع پشتیبانی نمی‌کند، بنابراین نیاز است که با مدلی که از فراخوانی توابع پشتیبانی می‌کند، برای جستجوی آنلاین ترکیب شود",
"title": "مدل جستجوی کمکی"
},
"title": "جستجوی متصل"
},
"searchAgentPlaceholder": "جستجوی دستیار...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "هیچ مدلی فعال نیست، لطفاً به تنظیمات بروید و آن را فعال کنید",
"emptyProvider": "هیچ ارائه‌دهنده‌ای فعال نیست، لطفاً به تنظیمات بروید و آن را فعال کنید",
"goToSettings": "به تنظیمات بروید",
"provider": "ارائه‌دهنده"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet توانایی‌هایی فراتر از Opus ارائه می‌دهد و سرعتی سریع‌تر از Sonnet دارد، در حالی که قیمت آن با Sonnet یکسان است. Sonnet به‌ویژه در برنامه‌نویسی، علم داده، پردازش بصری و وظایف نمایندگی مهارت دارد."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet هو هوش مصنوعی پیشرفته‌ترین مدل Anthropic است و همچنین اولین مدل استدلال ترکیبی در بازار به شمار می‌رود. Claude 3.7 Sonnet می‌تواند پاسخ‌های تقریباً آنی یا تفکر تدریجی و طولانی‌تری تولید کند که کاربران می‌توانند این فرآیندها را به وضوح مشاهده کنند. Sonnet به‌ویژه در برنامه‌نویسی، علم داده، پردازش بصری و وظایف نمایندگی مهارت دارد."
},
"aya": {
"description": "Aya 23 یک مدل چندزبانه است که توسط Cohere ارائه شده و از 23 زبان پشتیبانی می‌کند و برای برنامه‌های چندزبانه تسهیلات فراهم می‌آورد."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Arrêter",
"warp": "Saut de ligne"
},
"intentUnderstanding": {
"title": "Analyse et comprend votre intention..."
},
"knowledgeBase": {
"all": "Tout le contenu",
"allFiles": "Tous les fichiers",
@@ -144,7 +147,6 @@
"desc": "Détermine intelligemment si une recherche est nécessaire en fonction du contenu de la conversation",
"title": "Connexion intelligente"
},
"disable": "Le modèle actuel ne prend pas en charge l'appel de fonctions, donc la fonctionnalité de connexion intelligente est indisponible",
"off": {
"desc": "Utilise uniquement les connaissances de base du modèle, sans recherche en ligne",
"title": "Déconnexion"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Utiliser le moteur de recherche intégré du modèle"
},
"searchModel": {
"desc": "Le modèle actuel ne prend pas en charge les appels de fonction, il doit donc être associé à un modèle prenant en charge les appels de fonction pour effectuer une recherche en ligne",
"title": "Modèle d'assistance à la recherche"
},
"title": "Recherche en ligne"
},
"searchAgentPlaceholder": "Assistant de recherche...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "Aucun modèle activé. Veuillez vous rendre dans les paramètres pour l'activer.",
"emptyProvider": "Aucun fournisseur activé, veuillez aller dans les paramètres pour l'activer",
"goToSettings": "Aller aux paramètres",
"provider": "Fournisseur"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet offre des capacités supérieures à celles d'Opus et une vitesse plus rapide que Sonnet, tout en maintenant le même prix que Sonnet. Sonnet excelle particulièrement dans la programmation, la science des données, le traitement visuel et les tâches d'agent."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet est le modèle le plus intelligent d'Anthropic à ce jour, et le premier modèle de raisonnement hybride sur le marché. Claude 3.7 Sonnet peut produire des réponses quasi instantanées ou un raisonnement prolongé, permettant aux utilisateurs de voir clairement ces processus. Sonnet excelle particulièrement dans la programmation, la science des données, le traitement visuel et les tâches d'agent."
},
"aya": {
"description": "Aya 23 est un modèle multilingue lancé par Cohere, prenant en charge 23 langues, facilitant les applications linguistiques diversifiées."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Ferma",
"warp": "A capo"
},
"intentUnderstanding": {
"title": "Analizzando e comprendendo le tue intenzioni..."
},
"knowledgeBase": {
"all": "Tutti i contenuti",
"allFiles": "Tutti i file",
@@ -144,7 +147,6 @@
"desc": "Determina intelligentemente se è necessario cercare in base al contenuto della conversazione",
"title": "Collegamento intelligente"
},
"disable": "Il modello attuale non supporta le chiamate di funzione, quindi non è possibile utilizzare la funzionalità di collegamento intelligente",
"off": {
"desc": "Utilizza solo la conoscenza di base del modello, senza effettuare ricerche online",
"title": "Disattiva collegamento"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Utilizza il motore di ricerca integrato del modello"
},
"searchModel": {
"desc": "Il modello attuale non supporta le chiamate di funzione, quindi è necessario utilizzarlo insieme a un modello che supporti le chiamate di funzione per cercare online",
"title": "Modello di ricerca assistita"
},
"title": "Ricerca online"
},
"searchAgentPlaceholder": "Assistente di ricerca...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "Nessun modello attivo. Vai alle impostazioni per attivarne uno.",
"emptyProvider": "Nessun fornitore attivo, vai alle impostazioni per attivarlo",
"goToSettings": "Vai alle impostazioni",
"provider": "Provider"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet offre capacità superiori rispetto a Opus e una velocità maggiore rispetto a Sonnet, mantenendo lo stesso prezzo di Sonnet. Sonnet è particolarmente abile in programmazione, scienza dei dati, elaborazione visiva e compiti di agenzia."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet è il modello più intelligente di Anthropic fino ad oggi ed è il primo modello di ragionamento ibrido sul mercato. Claude 3.7 Sonnet può generare risposte quasi istantanee o pensieri prolungati e graduali, consentendo agli utenti di vedere chiaramente questi processi. Sonnet è particolarmente abile nella programmazione, nella scienza dei dati, nell'elaborazione visiva e nei compiti di agenzia."
},
"aya": {
"description": "Aya 23 è un modello multilingue lanciato da Cohere, supporta 23 lingue, facilitando applicazioni linguistiche diversificate."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "停止",
"warp": "改行"
},
"intentUnderstanding": {
"title": "あなたの意図を分析し理解しています..."
},
"knowledgeBase": {
"all": "すべてのコンテンツ",
"allFiles": "すべてのファイル",
@@ -144,7 +147,6 @@
"desc": "会話の内容に基づいて、検索が必要かどうかを自動的に判断します",
"title": "インテリジェント接続"
},
"disable": "現在のモデルは関数呼び出しをサポートしていないため、インテリジェント接続機能は使用できません",
"off": {
"desc": "モデルの基本知識のみを使用し、ネット検索は行いません",
"title": "接続をオフ"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "モデル内蔵の検索エンジンを使用"
},
"searchModel": {
"desc": "現在のモデルは関数呼び出しをサポートしていないため、関数呼び出しをサポートするモデルと組み合わせてネット検索を行う必要があります",
"title": "検索補助モデル"
},
"title": "ネット接続検索"
},
"searchAgentPlaceholder": "検索アシスタント...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "有効なモデルがありません。設定に移動して有効にしてください。",
"emptyProvider": "有効なサービスプロバイダーがありません。設定に移動して有効にしてください。",
"goToSettings": "設定に移動",
"provider": "プロバイダー"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 SonnetはOpusを超える能力を提供し、Sonnetよりも速い速度を持ちながら、Sonnetと同じ価格を維持します。Sonnetは特にプログラミング、データサイエンス、視覚処理、代理タスクに優れています。"
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnetは、Anthropicがこれまでに開発した最も知能の高いモデルであり、市場で初めての混合推論モデルです。Claude 3.7 Sonnetは、ほぼ瞬時の応答や段階的な思考を生成することができ、ユーザーはこれらのプロセスを明確に見ることができます。Sonnetは特にプログラミング、データサイエンス、視覚処理、代理タスクに優れています。"
},
"aya": {
"description": "Aya 23は、Cohereが提供する多言語モデルであり、23の言語をサポートし、多様な言語アプリケーションを便利にします。"
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "중지",
"warp": "줄바꿈"
},
"intentUnderstanding": {
"title": "귀하의 의도를 분석하고 이해하는 중입니다..."
},
"knowledgeBase": {
"all": "모든 내용",
"allFiles": "모든 파일",
@@ -144,7 +147,6 @@
"desc": "대화 내용을 기반으로 검색 필요성을 스마트하게 판단",
"title": "스마트 연결"
},
"disable": "현재 모델은 함수 호출을 지원하지 않으므로 스마트 연결 기능을 사용할 수 없습니다",
"off": {
"desc": "모델의 기본 지식만 사용하고 네트워크 검색을 수행하지 않음",
"title": "연결 끄기"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "모델 내장 검색 엔진 사용"
},
"searchModel": {
"desc": "현재 모델은 함수 호출을 지원하지 않으므로 함수 호출을 지원하는 모델과 함께 사용해야 인터넷 검색이 가능합니다.",
"title": "검색 보조 모델"
},
"title": "연결 검색"
},
"searchAgentPlaceholder": "검색 도우미...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "활성화된 모델이 없습니다. 설정으로 이동하여 활성화하세요",
"emptyProvider": "활성화된 서비스 제공자가 없습니다. 설정으로 가서 활성화하세요.",
"goToSettings": "설정으로 가기",
"provider": "제공자"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet은 Opus를 초월하는 능력과 Sonnet보다 더 빠른 속도를 제공하며, Sonnet과 동일한 가격을 유지합니다. Sonnet은 프로그래밍, 데이터 과학, 비주얼 처리 및 에이전트 작업에 특히 강합니다."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet은 Anthropic이 지금까지 개발한 가장 지능적인 모델로, 시장에서 최초의 혼합 추론 모델입니다. Claude 3.7 Sonnet은 거의 즉각적인 응답이나 연장된 단계적 사고를 생성할 수 있으며, 사용자는 이러한 과정을 명확하게 볼 수 있습니다. Sonnet은 프로그래밍, 데이터 과학, 시각 처리, 대리 작업에 특히 뛰어납니다."
},
"aya": {
"description": "Aya 23은 Cohere에서 출시한 다국어 모델로, 23개 언어를 지원하여 다양한 언어 응용에 편리함을 제공합니다."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Stoppen",
"warp": "Nieuwe regel"
},
"intentUnderstanding": {
"title": "Bezig met het analyseren en begrijpen van uw intentie..."
},
"knowledgeBase": {
"all": "Alle inhoud",
"allFiles": "Alle bestanden",
@@ -144,7 +147,6 @@
"desc": "Intelligente beoordeling of er gezocht moet worden op basis van de gesprekinhoud",
"title": "Slimme verbinding"
},
"disable": "Het huidige model ondersteunt geen functieaanroepen, dus de slimme verbindingsfunctie kan niet worden gebruikt",
"off": {
"desc": "Gebruik alleen de basiskennis van het model, zonder online zoekopdrachten",
"title": "Verbinding uitschakelen"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Gebruik de ingebouwde zoekmachine van het model"
},
"searchModel": {
"desc": "Het huidige model ondersteunt geen functieaanroepen, dus het moet worden gecombineerd met een model dat functieaanroepen ondersteunt om online te zoeken",
"title": "Zoekhulpmiddel model"
},
"title": "Online zoeken"
},
"searchAgentPlaceholder": "Zoekassistent...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "No enabled model, please go to settings to enable.",
"emptyProvider": "Geen ingeschakelde provider, ga naar instellingen om deze in te schakelen",
"goToSettings": "Ga naar instellingen",
"provider": "Provider"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet biedt mogelijkheden die verder gaan dan Opus en een snellere snelheid dan Sonnet, terwijl het dezelfde prijs als Sonnet behoudt. Sonnet is bijzonder goed in programmeren, datawetenschap, visuele verwerking en agenttaken."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet is het meest geavanceerde model van Anthropic tot nu toe en het eerste hybride redeneermodel op de markt. Claude 3.7 Sonnet kan bijna onmiddellijke reacties of uitgebreide stapsgewijze overpeinzingen genereren, waarbij gebruikers deze processen duidelijk kunnen volgen. Sonnet is bijzonder goed in programmeren, datawetenschap, visuele verwerking en agenttaken."
},
"aya": {
"description": "Aya 23 is een meertalig model van Cohere, ondersteunt 23 talen en biedt gemak voor diverse taaltoepassingen."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Zatrzymaj",
"warp": "Złamanie wiersza"
},
"intentUnderstanding": {
"title": "Analizuję i rozumiem Twoje intencje..."
},
"knowledgeBase": {
"all": "Wszystkie treści",
"allFiles": "Wszystkie pliki",
@@ -144,7 +147,6 @@
"desc": "Inteligentne określenie, czy potrzebne jest wyszukiwanie na podstawie treści rozmowy",
"title": "Inteligentne połączenie"
},
"disable": "Aktualny model nie obsługuje wywołań funkcji, więc nie można korzystać z inteligentnego połączenia",
"off": {
"desc": "Używaj tylko podstawowej wiedzy modelu, bez wyszukiwania w sieci",
"title": "Wyłącz połączenie"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Użyj wbudowanej wyszukiwarki modelu"
},
"searchModel": {
"desc": "Aktualny model nie obsługuje wywołań funkcji, dlatego wymaga współpracy z modelem obsługującym wywołania funkcji, aby móc przeszukiwać sieć",
"title": "Model wspomagający wyszukiwanie"
},
"title": "Wyszukiwanie w sieci"
},
"searchAgentPlaceholder": "Wyszukaj pomocnika...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "Brak włączonych modeli, przejdź do ustawień i włącz je",
"emptyProvider": "Nie ma aktywnego dostawcy usług, przejdź do ustawień, aby go włączyć",
"goToSettings": "Przejdź do ustawień",
"provider": "Dostawca"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet oferuje możliwości przewyższające Opus oraz szybsze tempo niż Sonnet, zachowując tę samą cenę. Sonnet szczególnie dobrze radzi sobie z programowaniem, nauką o danych, przetwarzaniem wizualnym i zadaniami agenta."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet to najinteligentniejszy model stworzony przez Anthropic, a także pierwszy na rynku model mieszanej dedukcji. Claude 3.7 Sonnet potrafi generować niemal natychmiastowe odpowiedzi lub wydłużone, krok po kroku myślenie, które użytkownicy mogą wyraźnie obserwować. Sonnet szczególnie dobrze radzi sobie z programowaniem, nauką o danych, przetwarzaniem wizualnym oraz zadaniami agenta."
},
"aya": {
"description": "Aya 23 to model wielojęzyczny wydany przez Cohere, wspierający 23 języki, ułatwiający różnorodne zastosowania językowe."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Parar",
"warp": "Quebrar linha"
},
"intentUnderstanding": {
"title": "Analisando e compreendendo sua intenção..."
},
"knowledgeBase": {
"all": "Todo conteúdo",
"allFiles": "Todos os arquivos",
@@ -144,7 +147,6 @@
"desc": "Determina inteligentemente se é necessário pesquisar com base no conteúdo da conversa",
"title": "Conexão Inteligente"
},
"disable": "O modelo atual não suporta chamadas de função, portanto, a funcionalidade de conexão inteligente não está disponível",
"off": {
"desc": "Usa apenas o conhecimento básico do modelo, sem realizar pesquisas na web",
"title": "Desativar Conexão"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Usar o mecanismo de busca embutido no modelo"
},
"searchModel": {
"desc": "O modelo atual não suporta chamadas de função, portanto, é necessário combiná-lo com um modelo que suporte chamadas de função para realizar buscas na internet",
"title": "Modelo de busca auxiliar"
},
"title": "Pesquisa Conectada"
},
"searchAgentPlaceholder": "Assistente de busca...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "Nenhum modelo habilitado. Por favor, vá para as configurações e habilite um.",
"emptyProvider": "Nenhum provedor ativado, por favor vá para as configurações para ativar",
"goToSettings": "Ir para as configurações",
"provider": "Fornecedor"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet oferece capacidades que vão além do Opus e uma velocidade superior ao Sonnet, mantendo o mesmo preço do Sonnet. O Sonnet é especialmente habilidoso em programação, ciência de dados, processamento visual e tarefas de agente."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet é o modelo mais inteligente da Anthropic até agora e é o primeiro modelo de raciocínio misto do mercado. Claude 3.7 Sonnet pode gerar respostas quase instantâneas ou um pensamento gradual prolongado, permitindo que os usuários vejam claramente esses processos. Sonnet é especialmente habilidoso em programação, ciência de dados, processamento visual e tarefas de agente."
},
"aya": {
"description": "Aya 23 é um modelo multilíngue lançado pela Cohere, suportando 23 idiomas, facilitando aplicações linguísticas diversificadas."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Остановить",
"warp": "Перенос строки"
},
"intentUnderstanding": {
"title": "Анализ и понимание вашего намерения..."
},
"knowledgeBase": {
"all": "Все содержимое",
"allFiles": "Все файлы",
@@ -144,7 +147,6 @@
"desc": "Интеллектуально определяет необходимость поиска на основе содержания диалога",
"title": "Интеллектуальное подключение к сети"
},
"disable": "Текущая модель не поддерживает вызовы функций, поэтому функция интеллектуального подключения к сети недоступна",
"off": {
"desc": "Использует только базовые знания модели, без сетевого поиска",
"title": "Отключить подключение к сети"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Использовать встроенный поисковый движок модели"
},
"searchModel": {
"desc": "Текущая модель не поддерживает вызов функций, поэтому необходимо использовать модель, поддерживающую вызов функций, для поиска в интернете",
"title": "Модель поиска"
},
"title": "Поиск в сети"
},
"searchAgentPlaceholder": "Поиск помощника...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "Нет активированных моделей. Пожалуйста, перейдите в настройки и включите модель",
"emptyProvider": "Нет активных провайдеров, пожалуйста, перейдите в настройки для их включения",
"goToSettings": "Перейти в настройки",
"provider": "Поставщик"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet предлагает возможности, превосходящие Opus, и скорость, превышающую Sonnet, при этом сохраняя ту же цену. Sonnet особенно хорошо справляется с программированием, наукой о данных, визуальной обработкой и агентскими задачами."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet — это самая умная модель от Anthropic на сегодняшний день и первая в мире смешанная модель вывода. Claude 3.7 Sonnet может генерировать почти мгновенные ответы или длительные пошаговые размышления, позволяя пользователям четко видеть эти процессы. Sonnet особенно хорошо справляется с программированием, научными данными, визуальной обработкой и агентскими задачами."
},
"aya": {
"description": "Aya 23 — это многоязычная модель, выпущенная Cohere, поддерживающая 23 языка, обеспечивая удобство для многоязычных приложений."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Dur",
"warp": "Satır atla"
},
"intentUnderstanding": {
"title": "Niyetinizi analiz ediyor ve anlıyor..."
},
"knowledgeBase": {
"all": "Tüm İçerik",
"allFiles": "Tüm Dosyalar",
@@ -144,7 +147,6 @@
"desc": "Sohbet içeriğine göre akıllıca arama gerekip gerekmediğini belirler",
"title": "Akıllı Bağlantı"
},
"disable": "Mevcut model fonksiyon çağrısını desteklemediği için akıllı bağlantı özelliği kullanılamaz",
"off": {
"desc": "Sadece modelin temel bilgilerini kullanır, ağ araması yapmaz",
"title": "Bağlantıyı Kapat"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Modelin yerleşik arama motorunu kullan"
},
"searchModel": {
"desc": "Mevcut model fonksiyon çağrısını desteklemiyor, bu nedenle çevrimiçi arama yapmak için fonksiyon çağrısını destekleyen bir model ile birlikte kullanılması gerekiyor",
"title": "Arama Yardımcı Modeli"
},
"title": "Ağ Araması"
},
"searchAgentPlaceholder": "Arama Asistanı...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "Etkinleştirilmiş model bulunmamaktadır, lütfen ayarlara giderek açın",
"emptyProvider": "Etkinleştirilmiş bir sağlayıcı yok, lütfen ayarlara gidin",
"goToSettings": "Ayrıntılara git",
"provider": "Sağlayıcı"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet, Opus'tan daha fazla yetenek ve Sonnet'ten daha hızlı bir hız sunar; aynı zamanda Sonnet ile aynı fiyatı korur. Sonnet, programlama, veri bilimi, görsel işleme ve ajan görevlerinde özellikle başarılıdır."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet, Anthropic'in şimdiye kadarki en akıllı modeli ve piyasadaki ilk karma akıl yürütme modelidir. Claude 3.7 Sonnet, neredeyse anlık yanıtlar veya uzatılmış adım adım düşünme süreçleri üretebilir; kullanıcılar bu süreçleri net bir şekilde görebilir. Sonnet, programlama, veri bilimi, görsel işleme ve temsilci görevlerde özellikle yeteneklidir."
},
"aya": {
"description": "Aya 23, Cohere tarafından sunulan çok dilli bir modeldir, 23 dili destekler ve çok dilli uygulamalar için kolaylık sağlar."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "Dừng",
"warp": "Xuống dòng"
},
"intentUnderstanding": {
"title": "Đang phân tích và hiểu ý định của bạn..."
},
"knowledgeBase": {
"all": "Tất cả nội dung",
"allFiles": "Tất cả tệp",
@@ -144,7 +147,6 @@
"desc": "Thông minh xác định xem có cần tìm kiếm dựa trên nội dung cuộc trò chuyện",
"title": "Kết nối thông minh"
},
"disable": "Mô hình hiện tại không hỗ trợ gọi hàm, do đó không thể sử dụng chức năng kết nối thông minh",
"off": {
"desc": "Chỉ sử dụng kiến thức cơ bản của mô hình, không thực hiện tìm kiếm trên mạng",
"title": "Tắt kết nối"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "Sử dụng công cụ tìm kiếm tích hợp của mô hình"
},
"searchModel": {
"desc": "Mô hình hiện tại không hỗ trợ gọi hàm, vì vậy cần kết hợp với mô hình hỗ trợ gọi hàm để tìm kiếm trực tuyến",
"title": "Mô hình hỗ trợ tìm kiếm"
},
"title": "Tìm kiếm trực tuyến"
},
"searchAgentPlaceholder": "Trợ lý tìm kiếm...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "Không có mô hình nào được kích hoạt, vui lòng điều chỉnh trong cài đặt",
"emptyProvider": "Không có nhà cung cấp nào được kích hoạt, vui lòng vào cài đặt để bật",
"goToSettings": "Đi đến cài đặt",
"provider": "Nhà cung cấp"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet cung cấp khả năng vượt trội hơn Opus và tốc độ nhanh hơn Sonnet, trong khi vẫn giữ giá tương tự. Sonnet đặc biệt xuất sắc trong lập trình, khoa học dữ liệu, xử lý hình ảnh và các nhiệm vụ đại lý."
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet là mô hình thông minh nhất của Anthropic cho đến nay, và cũng là mô hình suy luận hỗn hợp đầu tiên trên thị trường. Claude 3.7 Sonnet có khả năng tạo ra phản hồi gần như ngay lập tức hoặc suy nghĩ từng bước kéo dài, cho phép người dùng thấy rõ những quá trình này. Sonnet đặc biệt xuất sắc trong lập trình, khoa học dữ liệu, xử lý hình ảnh và các nhiệm vụ đại diện."
},
"aya": {
"description": "Aya 23 là mô hình đa ngôn ngữ do Cohere phát hành, hỗ trợ 23 ngôn ngữ, tạo điều kiện thuận lợi cho các ứng dụng ngôn ngữ đa dạng."
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "停止",
"warp": "换行"
},
"intentUnderstanding": {
"title": "正在分析并理解意图您的意图..."
},
"knowledgeBase": {
"all": "所有内容",
"allFiles": "所有文件",
@@ -144,7 +147,6 @@
"desc": "根据对话内容智能判断是否需要搜索",
"title": "智能联网"
},
"disable": "当前模型不支持函数调用,因此无法使用智能联网功能",
"off": {
"desc": "仅使用模型的基础知识,不进行网络搜索",
"title": "关闭联网"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "使用模型内置搜索引擎"
},
"searchModel": {
"desc": "当前模型不支持函数调用,因此需要搭配支持函数调用的模型才能联网搜索",
"title": "搜索辅助模型"
},
"title": "联网搜索"
},
"searchAgentPlaceholder": "搜索助手...",
+3 -1
View File
@@ -85,7 +85,9 @@
},
"ModelSwitchPanel": {
"emptyModel": "没有启用的模型,请前往设置开启",
"provider": "提供商"
"emptyProvider": "没有启用的服务商,请前往设置开启",
"goToSettings": "前往设置",
"provider": "服务商"
},
"OllamaSetupGuide": {
"cors": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet 提供了超越 Opus 的能力和比 Sonnet 更快的速度,同时保持与 Sonnet 相同的价格。Sonnet 特别擅长编程、数据科学、视觉处理、代理任务。"
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet 是 Anthropic 迄今为止最智能的模型,也是市场上首个混合推理模型。Claude 3.7 Sonnet 可以产生近乎即时的响应或延长的逐步思考,用户可以清晰地看到这些过程。Sonnet 特别擅长编程、数据科学、视觉处理、代理任务。"
},
"aya": {
"description": "Aya 23 是 Cohere 推出的多语言模型,支持 23 种语言,为多元化语言应用提供便利。"
},
+7 -1
View File
@@ -64,6 +64,9 @@
"stop": "停止",
"warp": "換行"
},
"intentUnderstanding": {
"title": "正在分析並理解您的意圖..."
},
"knowledgeBase": {
"all": "所有內容",
"allFiles": "所有檔案",
@@ -144,7 +147,6 @@
"desc": "根據對話內容智能判斷是否需要搜尋",
"title": "智能連網"
},
"disable": "當前模型不支持函數調用,因此無法使用智能連網功能",
"off": {
"desc": "僅使用模型的基礎知識,不進行網路搜尋",
"title": "關閉連網"
@@ -155,6 +157,10 @@
},
"useModelBuiltin": "使用模型內建搜尋引擎"
},
"searchModel": {
"desc": "當前模型不支持函數調用,因此需要搭配支持函數調用的模型才能聯網搜索",
"title": "搜索輔助模型"
},
"title": "連網搜尋"
},
"searchAgentPlaceholder": "搜尋助手...",
+2
View File
@@ -85,6 +85,8 @@
},
"ModelSwitchPanel": {
"emptyModel": "沒有啟用的模型,請前往設定開啟",
"emptyProvider": "沒有啟用的服務商,請前往設定開啟",
"goToSettings": "前往設定",
"provider": "提供商"
},
"OllamaSetupGuide": {
+3
View File
@@ -506,6 +506,9 @@
"anthropic/claude-3.5-sonnet": {
"description": "Claude 3.5 Sonnet 提供了超越 Opus 的能力和比 Sonnet 更快的速度,同時保持與 Sonnet 相同的價格。Sonnet 特別擅長程式設計、數據科學、視覺處理、代理任務。"
},
"anthropic/claude-3.7-sonnet": {
"description": "Claude 3.7 Sonnet 是 Anthropic 迄今為止最智能的模型,也是市場上首個混合推理模型。Claude 3.7 Sonnet 可以產生近乎即時的回應或延長的逐步思考,使用者可以清晰地看到這些過程。Sonnet 特別擅長程式設計、數據科學、視覺處理、代理任務。"
},
"aya": {
"description": "Aya 23 是 Cohere 推出的多語言模型,支持 23 種語言,為多元化語言應用提供便利。"
},
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@lobehub/chat",
"version": "1.69.4",
"version": "1.70.0",
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
"keywords": [
"framework",
@@ -120,7 +120,7 @@
"@clerk/themes": "^2.2.4",
"@codesandbox/sandpack-react": "^2.19.10",
"@cyntler/react-doc-viewer": "^1.17.0",
"@electric-sql/pglite": "0.2.13",
"@electric-sql/pglite": "0.2.17",
"@google-cloud/vertexai": "^1.9.2",
"@google/generative-ai": "^0.24.0",
"@huggingface/inference": "^2.8.1",
@@ -326,7 +326,7 @@
"vitest": "~1.2.2",
"vitest-canvas-mock": "^0.3.3"
},
"packageManager": "pnpm@9.15.6",
"packageManager": "pnpm@9.15.7",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
+1 -1
View File
@@ -5,7 +5,7 @@
"main": "src/index.ts",
"types": "src/index.ts",
"dependencies": {
"@mozilla/readability": "^0.5.0",
"@mozilla/readability": "^0.6.0",
"happy-dom": "^17.0.0",
"node-html-markdown": "^1.3.0",
"query-string": "^9.1.1",
@@ -67,7 +67,7 @@ describe('browserless', () => {
contentType: 'text',
description: expect.any(String),
length: expect.any(Number),
siteName: null,
siteName: undefined,
title: 'Test Title',
url: 'https://example.com',
});
@@ -48,7 +48,7 @@ export const browserless: CrawlImpl = async (url, { filterOptions }) => {
return {
content: result.content,
contentType: 'text',
description: result?.excerpt,
description: result?.description,
length: result.length,
siteName: result?.siteName,
title: result?.title,
+1 -1
View File
@@ -103,7 +103,7 @@ export const naive: CrawlImpl = async (url, { filterOptions }) => {
return {
content: result.content,
contentType: 'text',
description: result?.excerpt,
description: result?.description,
length: result.length,
siteName: result?.siteName,
title: result?.title,
+11 -1
View File
@@ -3,8 +3,18 @@ import { CrawlUrlRule } from './type';
import { crawUrlRules } from './urlRules';
import { applyUrlRules } from './utils/appUrlRules';
interface CrawlOptions {
impls?: string[];
}
export class Crawler {
impls = ['naive', 'jina', 'browserless'] as const;
impls: CrawlImplType[];
constructor(options: CrawlOptions = {}) {
this.impls = !!options.impls?.length
? (options.impls.filter((impl) => Object.keys(crawlImpls).includes(impl)) as CrawlImplType[])
: (['naive', 'jina', 'browserless'] as const);
}
/**
*
@@ -2,7 +2,6 @@
exports[`htmlToMarkdown > should transform terms.html to markdown 1`] = `
{
"byline": null,
"content": " Lasted Updated at
2024-03-01
@@ -111,378 +110,14 @@ Examples of prohibited activities include but are not limited to:
This agreement represents the entire agreement between You and LobeHub regarding the use of the Services. It supersedes any prior agreements or understandings. The failure of LobeHub to enforce any provision of this agreement does not constitute a waiver of its rights.
By accessing or using the LobeHub Services, You acknowledge that You have read, understood, and agreed to be bound by this agreement. If You have any questions regarding this agreement, please contact us at[support@lobehub.com](mailto:support@lobehub.com).",
"dir": null,
"excerpt": "Lasted Updated at",
"lang": null,
"description": "Lasted Updated at",
"length": 18284,
"publishedTime": null,
"siteName": null,
"textContent": "
Lasted Updated at
2024-03-01
Welcome to LobeHub! Please carefully read the following Terms of Use (hereinafter
referred to as the "Agreement"). This Agreement constitutes a legally binding
agreement between You and LobeHub regarding the access and use of the LobeHub
software applications, services, and websites (collectively referred to as the
"Services").
By accessing or using the Services in any way, You acknowledge that You have read,
understood, and agreed to be bound by all the terms of this Agreement. If You do not
agree to any part of this Agreement, You are not permitted to continue accessing or
using the Services.
Definitions
The words of which the initial letter is capitalized have meanings defined under the
following conditions. The following definitions shall have the same meaning
regardless of whether they appear in singular or in plural.
Affiliate means an entity that controls, is controlled by or is
under common control with a party, where "control" means ownership of 50% or more
of the shares, equity interest or other securities entitled to vote for election
of directors or other managing authority.
Agreement means this Terms of Use Agreement.
Company (referred to as either "the Company", "We", "Us" or "Our"
in this Agreement) refers to LobeHub LLC.
Service means the LobeHub software applications, services, and
website.
You means the individual accessing or using the Services, or the
company, or other legal entity on behalf of which such individual is accessing or
using the Services, as applicable.
Our Services
LobeHub provides a platform and interface that enables users to interact with
artificial intelligence technologies, including but not limited to natural language
processing models or content generation models developed independently or provided
by third parties such as Google, Microsoft, OpenAI, and other commercial companies
as well as open-source communities. The Service facilitates functions such as
information retrieval, content creation, and automation through user interaction
with AI systems. Additionally, it utilizes cloud technology to provide capabilities
like data synchronization, vector data storage, server-side functionalities, etc.,
to enhance the interactive experience with AI models.
Eligibility
By accessing or using the Services, You represent and warrant to the Company that
You: (1)Are of legal age (18 years and above). (2)Have legal capacity and agree to
abide by these terms. (3)Will use the Services in accordance with this Agreement and
all applicable laws. (4)Will not use the Services for any illegal, harmful,
dangerous, or offensive purposes.
Examples of prohibited activities include but are not limited to:
Illegal activities
Infringement of intellectual property rights
Generating harmful, unsafe, deceptive, or illegal content
Impersonation, fraud
If You do not comply with the usage conditions, We reserve the right to suspend or
terminate Your account and refuse any and all current or future use of the Services
(or any part thereof).
Account Registration
To access the Services, You must register an account by providing true, accurate,
up-to-date, and complete information. You are solely responsible for all activities
that occur under Your account, including maintaining the security of Your account
and restricting access. You must immediately notify LobeHub of any unauthorized
account use or other security breaches.
Please ensure to keep Your password secure and take responsibility for all use of
Your account and password. If We deem the chosen username inappropriate, containing
obscene content, or otherwise offensive, We reserve the right to delete, revoke, or
modify that username.
Purchases and Payments
You agree to provide current, complete, and accurate purchase and account
information for all purchases made using the Services. You also agree to promptly
update Your account and payment information, including email address, payment
method, and payment card expiration date, to allow us to complete Your transactions
and contact You when necessary. Sales tax will be added to the purchase price as
required by law.
You agree to pay all charges at the current purchase price and authorize us to
charge any such amounts to Your chosen payment provider at the time of purchase. If
Your order requires recurring charges, You agree that We may charge Your payment
method on a recurring basis at the specified intervals without obtaining prior
approval for each recurring charge until the relevant order is canceled. We reserve
the right to correct any errors or pricing errors even after payment has been
requested or accepted.
We may utilize third-party payment processing services (such as Stripe) for payment
processing. You may use a valid card (credit or debit card) for payment, subject to
verification and authorization by Your card issuer. We will not be liable for any
delays or failure to provide Services resulting from payment failures due to
authorization issues or any reasons related to third-party payment providers.
We reserve the right to refuse or cancel Your order at any time for certain reasons,
including but not limited to: (1) Service availability, (2) errors in Service
description or pricing, (3) order errors, (4) suspected fraud or unauthorized or
illegal transactions. We reserve the right, at our sole discretion, to limit or
prohibit orders placed by dealers, resellers, or distributors.
Fee Changes
We reserve the right to adjust the Service fees at our discretion and at any time.
Any changes in fees will take effect immediately upon the change. Services that have
already been paid for and purchased will not be affected.
If Your order requires recurring automatic billing, the revised price will take
effect on the next billing cycle. We will notify You in advance of any fee
adjustments so that You have the opportunity to cancel the order before the
adjustment takes effect. If You do not cancel the order and continue to use the
Services, You agree to pay the revised fee amount.
Refunds
For Services that have been purchased but not used, We support refunds within 30
days of payment. However, for Services that have been used or purchased for more
than 30 days, We will not accept refund requests.
For subscription-based Services where partial usage has occurred, Your refund
request will be reviewed on a case-by-case basis, and the final decision on
approving the refund will be at the Company's discretion.
Content
Our Services allows You to generate and publish content. You are responsible for the
legality, reliability, and appropriateness of the content generated using the AI
ability. We do not assume responsibility for user-generated content on the Services.
You explicitly understand and agree that You are solely responsible for the content
You post and all activities conducted under Your account, whether by Yourself or by
third parties using Your account.
By generating and publishing content in the Services, You grant us the rights and
licenses necessary to use, modify, publicly perform, publicly display, copy, and
distribute such content within the Services. You retain full ownership of all
content created, published, or displayed within the Services and are responsible for
maintaining these rights. You agree that this license includes the permission for us
to provide Your content to other Service users for their use under these terms.
Additionally, You declare and warrant that: (1) the content is owned by You or You
have the legal right to use and authorize it to us under this agreement. (2) posting
the shared information in the Services will not infringe upon the privacy rights,
image rights, copyrights, contractual relationships, or other individual rights of
others.
All content generated by You is by default stored locally on the client-side, and
You are responsible for the storage and backup of Your content.
Additionally, We offer optional cloud sync content functionality. By using this
feature, You agree that We may retain complete and accurate copies of any content in
locations independent of the Services in our manner. However, We cannot guarantee
that data will not be lost or damaged. Data or content loss or damage can occur due
to various reasons, such as pre-existing damage before synchronization or changes
during synchronization.
We do not assume any responsibility for the security and integrity of content in the
event of content damage or loss under any circumstances.
Intellectual Property Rights
LobeHub reserves all rights to the technology, software, first-party content, and
data within the Services, including but not limited to patents, trademarks, trade
secrets, copyrights, and other intellectual property rights. Your permission to use
the Services does not grant You any ownership or title. You are not permitted to
copy, modify, adapt, translate, create derivative works, reverse engineer,
disassemble, or decompile the Services or any part thereof. If You wish to
participate in collaborative technical development, please engage through our GitHub
open-source community and adhere to the relevant open-source licenses.
Privacy and Security
LobeHub employs industry-standard technical, managerial, and physical security
measures to protect the security, confidentiality, and integrity of Your data.
However, We cannot guarantee that unauthorized access, hacking attacks, data loss,
or other breaches will never occur. LobeHub is not liable for any damages or
liabilities related to security incidents. Please refer to our Privacy Policy for
more detailed information.
Termination of Services
You may close Your account and cease using the Services at any time. In the event of
a violation of the terms of the agreement, LobeHub may immediately suspend or
terminate Your access to the Services. Upon termination, You will immediately lose
the right to access or use the Services. LobeHub will not be liable to You or any
third party for the termination of the Services.
Disclaimer of Warranties
The Services provided by LobeHub are provided on an "as-is" basis, and without any
form of guarantee. We explicitly disclaim all warranties, whether express, implied,
statutory, or otherwise, including but not limited to warranties of merchantability,
fitness for a particular purpose, and non-infringement. Your use of the Services is
at Your own risk.
Limitation of Liability
In no event shall LobeHub, its Affiliates, directors, employees, or agents be liable
for any direct, indirect, punitive, incidental, special, or consequential damages
arising from or related to Your use or inability to use the Services. This
limitation applies regardless of the basis or form of action.
Modification of Terms
We may revise this agreement periodically, and the new version of the agreement will
replace the previous version. We will indicate the "last updated" date at the
beginning and provide notice within the Services to inform You of significant
changes. It is Your responsibility to regularly review these legal terms to stay
informed of any updates. By continuing to use the Services after the revised legal
terms are posted, You will be deemed to have understood and accepted any changes to
the revised legal terms.
Governing Law and Jurisdiction
This agreement shall be governed by the laws of the State of Delaware, and You agree
to submit to the exclusive jurisdiction of the state and federal courts located in
Delaware for the resolution of any disputes related to this agreement or the
Services. You may also be required to comply with the laws of Your local
jurisdiction, state, country, or international laws when using the Services.
Conclusion
This agreement represents the entire agreement between You and LobeHub regarding the
use of the Services. It supersedes any prior agreements or understandings. The
failure of LobeHub to enforce any provision of this agreement does not constitute a
waiver of its rights.
By accessing or using the LobeHub Services, You acknowledge that You have read,
understood, and agreed to be bound by this agreement. If You have any questions
regarding this agreement, please contact us at
support@lobehub.com.
",
"title": "Terms of Service · LobeHub",
}
`;
exports[`htmlToMarkdown > should transform yingchao.html to markdown 1`] = `
{
"byline": null,
"content": " 资讯
全部 NBA CBA 英超 法甲 意甲 德甲 西甲 综合 专题 预测
@@ -616,23 +251,8 @@ copyright © 2016 - 2025 qiumiwu.com All Rights Reserved
温馨提示
扫描二维码,下载球迷屋App,获得更好的使用体验",
"dir": null,
"excerpt": "球迷屋为您提供2024-2025赛季英超积分排行榜,包含所有英超球队的全部赛季的排行榜数据,包含了英超球队的排名、场次、胜平负、进球、失球、积分等等详细积分数据,让大家迅速了解英超积分排行榜的数据。",
"lang": null,
"description": "球迷屋为您提供2024-2025赛季英超积分排行榜,包含所有英超球队的全部赛季的排行榜数据,包含了英超球队的排名、场次、胜平负、进球、失球、积分等等详细积分数据,让大家迅速了解英超积分排行榜的数据。",
"length": 201,
"publishedTime": null,
"siteName": null,
"textContent": "
copyright © 2016 - 2025 qiumiwu.com All Rights Reserved
粤公网安备 44190002004105号
粤ICP备16062857号
增值电信业务经营许可证粤B2-20210041
粤网文[2021]4047-607号
",
"title": "英超排行榜|英超积分榜2024-2025赛季 - 球迷屋",
}
`;
@@ -4,10 +4,28 @@ import { NodeHtmlMarkdown, type TranslatorConfigObject } from 'node-html-markdow
import { FilterOptions } from '../type';
const cleanObj = <T extends object>(
obj: T,
): {
[K in keyof T as T[K] extends null ? never : K]: T[K];
} => Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== null)) as any;
interface HtmlToMarkdownOutput {
author?: string;
content: string;
description?: string;
dir?: string;
lang?: string;
length?: number;
publishedTime?: string;
siteName?: string;
title?: string;
}
export const htmlToMarkdown = (
html: string,
{ url, filterOptions }: { filterOptions: FilterOptions; url: string },
) => {
): HtmlToMarkdownOutput => {
const window = new Window({ url });
const document = window.document;
@@ -41,5 +59,17 @@ export const htmlToMarkdown = (
const content = nodeHtmlMarkdown.translate(htmlNode);
return { ...parsedContent, content };
const result = {
author: parsedContent?.byline,
content,
description: parsedContent?.excerpt,
dir: parsedContent?.dir,
lang: parsedContent?.lang,
length: parsedContent?.length,
publishedTime: parsedContent?.publishedTime,
siteName: parsedContent?.siteName,
title: parsedContent?.title,
};
return cleanObj(result) as HtmlToMarkdownOutput;
};
@@ -181,7 +181,10 @@ describe('POST handler', () => {
const response = await POST(request as unknown as Request, { params: mockParams });
expect(response).toEqual(mockChatResponse);
expect(AgentRuntime.prototype.chat).toHaveBeenCalledWith(mockChatPayload, { user: 'abc' });
expect(AgentRuntime.prototype.chat).toHaveBeenCalledWith(mockChatPayload, {
user: 'abc',
signal: expect.anything(),
});
});
it('should return an error response when chat completion fails', async () => {
@@ -39,7 +39,11 @@ export const POST = checkAuth(async (req: Request, { params, jwtPayload, createR
});
}
return await agentRuntime.chat(data, { user: jwtPayload.userId, ...traceOptions });
return await agentRuntime.chat(data, {
user: jwtPayload.userId,
...traceOptions,
signal: req.signal,
});
} catch (e) {
const {
errorType = ChatErrorType.InternalServerError,
@@ -105,7 +105,11 @@ const AgentsSuggest = memo<{ mobile?: boolean }>(({ mobile }) => {
: assistantList
.slice(sliceStart, sliceStart + agentLength)
.map((item: DiscoverAssistantItem) => (
<Link href={urlJoin('/discover/assistant/', item.identifier)} key={item.identifier}>
<Link
href={urlJoin('/discover/assistant/', item.identifier)}
key={item.identifier}
prefetch={false}
>
<Flexbox className={styles.card} gap={8} horizontal>
<Avatar avatar={item.meta.avatar} style={{ flex: 'none' }} />
<Flexbox gap={mobile ? 2 : 8} style={{ overflow: 'hidden', width: '100%' }}>
@@ -1,4 +1,5 @@
import { createStyles } from 'antd-style';
import { memo } from 'react';
export const useStyles = createStyles(({ css, token }, borderWidth: number = 2.5) => ({
background: css`
@@ -44,7 +45,7 @@ export const useStyles = createStyles(({ css, token }, borderWidth: number = 2.5
`,
}));
const Loader = () => {
const CircleLoader = memo(() => {
const { styles } = useStyles();
return (
@@ -53,6 +54,6 @@ const Loader = () => {
<div className={styles.background} />
</div>
);
};
});
export default Loader;
export default CircleLoader;
+3
View File
@@ -301,6 +301,9 @@ const OpenAI: ModelProviderCard = {
name: 'OpenAI',
settings: {
showModelFetcher: true,
smoothing: {
text: true,
},
},
url: 'https://openai.com',
};
+2
View File
@@ -4,10 +4,12 @@ import { z } from 'zod';
export const getToolsConfig = () => {
return createEnv({
runtimeEnv: {
CRAWLER_IMPLS: process.env.CRAWLER_IMPLS,
SEARXNG_URL: process.env.SEARXNG_URL,
},
server: {
CRAWLER_IMPLS: z.string().optional(),
SEARXNG_URL: z.string().url().optional(),
},
});
+6
View File
@@ -13,6 +13,11 @@ export const DEFAUTT_AGENT_TTS_CONFIG: LobeAgentTTSConfig = {
},
};
export const DEFAULT_AGENT_SEARCH_FC_MODEL = {
model: DEFAULT_MODEL,
provider: ModelProvider.OpenAI,
};
export const DEFAULT_AGENT_CHAT_CONFIG: LobeAgentChatConfig = {
autoCreateTopicThreshold: 2,
displayMode: 'chat',
@@ -22,6 +27,7 @@ export const DEFAULT_AGENT_CHAT_CONFIG: LobeAgentChatConfig = {
enableReasoning: false,
historyCount: 8,
reasoningBudgetToken: 1024,
searchFCModel: DEFAULT_AGENT_SEARCH_FC_MODEL,
searchMode: 'off',
};
+3 -3
View File
@@ -26,13 +26,13 @@ export class DatabaseManager {
// CDN 配置
private static WASM_CDN_URL =
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.13/files/dist/postgres.wasm';
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.17/files/dist/postgres.wasm';
private static FSBUNDLER_CDN_URL =
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.13/files/dist/postgres.data';
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.17/files/dist/postgres.data';
private static VECTOR_CDN_URL =
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.13/files/dist/vector.tar.gz';
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.17/files/dist/vector.tar.gz';
private constructor() {}
@@ -0,0 +1,56 @@
import { createStyles } from 'antd-style';
import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit';
import InfoTooltip from '@/components/InfoTooltip';
import { useAgentStore } from '@/store/agent';
import { agentChatConfigSelectors } from '@/store/agent/slices/chat';
import FunctionCallingModelSelect from './FunctionCallingModelSelect';
const useStyles = createStyles(({ css, token }) => ({
check: css`
margin-inline-start: 12px;
font-size: 16px;
color: ${token.colorPrimary};
`,
content: css`
flex: 1;
width: 230px;
`,
description: css`
width: 200px;
font-size: 12px;
color: ${token.colorTextSecondary};
`,
title: css`
font-size: 14px;
font-weight: 500;
color: ${token.colorText};
`,
}));
const FCSearchModel = () => {
const { t } = useTranslation('chat');
const { styles } = useStyles();
const [searchFCModel, updateAgentChatConfig] = useAgentStore((s) => [
agentChatConfigSelectors.searchFCModel(s),
s.updateAgentChatConfig,
]);
return (
<Flexbox distribution={'space-between'} gap={16} horizontal padding={8}>
<Flexbox align={'center'} gap={4} horizontal>
<Flexbox className={styles.title}>{t('search.searchModel.title')}</Flexbox>
<InfoTooltip title={t('search.searchModel.desc')} />
</Flexbox>
<FunctionCallingModelSelect
onChange={(value) => {
updateAgentChatConfig({ searchFCModel: value });
}}
value={searchFCModel}
/>
</Flexbox>
);
};
export default FCSearchModel;
@@ -0,0 +1,85 @@
import { Select, SelectProps } from 'antd';
import { createStyles } from 'antd-style';
import { memo, useMemo } from 'react';
import { ModelItemRender, ProviderItemRender } from '@/components/ModelSelect';
import { useEnabledChatModels } from '@/hooks/useEnabledChatModels';
import { WorkingModel } from '@/types/agent';
import { EnabledProviderWithModels } from '@/types/aiProvider';
const useStyles = createStyles(({ css, prefixCls }) => ({
select: css`
&.${prefixCls}-select-dropdown .${prefixCls}-select-item-option-grouped {
padding-inline-start: 12px;
}
`,
}));
interface ModelOption {
label: any;
provider: string;
value: string;
}
interface ModelSelectProps {
onChange?: (props: WorkingModel) => void;
showAbility?: boolean;
value?: WorkingModel;
}
const ModelSelect = memo<ModelSelectProps>(({ value, onChange }) => {
const enabledList = useEnabledChatModels();
const { styles } = useStyles();
const options = useMemo<SelectProps['options']>(() => {
const getChatModels = (provider: EnabledProviderWithModels) =>
provider.children
.filter((model) => !!model.abilities.functionCall)
.map((model) => ({
label: <ModelItemRender {...model} {...model.abilities} showInfoTag={false} />,
provider: provider.id,
value: `${provider.id}/${model.id}`,
}));
if (enabledList.length === 1) {
const provider = enabledList[0];
return getChatModels(provider);
}
return enabledList
.filter((p) => !!getChatModels(p).length)
.map((provider) => {
const options = getChatModels(provider);
return {
label: (
<ProviderItemRender
logo={provider.logo}
name={provider.name}
provider={provider.id}
source={provider.source}
/>
),
options,
};
});
}, [enabledList]);
return (
<Select
onChange={(value, option) => {
const model = value.split('/').slice(1).join('/');
onChange?.({ model, provider: (option as unknown as ModelOption).provider });
}}
options={options}
popupClassName={styles.select}
popupMatchSelectWidth={false}
value={`${value?.provider}/${value?.model}`}
variant={'filled'}
/>
);
});
export default ModelSelect;
@@ -12,6 +12,7 @@ import { agentChatConfigSelectors, agentSelectors } from '@/store/agent/slices/c
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
import { SearchMode } from '@/types/search';
import FCSearchModel from './FCSearchModel';
import ModelBuiltinSearch from './ModelBuiltinSearch';
const { Text } = Typography;
@@ -38,10 +39,6 @@ const useStyles = createStyles(({ css, token }) => ({
font-size: 12px;
color: ${token.colorTextSecondary};
`,
disable: css`
cursor: not-allowed;
opacity: 0.45;
`,
iconWrapper: css`
display: flex;
flex-shrink: 0;
@@ -80,8 +77,7 @@ const useStyles = createStyles(({ css, token }) => ({
`,
}));
const Item = memo<NetworkOption>(({ value, description, icon, label, disable }) => {
const { t } = useTranslation('chat');
const Item = memo<NetworkOption>(({ value, description, icon, label }) => {
const { styles } = useStyles();
const [mode, updateAgentChatConfig] = useAgentStore((s) => [
agentChatConfigSelectors.agentSearchMode(s),
@@ -96,12 +92,12 @@ const Item = memo<NetworkOption>(({ value, description, icon, label, disable })
key={value}
onClick={() => updateAgentChatConfig({ searchMode: value })}
>
<Flexbox className={disable ? styles.disable : ''} gap={8} horizontal>
<Flexbox gap={8} horizontal>
<div className={styles.iconWrapper}>{icon}</div>
<div className={styles.content}>
<div className={styles.title}>{label}</div>
<Text className={styles.description} type="secondary">
{disable ? t('search.mode.disable') : description}
{description}
</Text>
</div>
</Flexbox>
@@ -132,34 +128,24 @@ const AINetworkSettings = memo<AINetworkSettingsProps>(() => {
label: t('search.mode.off.title'),
value: 'off',
},
// 等应用层联网功能做好以后再开启
// {
// description: t('search.mode.on.desc'),
// icon: <WifiOutlined />,
// label: t('search.mode.on.title'),
// value: 'on',
// },
{
description: t('search.mode.auto.desc'),
disable: !supportFC,
icon: <Icon icon={SparklesIcon} />,
label: t('search.mode.auto.title'),
value: 'auto',
},
];
const showDivider = isModelHasBuiltinSearchConfig || !supportFC;
return (
<Flexbox gap={8}>
{options.map((option) => (
<Item {...option} key={option.value} />
))}
{isModelHasBuiltinSearchConfig && (
<>
<Divider style={{ margin: 0, paddingInline: 12 }} />
<ModelBuiltinSearch />
</>
)}
{showDivider && <Divider style={{ margin: 0, paddingInline: 12 }} />}
{isModelHasBuiltinSearchConfig && <ModelBuiltinSearch />}
{!supportFC && <FCSearchModel />}
</Flexbox>
);
});
@@ -7,11 +7,10 @@ import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit';
import { getPrice } from '@/features/Conversation/Extras/Usage/UsageDetail/pricing';
import { useGlobalStore } from '@/store/global';
import { systemStatusSelectors } from '@/store/global/selectors';
import { LobeDefaultAiModelListItem } from '@/types/aiModel';
import { ModelPriceCurrency } from '@/types/llm';
import { formatPriceByCurrency } from '@/utils/format';
export const useStyles = createStyles(({ css, token }) => {
return {
@@ -40,19 +39,8 @@ const ModelCard = memo<ModelCardProps>(({ pricing, id, provider, displayName })
const isShowCredit = useGlobalStore(systemStatusSelectors.isShowCredit) && !!pricing;
const updateSystemStatus = useGlobalStore((s) => s.updateSystemStatus);
const inputPrice = formatPriceByCurrency(pricing?.input, pricing?.currency as ModelPriceCurrency);
const cachedInputPrice = formatPriceByCurrency(
pricing?.cachedInput,
pricing?.currency as ModelPriceCurrency,
);
const writeCacheInputPrice = formatPriceByCurrency(
pricing?.writeCacheInput,
pricing?.currency as ModelPriceCurrency,
);
const outputPrice = formatPriceByCurrency(
pricing?.output,
pricing?.currency as ModelPriceCurrency,
);
const formatPrice = getPrice(pricing || {});
return (
<Flexbox gap={8}>
<Flexbox
@@ -103,37 +91,41 @@ const ModelCard = memo<ModelCardProps>(({ pricing, id, provider, displayName })
{pricing?.cachedInput && (
<Tooltip
title={t('messages.modelCard.pricing.inputCachedTokens', {
amount: cachedInputPrice,
amount: formatPrice.cachedInput,
})}
>
<Flexbox gap={2} horizontal>
<Icon icon={CircleFadingArrowUp} />
{cachedInputPrice}
{formatPrice.cachedInput}
</Flexbox>
</Tooltip>
)}
{pricing?.writeCacheInput && (
<Tooltip
title={t('messages.modelCard.pricing.writeCacheInputTokens', {
amount: writeCacheInputPrice,
amount: formatPrice.writeCacheInput,
})}
>
<Flexbox gap={2} horizontal>
<Icon icon={BookUp2Icon} />
{writeCacheInputPrice}
{formatPrice.writeCacheInput}
</Flexbox>
</Tooltip>
)}
<Tooltip title={t('messages.modelCard.pricing.inputTokens', { amount: inputPrice })}>
<Tooltip
title={t('messages.modelCard.pricing.inputTokens', { amount: formatPrice.input })}
>
<Flexbox gap={2} horizontal>
<Icon icon={ArrowUpFromDot} />
{inputPrice}
{formatPrice.input}
</Flexbox>
</Tooltip>
<Tooltip title={t('messages.modelCard.pricing.outputTokens', { amount: outputPrice })}>
<Tooltip
title={t('messages.modelCard.pricing.outputTokens', { amount: formatPrice.output })}
>
<Flexbox gap={2} horizontal>
<Icon icon={ArrowDownToDot} />
{outputPrice}
{formatPrice.output}
</Flexbox>
</Tooltip>
</Flexbox>
@@ -0,0 +1,26 @@
import { ChatModelPricing } from '@/types/aiModel';
import { ModelPriceCurrency } from '@/types/llm';
import { formatPriceByCurrency } from '@/utils/format';
export const getPrice = (pricing: ChatModelPricing) => {
const inputPrice = formatPriceByCurrency(pricing?.input, pricing?.currency as ModelPriceCurrency);
const cachedInputPrice = formatPriceByCurrency(
pricing?.cachedInput,
pricing?.currency as ModelPriceCurrency,
);
const writeCacheInputPrice = formatPriceByCurrency(
pricing?.writeCacheInput,
pricing?.currency as ModelPriceCurrency,
);
const outputPrice = formatPriceByCurrency(
pricing?.output,
pricing?.currency as ModelPriceCurrency,
);
return {
cachedInput: Number(cachedInputPrice),
input: Number(inputPrice),
output: Number(outputPrice),
writeCacheInput: Number(writeCacheInputPrice),
};
};
@@ -70,7 +70,7 @@ describe('getDetailsToken', () => {
const result = getDetailsToken(usage, mockModelCard);
expect(result.inputCached).toEqual({
credit: 0, // 50 * 0.005 = 0.25, rounded to 0
credit: 1,
token: 50,
});
@@ -165,12 +165,12 @@ describe('getDetailsToken', () => {
const result = getDetailsToken(usage, mockModelCard);
// uncachedInput: (200 - 50) * 0.01 = 1.5 -> 2
// cachedInput: 50 * 0.005 = 0.25 -> 0
// cachedInput: 50 * 0.005 = 0.25 -> 1
// totalOutput: 300 * 0.02 = 6
// totalCredit = 2 + 0 + 6 = 8
// totalCredit = 2 + 1 + 6 = 9
expect(result.totalTokens).toEqual({
credit: 8,
credit: 9,
token: 500,
});
});
@@ -1,6 +1,8 @@
import { LobeDefaultAiModelListItem } from '@/types/aiModel';
import { ChatModelPricing, LobeDefaultAiModelListItem } from '@/types/aiModel';
import { ModelTokensUsage } from '@/types/message';
import { getPrice } from './pricing';
const calcCredit = (token: number, pricing?: number) => {
if (!pricing) return '-';
@@ -29,23 +31,26 @@ export const getDetailsToken = (
? usage?.inputCacheMissTokens
: totalInputTokens - (inputCacheTokens || 0);
// Pricing
const formatPrice = getPrice(modelCard?.pricing as ChatModelPricing);
const inputCacheMissCredit = (
!!inputCacheMissTokens ? calcCredit(inputCacheMissTokens, modelCard?.pricing?.input) : 0
!!inputCacheMissTokens ? calcCredit(inputCacheMissTokens, formatPrice.input) : 0
) as number;
const inputCachedCredit = (
!!inputCacheTokens ? calcCredit(inputCacheTokens, modelCard?.pricing?.cachedInput) : 0
!!inputCacheTokens ? calcCredit(inputCacheTokens, formatPrice.cachedInput) : 0
) as number;
const inputWriteCachedCredit = !!inputWriteCacheTokens
? (calcCredit(inputWriteCacheTokens, modelCard?.pricing?.writeCacheInput) as number)
? (calcCredit(inputWriteCacheTokens, formatPrice.writeCacheInput) as number)
: 0;
const totalOutputCredit = (
!!totalOutputTokens ? calcCredit(totalOutputTokens, modelCard?.pricing?.output) : 0
!!totalOutputTokens ? calcCredit(totalOutputTokens, formatPrice.output) : 0
) as number;
const totalInputCredit = (
!!totalInputTokens ? calcCredit(totalInputTokens, modelCard?.pricing?.output) : 0
!!totalInputTokens ? calcCredit(totalInputTokens, formatPrice.output) : 0
) as number;
const totalCredit =
@@ -69,13 +74,13 @@ export const getDetailsToken = (
: undefined,
inputCitation: !!usage.inputCitationTokens
? {
credit: calcCredit(usage.inputCitationTokens, modelCard?.pricing?.input),
credit: calcCredit(usage.inputCitationTokens, formatPrice.input),
token: usage.inputCitationTokens,
}
: undefined,
inputText: !!inputTextTokens
? {
credit: calcCredit(inputTextTokens, modelCard?.pricing?.input),
credit: calcCredit(inputTextTokens, formatPrice.input),
token: inputTextTokens,
}
: undefined,
@@ -89,13 +94,13 @@ export const getDetailsToken = (
: undefined,
outputReasoning: !!outputReasoningTokens
? {
credit: calcCredit(outputReasoningTokens, modelCard?.pricing?.output),
credit: calcCredit(outputReasoningTokens, formatPrice.output),
token: outputReasoningTokens,
}
: undefined,
outputText: !!outputTextTokens
? {
credit: calcCredit(outputTextTokens, modelCard?.pricing?.output),
credit: calcCredit(outputTextTokens, formatPrice.output),
token: outputTextTokens,
}
: undefined,
@@ -0,0 +1,25 @@
import { createStyles } from 'antd-style';
import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit';
import CircleLoader from '@/components/CircleLoader';
import { shinyTextStylish } from '@/styles/loading';
const useStyles = createStyles(({ token }) => ({
shinyText: shinyTextStylish(token),
}));
const IntentUnderstanding = () => {
const { styles } = useStyles();
const { t } = useTranslation('chat');
return (
<Flexbox align={'center'} gap={8} horizontal>
<CircleLoader />
<Flexbox className={styles.shinyText} horizontal>
{t('intentUnderstanding.title')}
</Flexbox>
</Flexbox>
);
};
export default IntentUnderstanding;
@@ -6,6 +6,7 @@ import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit';
import Loader from '@/components/CircleLoader';
import PluginAvatar from '@/features/PluginAvatar';
import { useChatStore } from '@/store/chat';
import { chatSelectors } from '@/store/chat/selectors';
@@ -14,8 +15,6 @@ import { toolSelectors } from '@/store/tool/selectors';
import { shinyTextStylish } from '@/styles/loading';
import { WebBrowsingManifest } from '@/tools/web-browsing';
import Loader from './Loader';
export const useStyles = createStyles(({ css, token }) => ({
apiName: css`
overflow: hidden;
@@ -8,6 +8,7 @@ import { ChatMessage } from '@/types/message';
import { DefaultMessage } from '../Default';
import FileChunks from './FileChunks';
import IntentUnderstanding from './IntentUnderstanding';
import Reasoning from './Reasoning';
import SearchGrounding from './SearchGrounding';
import Tool from './Tool';
@@ -24,6 +25,8 @@ export const AssistantMessage = memo<
const isReasoning = useChatStore(aiChatSelectors.isMessageInReasoning(id));
const isIntentUnderstanding = useChatStore(aiChatSelectors.isIntentUnderstanding(id));
const showSearch = !!search && !!search.citations?.length;
// remove \n to avoid empty content
@@ -32,6 +35,8 @@ export const AssistantMessage = memo<
(!!props.reasoning && props.reasoning.content?.trim() !== '') ||
(!props.reasoning && isReasoning);
const showFileChunks = !!chunksList && chunksList.length > 0;
return editing ? (
<DefaultMessage
content={content}
@@ -44,16 +49,20 @@ export const AssistantMessage = memo<
{showSearch && (
<SearchGrounding citations={search?.citations} searchQueries={search?.searchQueries} />
)}
{!!chunksList && chunksList.length > 0 && <FileChunks data={chunksList} />}
{showFileChunks && <FileChunks data={chunksList} />}
{showReasoning && <Reasoning {...props.reasoning} id={id} />}
{content && (
<DefaultMessage
addIdOnDOM={false}
content={content}
id={id}
isToolCallGenerating={isToolCallGenerating}
{...props}
/>
{isIntentUnderstanding ? (
<IntentUnderstanding />
) : (
content && (
<DefaultMessage
addIdOnDOM={false}
content={content}
id={id}
isToolCallGenerating={isToolCallGenerating}
{...props}
/>
)
)}
{tools && (
<Flexbox gap={8}>
@@ -64,16 +64,14 @@ const Render = memo<ArtifactProps>(({ identifier, title, type, language, childre
const inThread = useContext(InPortalThreadContext);
const { message } = App.useApp();
const [isGenerating, isArtifactTagClosed, currentArtifactMessageId, openArtifact, closeArtifact] =
useChatStore((s) => {
return [
chatSelectors.isMessageGenerating(id)(s),
chatPortalSelectors.isArtifactTagClosed(id)(s),
chatPortalSelectors.artifactMessageId(s),
s.openArtifact,
s.closeArtifact,
];
});
const [isGenerating, isArtifactTagClosed, openArtifact, closeArtifact] = useChatStore((s) => {
return [
chatSelectors.isMessageGenerating(id)(s),
chatPortalSelectors.isArtifactTagClosed(id)(s),
s.openArtifact,
s.closeArtifact,
];
});
const openArtifactUI = () => {
openArtifact({ id, identifier, language, title, type });
@@ -86,52 +84,53 @@ const Render = memo<ArtifactProps>(({ identifier, title, type, language, childre
}, [isGenerating, hasChildren, str, identifier, title, type, id, language]);
return (
<p>
<Flexbox
className={styles.container}
gap={16}
onClick={() => {
if (currentArtifactMessageId === id) {
closeArtifact();
} else {
if (inThread) {
message.info(t('artifact.inThread'));
return;
}
openArtifactUI();
<Flexbox
className={styles.container}
gap={16}
onClick={() => {
const currentArtifactMessageId = chatPortalSelectors.artifactMessageId(
useChatStore.getState(),
);
if (currentArtifactMessageId === id) {
closeArtifact();
} else {
if (inThread) {
message.info(t('artifact.inThread'));
return;
}
}}
width={'100%'}
>
<Flexbox align={'center'} flex={1} horizontal>
<Center className={styles.avatar} height={64} horizontal width={64}>
<ArtifactIcon type={type} />
</Center>
<Flexbox gap={4} paddingBlock={8} paddingInline={12}>
{!title && isGenerating ? (
<Flexbox className={cx(dotLoading)} horizontal>
{t('artifact.generating')}
openArtifactUI();
}
}}
width={'100%'}
>
<Flexbox align={'center'} flex={1} horizontal>
<Center className={styles.avatar} height={64} horizontal width={64}>
<ArtifactIcon type={type} />
</Center>
<Flexbox gap={4} paddingBlock={8} paddingInline={12}>
{!title && isGenerating ? (
<Flexbox className={cx(dotLoading)} horizontal>
{t('artifact.generating')}
</Flexbox>
) : (
<Flexbox className={cx(styles.title)}>{title || t('artifact.unknownTitle')}</Flexbox>
)}
{hasChildren && (
<Flexbox className={styles.desc} horizontal>
{identifier} ·{' '}
<Flexbox gap={2} horizontal>
{!isArtifactTagClosed && (
<div>
<Icon icon={Loader2} spin />
</div>
)}
{str?.length}
</Flexbox>
) : (
<Flexbox className={cx(styles.title)}>{title || t('artifact.unknownTitle')}</Flexbox>
)}
{hasChildren && (
<Flexbox className={styles.desc} horizontal>
{identifier} ·{' '}
<Flexbox gap={2} horizontal>
{!isArtifactTagClosed && (
<div>
<Icon icon={Loader2} spin />
</div>
)}
{str?.length}
</Flexbox>
</Flexbox>
)}
</Flexbox>
</Flexbox>
)}
</Flexbox>
</Flexbox>
</p>
</Flexbox>
);
});
+34 -8
View File
@@ -1,8 +1,9 @@
import { Icon } from '@lobehub/ui';
import { ActionIcon, Icon } from '@lobehub/ui';
import { Dropdown } from 'antd';
import { createStyles } from 'antd-style';
import type { ItemType } from 'antd/es/menu/interface';
import { LucideArrowRight } from 'lucide-react';
import { LucideArrowRight, LucideBolt } from 'lucide-react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { PropsWithChildren, memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -86,17 +87,42 @@ const ModelSwitchPanel = memo<PropsWithChildren>(({ children }) => {
return items;
};
if (enabledList.length === 0)
return [
{
key: `no-provider`,
label: (
<Flexbox gap={8} horizontal style={{ color: theme.colorTextTertiary }}>
{t('ModelSwitchPanel.emptyProvider')}
<Icon icon={LucideArrowRight} />
</Flexbox>
),
onClick: () => {
router.push(isDeprecatedEdition ? '/settings/llm' : `/settings/provider`);
},
},
];
// otherwise show with provider group
return enabledList.map((provider) => ({
children: getModelItems(provider),
key: provider.id,
label: (
<ProviderItemRender
logo={provider.logo}
name={provider.name}
provider={provider.id}
source={provider.source}
/>
<Flexbox horizontal justify="space-between">
<ProviderItemRender
logo={provider.logo}
name={provider.name}
provider={provider.id}
source={provider.source}
/>
<Link href={isDeprecatedEdition ? '/settings/llm' : `/settings/provider/${provider.id}`}>
<ActionIcon
icon={LucideBolt}
size={'small'}
title={t('ModelSwitchPanel.goToSettings')}
/>
</Link>
</Flexbox>
),
type: 'group',
}));
+1 -9
View File
@@ -9,19 +9,11 @@ export const useAgentEnableSearch = () => {
agentChatConfigSelectors.agentSearchMode(s),
]);
const isModelSupportToolUse = useAiInfraStore(
aiModelSelectors.isModelSupportToolUse(model, provider),
);
const searchImpl = useAiInfraStore(aiModelSelectors.modelBuiltinSearchImpl(model, provider));
// 只要是内置的搜索实现,一定可以联网搜索
if (searchImpl === 'internal') return true;
// 如果是关闭状态,一定不能联网搜索
if (agentSearchMode === 'off') return false;
// 如果是智能模式,根据是否支持 Tool Calling 判断
if (agentSearchMode === 'auto') {
return isModelSupportToolUse;
}
return agentSearchMode !== 'off';
};
+5 -2
View File
@@ -102,7 +102,8 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
if (!!thinking) {
const maxTokens =
max_tokens ?? (thinking?.budget_tokens ? thinking?.budget_tokens + 4096 : 4096);
// claude 3.7 thinking has max output of 64000 tokens
max_tokens ?? (thinking?.budget_tokens ? thinking?.budget_tokens + 64_000 : 8192);
// `temperature` may only be set to 1 when thinking is enabled.
// `top_p` must be unset when thinking is enabled.
@@ -117,7 +118,9 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
}
return {
max_tokens: max_tokens ?? 4096,
// claude 3 series model hax max output token of 4096, 3.x series has 8192
// https://docs.anthropic.com/en/docs/about-claude/models/all-models#:~:text=200K-,Max%20output,-Normal%3A
max_tokens: max_tokens ?? (model.startsWith('claude-3-') ? 4096 : 8192),
messages: postMessages,
model,
system: systemPrompts,
+7 -3
View File
@@ -65,6 +65,9 @@ export default {
stop: '停止',
warp: '换行',
},
intentUnderstanding: {
title: '正在分析并理解意图您的意图...',
},
knowledgeBase: {
all: '所有内容',
allFiles: '所有文件',
@@ -142,13 +145,11 @@ export default {
searchQueries: '搜索关键词',
title: '已搜索到 {{count}} 个结果',
},
mode: {
auto: {
desc: '根据对话内容智能判断是否需要搜索',
title: '智能联网',
},
disable: '当前模型不支持函数调用,因此无法使用智能联网功能',
off: {
desc: '仅使用模型的基础知识,不进行网络搜索',
title: '关闭联网',
@@ -159,7 +160,10 @@ export default {
},
useModelBuiltin: '使用模型内置搜索引擎',
},
searchModel: {
desc: '当前模型不支持函数调用,因此需要搭配支持函数调用的模型才能联网搜索',
title: '搜索辅助模型',
},
title: '联网搜索',
},
searchAgentPlaceholder: '搜索助手...',
+3 -1
View File
@@ -87,7 +87,9 @@ export default {
},
ModelSwitchPanel: {
emptyModel: '没有启用的模型,请前往设置开启',
provider: '提供商',
emptyProvider: '没有启用的服务商,请前往设置开启',
goToSettings: '前往设置',
provider: '服务商',
},
OllamaSetupGuide: {
cors: {
+8 -1
View File
@@ -20,7 +20,14 @@ export const searchRouter = router({
}),
)
.mutation(async ({ input }) => {
const crawler = new Crawler();
const envString = toolsEnv.CRAWLER_IMPLS || '';
// 处理全角逗号和多余空格
let envValue = envString.replaceAll('', ',').trim();
const impls = envValue.split(',').filter(Boolean);
const crawler = new Crawler({ impls });
const results = await pMap(
input.urls,
+124
View File
@@ -26,12 +26,16 @@ import {
ModelProvider,
} from '@/libs/agent-runtime';
import { AgentRuntime } from '@/libs/agent-runtime';
import { agentChatConfigSelectors } from '@/store/agent/selectors';
import { aiModelSelectors } from '@/store/aiInfra';
import { useToolStore } from '@/store/tool';
import { toolSelectors } from '@/store/tool/selectors';
import { UserStore } from '@/store/user';
import { useUserStore } from '@/store/user';
import { modelConfigSelectors } from '@/store/user/selectors';
import { UserSettingsState, initialSettingsState } from '@/store/user/slices/settings/initialState';
import { DalleManifest } from '@/tools/dalle';
import { WebBrowsingManifest } from '@/tools/web-browsing';
import { ChatMessage } from '@/types/message';
import { ChatStreamPayload, type OpenAIChatMessage } from '@/types/openai/chat';
import { LobeTool } from '@/types/tool';
@@ -480,6 +484,125 @@ describe('ChatService', () => {
expect(calls![1]).toBeUndefined();
});
});
describe('search functionality', () => {
it('should add WebBrowsingManifest when search is enabled and not using model built-in search', async () => {
const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
const messages = [{ content: 'Search for something', role: 'user' }] as ChatMessage[];
// Mock agent store state with search enabled
vi.spyOn(agentChatConfigSelectors, 'currentChatConfig').mockReturnValueOnce({
searchMode: 'auto', // not 'off'
useModelBuiltinSearch: false,
} as any);
// Mock AI infra store state
vi.spyOn(aiModelSelectors, 'isModelHasBuiltinSearch').mockReturnValueOnce(() => false);
vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValueOnce(() => false);
// Mock tool selectors
vi.spyOn(toolSelectors, 'enabledSchema').mockReturnValueOnce(() => [
{
type: 'function',
function: {
name: WebBrowsingManifest.identifier + '____search',
description: 'Search the web',
},
},
]);
await chatService.createAssistantMessage({ messages, plugins: [] });
// Verify tools were passed to getChatCompletion
expect(getChatCompletionSpy).toHaveBeenCalledWith(
expect.objectContaining({
tools: expect.arrayContaining([
expect.objectContaining({
function: expect.objectContaining({
name: expect.stringContaining(WebBrowsingManifest.identifier),
}),
}),
]),
}),
undefined,
);
});
it('should enable built-in search when model supports it and useModelBuiltinSearch is true', async () => {
const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
const messages = [{ content: 'Search for something', role: 'user' }] as ChatMessage[];
// Mock agent store state with search enabled and useModelBuiltinSearch enabled
vi.spyOn(agentChatConfigSelectors, 'currentChatConfig').mockReturnValueOnce({
searchMode: 'auto', // not 'off'
useModelBuiltinSearch: true,
} as any);
// Mock AI infra store state - model has built-in search
vi.spyOn(aiModelSelectors, 'isModelHasBuiltinSearch').mockReturnValueOnce(() => true);
vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValueOnce(() => false);
// Mock tool selectors
vi.spyOn(toolSelectors, 'enabledSchema').mockReturnValueOnce(() => [
{
type: 'function',
function: {
name: WebBrowsingManifest.identifier + '____search',
description: 'Search the web',
},
},
]);
await chatService.createAssistantMessage({ messages, plugins: [] });
// Verify enabledSearch was set to true
expect(getChatCompletionSpy).toHaveBeenCalledWith(
expect.objectContaining({
enabledSearch: true,
}),
undefined,
);
});
it('should not enable search when searchMode is off', async () => {
const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
const messages = [{ content: 'Search for something', role: 'user' }] as ChatMessage[];
// Mock agent store state with search disabled
vi.spyOn(agentChatConfigSelectors, 'currentChatConfig').mockReturnValueOnce({
searchMode: 'off',
useModelBuiltinSearch: true,
} as any);
// Mock AI infra store state
vi.spyOn(aiModelSelectors, 'isModelHasBuiltinSearch').mockReturnValueOnce(() => true);
vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValueOnce(() => false);
// Mock tool selectors
vi.spyOn(toolSelectors, 'enabledSchema').mockReturnValueOnce(() => [
{
type: 'function',
function: {
name: WebBrowsingManifest.identifier + '____search',
description: 'Search the web',
},
},
]);
await chatService.createAssistantMessage({ messages, plugins: [] });
// Verify enabledSearch was not set
expect(getChatCompletionSpy).toHaveBeenCalledWith(
expect.objectContaining({
enabledSearch: undefined,
}),
undefined,
);
});
});
});
describe('getChatCompletion', () => {
@@ -754,6 +877,7 @@ describe('ChatService', () => {
// 重新模拟模块,设置 isServerMode 为 true
vi.doMock('@/const/version', () => ({
isServerMode: true,
isDeprecatedEdition: false,
}));
// 需要在修改模拟后重新导入相关模块
+82 -49
View File
@@ -19,12 +19,7 @@ import { filesPrompts } from '@/prompts/files';
import { BuiltinSystemRolePrompts } from '@/prompts/systemRole';
import { getAgentStoreState } from '@/store/agent';
import { agentChatConfigSelectors } from '@/store/agent/selectors';
import {
aiModelSelectors,
aiProviderSelectors,
getAiInfraStoreState,
useAiInfraStore,
} from '@/store/aiInfra';
import { aiModelSelectors, aiProviderSelectors, getAiInfraStoreState } from '@/store/aiInfra';
import { getSessionStoreState } from '@/store/session';
import { sessionMetaSelectors } from '@/store/session/selectors';
import { getToolStoreState } from '@/store/tool';
@@ -37,6 +32,7 @@ import {
userProfileSelectors,
} from '@/store/user/selectors';
import { WebBrowsingManifest } from '@/tools/web-browsing';
import { WorkingModel } from '@/types/agent';
import { ChatErrorType } from '@/types/fetch';
import { ChatMessage, MessageToolCall } from '@/types/message';
import type { ChatStreamPayload, OpenAIChatMessage } from '@/types/openai/chat';
@@ -74,9 +70,9 @@ const findDeploymentName = (model: string, provider: string) => {
if (deploymentName) deploymentId = deploymentName;
} else {
// find the model by id
const modelItem = useAiInfraStore
.getState()
.enabledAiModels?.find((i) => i.id === model && i.providerId === provider);
const modelItem = getAiInfraStoreState().enabledAiModels?.find(
(i) => i.id === model && i.providerId === provider,
);
if (modelItem && modelItem.config?.deploymentName) {
deploymentId = modelItem.config?.deploymentName;
@@ -91,7 +87,7 @@ const isEnableFetchOnClient = (provider: string) => {
if (isDeprecatedEdition) {
return modelConfigSelectors.isProviderFetchOnClient(provider)(useUserStore.getState());
} else {
return aiProviderSelectors.isProviderFetchOnClient(provider)(useAiInfraStore.getState());
return aiProviderSelectors.isProviderFetchOnClient(provider)(getAiInfraStoreState());
}
};
@@ -181,10 +177,10 @@ class ChatService {
const isModelHasBuiltinSearch = aiModelSelectors.isModelHasBuiltinSearch(
payload.model,
payload.provider!,
)(useAiInfraStore.getState());
)(getAiInfraStoreState());
const useApplicationBuiltinSearchTool =
enabledSearch && !(isModelHasBuiltinSearch && chatConfig.useModelBuiltinSearch);
const useModelSearch = isModelHasBuiltinSearch && chatConfig.useModelBuiltinSearch;
const useApplicationBuiltinSearchTool = enabledSearch && !useModelSearch;
const pluginIds = [...(enabledPlugins || [])];
@@ -206,17 +202,10 @@ class ChatService {
// ============ 2. preprocess tools ============ //
let filterTools = toolSelectors.enabledSchema(pluginIds)(getToolStoreState());
// check this model can use function call
const canUseFC = isCanUseFC(payload.model, payload.provider!);
// the rule that model can use tools:
// 1. tools is not empty
// 2. model can use function call
const shouldUseTools = filterTools.length > 0 && canUseFC;
const tools = shouldUseTools ? filterTools : undefined;
const tools = this.prepareTools(pluginIds, {
model: payload.model,
provider: payload.provider!,
});
// ============ 3. process extend params ============ //
@@ -225,14 +214,14 @@ class ChatService {
const isModelHasExtendParams = aiModelSelectors.isModelHasExtendParams(
payload.model,
payload.provider!,
)(useAiInfraStore.getState());
)(getAiInfraStoreState());
// model
if (isModelHasExtendParams) {
const modelExtendParams = aiModelSelectors.modelExtendParams(
payload.model,
payload.provider!,
)(useAiInfraStore.getState());
)(getAiInfraStoreState());
// if model has extended params, then we need to check if the model can use reasoning
if (modelExtendParams!.includes('enableReasoning') && chatConfig.enableReasoning) {
@@ -241,13 +230,19 @@ class ChatService {
type: 'enabled',
};
}
if (
modelExtendParams!.includes('disableContextCaching') &&
chatConfig.disableContextCaching
) {
extendParams.enabledContextCaching = false;
}
}
return this.getChatCompletion(
{
...params,
...extendParams,
enabledSearch: enabledSearch && isModelHasBuiltinSearch ? true : undefined,
enabledSearch: enabledSearch && useModelSearch ? true : undefined,
messages: oaiMessages,
tools,
},
@@ -351,9 +346,8 @@ class ChatService {
// TODO: remove `!isDeprecatedEdition` condition in V2.0
if (!isDeprecatedEdition && !isBuiltin) {
const providerConfig = aiProviderSelectors.providerConfigById(provider)(
useAiInfraStore.getState(),
);
const providerConfig =
aiProviderSelectors.providerConfigById(provider)(getAiInfraStoreState());
sdkType = providerConfig?.settings.sdkType || 'openai';
}
@@ -433,15 +427,29 @@ class ChatService {
onLoadingChange?.(true);
try {
await this.getChatCompletion(params, {
onErrorHandle: (error) => {
errorHandle(new Error(error.message), error);
},
onFinish,
onMessageHandle,
signal: abortController?.signal,
trace: this.mapTrace(trace, TraceTagMap.SystemChain),
const oaiMessages = this.processMessages({
messages: params.messages as any,
model: params.model!,
provider: params.provider!,
tools: params.plugins,
});
const tools = this.prepareTools(params.plugins || [], {
model: params.model!,
provider: params.provider!,
});
await this.getChatCompletion(
{ ...params, messages: oaiMessages, tools },
{
onErrorHandle: (error) => {
errorHandle(new Error(error.message), error);
},
onFinish,
onMessageHandle,
signal: abortController?.signal,
trace: this.mapTrace(trace, TraceTagMap.SystemChain),
},
);
onLoadingChange?.(false);
} catch (e) {
@@ -451,7 +459,7 @@ class ChatService {
private processMessages = (
{
messages,
messages = [],
tools,
model,
provider,
@@ -483,6 +491,7 @@ class ChatService {
};
let postMessages = messages.map((m): OpenAIChatMessage => {
const supportTools = isCanUseFC(model, provider);
switch (m.role) {
case 'user': {
return { content: getContent(m), role: m.role };
@@ -492,17 +501,23 @@ class ChatService {
// signature is a signal of anthropic thinking mode
const shouldIncludeThinking = m.reasoning && !!m.reasoning?.signature;
const content = shouldIncludeThinking
? [
{
signature: m.reasoning!.signature,
thinking: m.reasoning!.content,
type: 'thinking',
} as any,
{ text: m.content, type: 'text' },
]
: m.content;
if (!supportTools) {
return { content, role: m.role };
}
return {
content: shouldIncludeThinking
? [
{
signature: m.reasoning!.signature,
thinking: m.reasoning!.content,
type: 'thinking',
} as any,
{ text: m.content, type: 'text' },
]
: m.content,
content,
role: m.role,
tool_calls: m.tools?.map(
(tool): MessageToolCall => ({
@@ -518,6 +533,10 @@ class ChatService {
}
case 'tool': {
if (!supportTools) {
return { content: m.content, role: 'user' };
}
return {
content: m.content,
name: genToolCallingName(m.plugin!.identifier, m.plugin!.apiName, m.plugin?.type),
@@ -669,6 +688,20 @@ class ChatService {
return reorderedMessages;
};
private prepareTools = (pluginIds: string[], { model, provider }: WorkingModel) => {
let filterTools = toolSelectors.enabledSchema(pluginIds)(getToolStoreState());
// check this model can use function call
const canUseFC = isCanUseFC(model, provider!);
// the rule that model can use tools:
// 1. tools is not empty
// 2. model can use function call
const shouldUseTools = filterTools.length > 0 && canUseFC;
return shouldUseTools ? filterTools : undefined;
};
}
export const chatService = new ChatService();
+1 -1
View File
@@ -53,7 +53,7 @@ export interface ISessionService {
updateSessionChatConfig(
id: string,
config: DeepPartial<LobeAgentChatConfig>,
config: Partial<LobeAgentChatConfig>,
signal?: AbortSignal,
): Promise<any>;
@@ -11,6 +11,10 @@ exports[`agentSelectors > defaultAgentConfig > should merge DEFAULT_AGENT_CONFIG
"enableReasoning": false,
"historyCount": 8,
"reasoningBudgetToken": 1024,
"searchFCModel": {
"model": "gpt-4o-mini",
"provider": "openai",
},
"searchMode": "off",
},
"model": "gpt-3.5-turbo",
@@ -1,5 +1,5 @@
import { contextCachingModels, thinkingWithToolClaudeModels } from '@/const/models';
import { DEFAULT_AGENT_CHAT_CONFIG } from '@/const/settings';
import { DEFAULT_AGENT_CHAT_CONFIG, DEFAULT_AGENT_SEARCH_FC_MODEL } from '@/const/settings';
import { AgentStoreState } from '@/store/agent/initialState';
import { LobeAgentChatConfig } from '@/types/agent';
@@ -14,6 +14,9 @@ const isAgentEnableSearch = (s: AgentStoreState) => agentSearchMode(s) !== 'off'
const useModelBuiltinSearch = (s: AgentStoreState) =>
currentAgentChatConfig(s).useModelBuiltinSearch;
const searchFCModel = (s: AgentStoreState) =>
currentAgentChatConfig(s).searchFCModel || DEFAULT_AGENT_SEARCH_FC_MODEL;
const enableHistoryCount = (s: AgentStoreState) => {
const config = currentAgentConfig(s);
const chatConfig = currentAgentChatConfig(s);
@@ -62,5 +65,6 @@ export const agentChatConfigSelectors = {
enableHistoryDivider,
historyCount,
isAgentEnableSearch,
searchFCModel,
useModelBuiltinSearch,
};
@@ -765,10 +765,12 @@ describe('chatMessage actions', () => {
(fetch as Mock).mockResolvedValueOnce(new Response(aiResponse));
await act(async () => {
const response = await result.current.internal_fetchAIChatMessage(
const response = await result.current.internal_fetchAIChatMessage({
messages,
assistantMessageId,
);
messageId: assistantMessageId,
model: 'gpt-4o-mini',
provider: 'openai',
});
expect(response.isFunctionCall).toEqual(false);
});
});
@@ -784,7 +786,13 @@ describe('chatMessage actions', () => {
await act(async () => {
expect(
await result.current.internal_fetchAIChatMessage(messages, assistantMessageId),
await result.current.internal_fetchAIChatMessage({
model: 'gpt-4o-mini',
provider: 'openai',
messages,
messageId: assistantMessageId,
}),
).toEqual({
isFunctionCall: false,
});
@@ -13,10 +13,13 @@ import { messageService } from '@/services/message';
import { useAgentStore } from '@/store/agent';
import { agentChatConfigSelectors, agentSelectors } from '@/store/agent/selectors';
import { getAgentStoreState } from '@/store/agent/store';
import { aiModelSelectors } from '@/store/aiInfra';
import { getAiInfraStoreState } from '@/store/aiInfra/store';
import { chatHelpers } from '@/store/chat/helpers';
import { ChatStore } from '@/store/chat/store';
import { messageMapKey } from '@/store/chat/utils/messageMapKey';
import { useSessionStore } from '@/store/session';
import { WebBrowsingManifest } from '@/tools/web-browsing';
import { ChatMessage, CreateMessageParams, SendMessageParams } from '@/types/message';
import { MessageSemanticSearchChunk } from '@/types/rag';
import { setNamespace } from '@/utils/storeDebug';
@@ -28,6 +31,7 @@ const n = setNamespace('ai');
interface ProcessMessageParams {
traceId?: string;
isWelcomeQuestion?: boolean;
inSearchWorkflow?: boolean;
/**
* the RAG query content, should be embedding and used in the semantic search
*/
@@ -70,11 +74,13 @@ export interface AIGenerateAction {
/**
* Retrieves an AI-generated chat message from the backend service
*/
internal_fetchAIChatMessage: (
messages: ChatMessage[],
messageId: string,
params?: ProcessMessageParams,
) => Promise<{
internal_fetchAIChatMessage: (input: {
messages: ChatMessage[];
messageId: string;
params?: ProcessMessageParams;
model: string;
provider: string;
}) => Promise<{
isFunctionCall: boolean;
traceId?: string;
}>;
@@ -110,6 +116,8 @@ export interface AIGenerateAction {
id?: string,
action?: string,
) => AbortController | undefined;
internal_toggleSearchWorkflow: (loading: boolean, id?: string) => void;
}
export const generateAIChat: StateCreator<
@@ -336,10 +344,97 @@ export const generateAIChat: StateCreator<
const assistantId = await get().internal_createMessage(assistantMessage);
// 3. fetch the AI response
const { isFunctionCall } = await internal_fetchAIChatMessage(messages, assistantId, params);
// 3. place a search with the search working model if this model is not support tool use
const isModelSupportToolUse = aiModelSelectors.isModelSupportToolUse(
model,
provider!,
)(getAiInfraStoreState());
const isAgentEnableSearch = agentChatConfigSelectors.isAgentEnableSearch(getAgentStoreState());
// 4. if it's the function call message, trigger the function method
if (isAgentEnableSearch && !isModelSupportToolUse) {
const { model, provider } = agentChatConfigSelectors.searchFCModel(getAgentStoreState());
let isToolsCalling = false;
let isError = false;
const abortController = get().internal_toggleChatLoading(
true,
assistantId,
n('generateMessage(start)', { messageId: assistantId, messages }) as string,
);
get().internal_toggleSearchWorkflow(true, assistantId);
await chatService.fetchPresetTaskResult({
params: { messages, model, provider, plugins: [WebBrowsingManifest.identifier] },
onFinish: async (_, { toolCalls, usage }) => {
if (toolCalls && toolCalls.length > 0) {
get().internal_toggleToolCallingStreaming(assistantId, undefined);
// update tools calling
await get().internal_updateMessageContent(assistantId, '', {
toolCalls,
metadata: usage,
model,
provider,
});
}
},
abortController,
onMessageHandle: async (chunk) => {
if (chunk.type === 'tool_calls') {
get().internal_toggleSearchWorkflow(false, assistantId);
get().internal_toggleToolCallingStreaming(assistantId, chunk.isAnimationActives);
get().internal_dispatchMessage({
id: assistantId,
type: 'updateMessage',
value: { tools: get().internal_transformToolCalls(chunk.tool_calls) },
});
isToolsCalling = true;
}
if (chunk.type === 'text') {
abortController!.abort('not fc');
}
},
onErrorHandle: async (error) => {
isError = true;
await messageService.updateMessageError(assistantId, error);
await refreshMessages();
},
});
get().internal_toggleChatLoading(
false,
assistantId,
n('generateMessage(start)', { messageId: assistantId, messages }) as string,
);
get().internal_toggleSearchWorkflow(false, assistantId);
// if there is error, then stop
if (isError) return;
// if it's the function call message, trigger the function method
if (isToolsCalling) {
await refreshMessages();
await triggerToolCalls(assistantId, {
threadId: params?.threadId,
inPortalThread: params?.inPortalThread,
});
// then story the workflow
return;
}
}
// 4. fetch the AI response
const { isFunctionCall } = await internal_fetchAIChatMessage({
messages,
messageId: assistantId,
params,
model,
provider: provider!,
});
// 5. if it's the function call message, trigger the function method
if (isFunctionCall) {
await refreshMessages();
await triggerToolCalls(assistantId, {
@@ -348,7 +443,7 @@ export const generateAIChat: StateCreator<
});
}
// 5. summary history if context messages is larger than historyCount
// 6. summary history if context messages is larger than historyCount
const historyCount = agentChatConfigSelectors.historyCount(getAgentStoreState());
if (
@@ -365,7 +460,7 @@ export const generateAIChat: StateCreator<
await get().internal_summaryHistory(historyMessages);
}
},
internal_fetchAIChatMessage: async (messages, messageId, params) => {
internal_fetchAIChatMessage: async ({ messages, messageId, params, provider, model }) => {
const {
internal_toggleChatLoading,
refreshMessages,
@@ -382,7 +477,7 @@ export const generateAIChat: StateCreator<
);
const agentConfig = agentSelectors.currentAgentConfig(getAgentStoreState());
const chatConfig = agentConfig.chatConfig;
const chatConfig = agentChatConfigSelectors.currentChatConfig(getAgentStoreState());
const compiler = template(chatConfig.inputTemplate, { interpolate: /{{([\S\s]+?)}}/g });
@@ -444,8 +539,8 @@ export const generateAIChat: StateCreator<
abortController,
params: {
messages: preprocessMsgs,
model: agentConfig.model,
provider: agentConfig.provider,
model,
provider,
...agentConfig.params,
plugins: agentConfig.plugins,
},
@@ -529,6 +624,7 @@ export const generateAIChat: StateCreator<
});
break;
}
case 'reasoning': {
// if there is no thinkingStartAt, it means the start of reasoning
if (!thinkingStartAt) {
@@ -639,4 +735,8 @@ export const generateAIChat: StateCreator<
`toggleToolCallingStreaming/${!!streaming ? 'start' : 'end'}`,
);
},
internal_toggleSearchWorkflow: (loading, id) => {
return get().internal_toggleLoadingArrays('searchWorkflowLoadingIds', loading, id);
},
});
@@ -15,6 +15,7 @@ export interface ChatAIChatState {
* is the AI message is reasoning
*/
reasoningLoadingIds: string[];
searchWorkflowLoadingIds: string[];
/**
* the tool calling stream ids
*/
@@ -28,5 +29,6 @@ export const initialAiChatState: ChatAIChatState = {
messageRAGLoadingIds: [],
pluginApiLoadingIds: [],
reasoningLoadingIds: [],
searchWorkflowLoadingIds: [],
toolCallingStreamIds: {},
};
+8 -1
View File
@@ -1,9 +1,16 @@
import type { ChatStoreState } from '../../initialState';
const isMessageInReasoning = (id: string) => (s: ChatStoreState) =>
s.reasoningLoadingIds.includes(id);
const isMessageInSearchWorkflow = (id: string) => (s: ChatStoreState) =>
s.searchWorkflowLoadingIds.includes(id);
const isIntentUnderstanding = (id: string) => (s: ChatStoreState) =>
isMessageInSearchWorkflow(id)(s);
export const aiChatSelectors = {
isIntentUnderstanding,
isMessageInReasoning,
isMessageInSearchWorkflow,
};

Some files were not shown because too many files have changed in this diff Show More