@lobehub/chat 1.90.3 → 1.91.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/.cursor/rules/backend-architecture.mdc +12 -9
  2. package/.cursor/rules/cursor-ux-optimize.mdc +1 -1
  3. package/.cursor/rules/define-database-model.mdc +1 -1
  4. package/.cursor/rules/drizzle-schema-style-guide.mdc +1 -1
  5. package/.cursor/rules/i18n/i18n.mdc +1 -1
  6. package/.cursor/rules/project-introduce.mdc +2 -1
  7. package/.cursor/rules/system-role.mdc +42 -0
  8. package/.cursor/rules/zustand-action-patterns.mdc +318 -0
  9. package/.cursor/rules/zustand-slice-organization.mdc +300 -0
  10. package/CHANGELOG.md +66 -0
  11. package/README.md +2 -2
  12. package/README.zh-CN.md +2 -2
  13. package/changelog/v1.json +24 -0
  14. package/docs/self-hosting/advanced/model-list.mdx +1 -1
  15. package/docs/self-hosting/advanced/model-list.zh-CN.mdx +1 -1
  16. package/docs/self-hosting/environment-variables/model-provider.mdx +2 -2
  17. package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +2 -2
  18. package/package.json +44 -44
  19. package/packages/web-crawler/src/crawImpl/exa.ts +93 -0
  20. package/packages/web-crawler/src/crawImpl/firecrawl.ts +97 -0
  21. package/packages/web-crawler/src/crawImpl/index.ts +6 -0
  22. package/packages/web-crawler/src/crawImpl/tavily.ts +94 -0
  23. package/src/config/aiModels/modelscope.ts +3 -3
  24. package/src/config/modelProviders/modelscope.ts +3 -3
  25. package/src/database/client/migrations.json +10 -0
  26. package/src/database/migrations/0023_remove_param_and_doubao.sql +6 -0
  27. package/src/database/migrations/meta/0023_snapshot.json +5340 -0
  28. package/src/database/migrations/meta/_journal.json +7 -0
  29. package/src/features/PluginsUI/Render/utils/iframeOnReady.test.ts +1 -1
  30. package/src/features/PluginsUI/Render/utils/pluginSettings.test.ts +1 -1
  31. package/src/features/PluginsUI/Render/utils/pluginState.test.ts +1 -1
  32. package/src/libs/model-runtime/BaseAI.ts +3 -3
  33. package/src/libs/model-runtime/ModelRuntime.ts +2 -2
  34. package/src/libs/model-runtime/UniformRuntime/index.ts +2 -2
  35. package/src/libs/model-runtime/ai21/index.ts +2 -2
  36. package/src/libs/model-runtime/ai360/index.ts +2 -2
  37. package/src/libs/model-runtime/anthropic/index.ts +15 -11
  38. package/src/libs/model-runtime/azureOpenai/index.ts +2 -2
  39. package/src/libs/model-runtime/azureai/index.ts +4 -4
  40. package/src/libs/model-runtime/baichuan/index.ts +2 -2
  41. package/src/libs/model-runtime/bedrock/index.ts +4 -4
  42. package/src/libs/model-runtime/cloudflare/index.ts +2 -2
  43. package/src/libs/model-runtime/cohere/index.ts +2 -2
  44. package/src/libs/model-runtime/deepseek/index.ts +2 -2
  45. package/src/libs/model-runtime/fireworksai/index.ts +2 -2
  46. package/src/libs/model-runtime/giteeai/index.ts +2 -2
  47. package/src/libs/model-runtime/github/index.ts +2 -2
  48. package/src/libs/model-runtime/google/index.ts +7 -5
  49. package/src/libs/model-runtime/groq/index.ts +2 -2
  50. package/src/libs/model-runtime/higress/index.ts +2 -2
  51. package/src/libs/model-runtime/huggingface/index.ts +2 -2
  52. package/src/libs/model-runtime/hunyuan/index.ts +2 -2
  53. package/src/libs/model-runtime/index.ts +1 -1
  54. package/src/libs/model-runtime/infiniai/index.ts +2 -2
  55. package/src/libs/model-runtime/internlm/index.ts +7 -9
  56. package/src/libs/model-runtime/jina/index.ts +2 -2
  57. package/src/libs/model-runtime/lmstudio/index.ts +2 -2
  58. package/src/libs/model-runtime/minimax/index.ts +2 -2
  59. package/src/libs/model-runtime/mistral/index.ts +2 -2
  60. package/src/libs/model-runtime/modelscope/index.ts +2 -3
  61. package/src/libs/model-runtime/moonshot/index.ts +2 -2
  62. package/src/libs/model-runtime/novita/index.ts +2 -2
  63. package/src/libs/model-runtime/nvidia/index.ts +2 -2
  64. package/src/libs/model-runtime/ollama/index.ts +2 -2
  65. package/src/libs/model-runtime/openai/index.ts +3 -3
  66. package/src/libs/model-runtime/openrouter/index.ts +2 -2
  67. package/src/libs/model-runtime/perplexity/index.ts +2 -2
  68. package/src/libs/model-runtime/ppio/index.ts +2 -2
  69. package/src/libs/model-runtime/qiniu/index.ts +2 -2
  70. package/src/libs/model-runtime/qwen/index.ts +2 -2
  71. package/src/libs/model-runtime/sambanova/index.ts +2 -2
  72. package/src/libs/model-runtime/search1api/index.ts +2 -2
  73. package/src/libs/model-runtime/sensenova/index.ts +2 -2
  74. package/src/libs/model-runtime/siliconcloud/index.ts +2 -2
  75. package/src/libs/model-runtime/spark/index.ts +15 -13
  76. package/src/libs/model-runtime/stepfun/index.ts +2 -2
  77. package/src/libs/model-runtime/taichu/index.ts +2 -2
  78. package/src/libs/model-runtime/tencentcloud/index.ts +2 -2
  79. package/src/libs/model-runtime/togetherai/index.ts +2 -2
  80. package/src/libs/model-runtime/types/chat.ts +1 -1
  81. package/src/libs/model-runtime/upstage/index.ts +2 -2
  82. package/src/libs/model-runtime/utils/openaiCompatibleFactory/index.test.ts +7 -7
  83. package/src/libs/model-runtime/utils/openaiCompatibleFactory/index.ts +3 -3
  84. package/src/libs/model-runtime/vllm/index.ts +2 -2
  85. package/src/libs/model-runtime/volcengine/index.ts +2 -2
  86. package/src/libs/model-runtime/wenxin/index.ts +2 -2
  87. package/src/libs/model-runtime/xai/index.ts +6 -3
  88. package/src/libs/model-runtime/xinference/index.ts +2 -2
  89. package/src/libs/model-runtime/zeroone/index.ts +2 -2
  90. package/src/libs/model-runtime/zhipu/index.ts +2 -2
  91. package/src/middleware.ts +3 -1
  92. package/src/server/routers/tools/search.test.ts +2 -4
  93. package/src/server/services/search/impls/bocha/index.ts +124 -0
  94. package/src/server/services/search/impls/bocha/type.ts +47 -0
  95. package/src/server/services/search/impls/exa/index.ts +129 -0
  96. package/src/server/services/search/impls/exa/type.ts +39 -0
  97. package/src/server/services/search/impls/firecrawl/index.ts +128 -0
  98. package/src/server/services/search/impls/firecrawl/type.ts +35 -0
  99. package/src/server/services/search/impls/index.ts +31 -0
  100. package/src/server/services/search/impls/jina/index.ts +109 -0
  101. package/src/server/services/search/impls/jina/type.ts +26 -0
  102. package/src/server/services/search/impls/tavily/index.ts +124 -0
  103. package/src/server/services/search/impls/tavily/type.ts +36 -0
  104. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +4 -2
  105. package/src/store/chat/slices/message/action.test.ts +2 -1
  106. package/src/store/chat/slices/topic/action.test.ts +3 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.90.3",
3
+ "version": "1.91.0",
4
4
  "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.",
5
5
  "keywords": [
6
6
  "framework",
@@ -123,15 +123,15 @@
123
123
  "@ant-design/pro-components": "^2.8.7",
124
124
  "@anthropic-ai/sdk": "^0.51.0",
125
125
  "@auth/core": "^0.38.0",
126
- "@aws-sdk/client-bedrock-runtime": "^3.812.0",
127
- "@aws-sdk/client-s3": "^3.812.0",
128
- "@aws-sdk/s3-request-presigner": "^3.812.0",
126
+ "@aws-sdk/client-bedrock-runtime": "^3.821.0",
127
+ "@aws-sdk/client-s3": "^3.821.0",
128
+ "@aws-sdk/s3-request-presigner": "^3.821.0",
129
129
  "@azure-rest/ai-inference": "1.0.0-beta.5",
130
130
  "@azure/core-auth": "^1.9.0",
131
131
  "@cfworker/json-schema": "^4.1.1",
132
- "@clerk/localizations": "^3.16.0",
133
- "@clerk/nextjs": "^6.19.4",
134
- "@clerk/themes": "^2.2.45",
132
+ "@clerk/localizations": "^3.16.3",
133
+ "@clerk/nextjs": "^6.20.2",
134
+ "@clerk/themes": "^2.2.48",
135
135
  "@codesandbox/sandpack-react": "^2.20.0",
136
136
  "@cyntler/react-doc-viewer": "^1.17.0",
137
137
  "@electric-sql/pglite": "0.2.17",
@@ -140,7 +140,7 @@
140
140
  "@huggingface/inference": "^2.8.1",
141
141
  "@icons-pack/react-simple-icons": "9.6.0",
142
142
  "@khmyznikov/pwa-install": "0.3.9",
143
- "@langchain/community": "^0.3.43",
143
+ "@langchain/community": "^0.3.45",
144
144
  "@lobechat/electron-client-ipc": "workspace:*",
145
145
  "@lobechat/electron-server-ipc": "workspace:*",
146
146
  "@lobechat/file-loaders": "workspace:*",
@@ -148,21 +148,21 @@
148
148
  "@lobehub/charts": "^2.0.0",
149
149
  "@lobehub/chat-plugin-sdk": "^1.32.4",
150
150
  "@lobehub/chat-plugins-gateway": "^1.9.0",
151
- "@lobehub/icons": "^2.0.0",
151
+ "@lobehub/icons": "^2.2.0",
152
152
  "@lobehub/tts": "^2.0.1",
153
- "@lobehub/ui": "^2.1.7",
154
- "@modelcontextprotocol/sdk": "^1.11.4",
153
+ "@lobehub/ui": "^2.1.15",
154
+ "@modelcontextprotocol/sdk": "^1.12.1",
155
155
  "@neondatabase/serverless": "^1.0.0",
156
- "@next/third-parties": "^15.3.2",
156
+ "@next/third-parties": "^15.3.3",
157
157
  "@react-spring/web": "^9.7.5",
158
158
  "@sentry/nextjs": "^7.120.3",
159
159
  "@serwist/next": "^9.0.14",
160
160
  "@t3-oss/env-nextjs": "^0.12.0",
161
- "@tanstack/react-query": "^5.76.1",
162
- "@trpc/client": "^11.1.2",
163
- "@trpc/next": "^11.1.2",
164
- "@trpc/react-query": "^11.1.2",
165
- "@trpc/server": "^11.1.2",
161
+ "@tanstack/react-query": "^5.79.0",
162
+ "@trpc/client": "^11.2.0",
163
+ "@trpc/next": "^11.1.4",
164
+ "@trpc/react-query": "^11.2.0",
165
+ "@trpc/server": "^11.2.0",
166
166
  "@vercel/analytics": "^1.5.0",
167
167
  "@vercel/edge-config": "^1.4.0",
168
168
  "@vercel/functions": "^2.1.0",
@@ -170,7 +170,7 @@
170
170
  "@xterm/xterm": "^5.5.0",
171
171
  "ahooks": "^3.8.5",
172
172
  "ai": "^3.4.33",
173
- "antd": "^5.25.2",
173
+ "antd": "^5.25.4",
174
174
  "antd-style": "^3.7.1",
175
175
  "brotli-wasm": "^3.0.1",
176
176
  "chroma-js": "^3.1.2",
@@ -184,7 +184,7 @@
184
184
  "epub2": "^3.0.2",
185
185
  "fast-deep-equal": "^3.1.3",
186
186
  "file-type": "^20.5.0",
187
- "framer-motion": "^12.12.1",
187
+ "framer-motion": "^12.15.0",
188
188
  "gpt-tokenizer": "^2.9.0",
189
189
  "html-to-text": "^9.0.5",
190
190
  "i18next": "^24.2.3",
@@ -193,19 +193,19 @@
193
193
  "idb-keyval": "^6.2.2",
194
194
  "immer": "^10.1.1",
195
195
  "jose": "^5.10.0",
196
- "js-sha256": "^0.11.0",
196
+ "js-sha256": "^0.11.1",
197
197
  "jsonl-parse-stringify": "^1.0.3",
198
198
  "keyv": "^4.5.4",
199
- "langchain": "^0.3.26",
200
- "langfuse": "^3.37.2",
201
- "langfuse-core": "^3.37.2",
199
+ "langchain": "^0.3.27",
200
+ "langfuse": "^3.37.3",
201
+ "langfuse-core": "^3.37.3",
202
202
  "lodash-es": "^4.17.21",
203
203
  "lucide-react": "^0.509.0",
204
- "mammoth": "^1.9.0",
204
+ "mammoth": "^1.9.1",
205
205
  "mdast-util-to-markdown": "^2.1.2",
206
206
  "modern-screenshot": "^4.6.0",
207
207
  "nanoid": "^5.1.5",
208
- "next": "^15.3.2",
208
+ "next": "^15.3.3",
209
209
  "next-auth": "5.0.0-beta.25",
210
210
  "next-mdx-remote": "^5.0.0",
211
211
  "nextjs-toploader": "^3.8.16",
@@ -213,8 +213,8 @@
213
213
  "nuqs": "^2.4.3",
214
214
  "officeparser": "^5.1.1",
215
215
  "oidc-provider": "^8.8.1",
216
- "ollama": "^0.5.15",
217
- "openai": "^4.100.0",
216
+ "ollama": "^0.5.16",
217
+ "openai": "^4.104.0",
218
218
  "openapi-fetch": "^0.9.8",
219
219
  "partial-json": "^0.1.7",
220
220
  "path-browserify-esm": "^1.0.6",
@@ -224,22 +224,22 @@
224
224
  "pino": "^9.7.0",
225
225
  "plaiceholder": "^3.0.0",
226
226
  "polished": "^4.3.1",
227
- "posthog-js": "^1.245.0",
227
+ "posthog-js": "^1.249.0",
228
228
  "pwa-install-handler": "^2.6.2",
229
- "query-string": "^9.1.2",
229
+ "query-string": "^9.2.0",
230
230
  "random-words": "^2.0.1",
231
231
  "react": "^19.1.0",
232
232
  "react-confetti": "^6.4.0",
233
233
  "react-dom": "^19.1.0",
234
234
  "react-fast-marquee": "^1.6.5",
235
235
  "react-hotkeys-hook": "^4.6.2",
236
- "react-i18next": "^15.5.1",
236
+ "react-i18next": "^15.5.2",
237
237
  "react-layout-kit": "^1.9.1",
238
238
  "react-lazy-load": "^4.0.1",
239
239
  "react-pdf": "^9.2.1",
240
240
  "react-rnd": "^10.5.2",
241
241
  "react-scan": "^0.3.4",
242
- "react-virtuoso": "^4.12.7",
242
+ "react-virtuoso": "^4.12.8",
243
243
  "react-wrap-balancer": "^1.1.1",
244
244
  "remark": "^15.0.1",
245
245
  "remark-gfm": "^4.0.1",
@@ -252,7 +252,7 @@
252
252
  "shiki": "^3.4.2",
253
253
  "stripe": "^16.12.0",
254
254
  "superjson": "^2.2.2",
255
- "svix": "^1.65.0",
255
+ "svix": "^1.66.0",
256
256
  "swr": "^2.3.3",
257
257
  "systemjs": "^6.15.1",
258
258
  "tokenx": "^0.4.1",
@@ -268,7 +268,7 @@
268
268
  "y-webrtc": "^10.3.0",
269
269
  "yaml": "^2.8.0",
270
270
  "yjs": "^13.6.27",
271
- "zod": "^3.25.7",
271
+ "zod": "^3.25.48",
272
272
  "zustand": "5.0.4",
273
273
  "zustand-utils": "^2.1.0"
274
274
  },
@@ -276,11 +276,11 @@
276
276
  "@commitlint/cli": "^19.8.1",
277
277
  "@edge-runtime/vm": "^5.0.0",
278
278
  "@huggingface/tasks": "^0.15.9",
279
- "@lobehub/i18n-cli": "^1.20.3",
280
- "@lobehub/lint": "^1.26.1",
281
- "@lobehub/seo-cli": "^1.4.3",
282
- "@next/bundle-analyzer": "^15.3.2",
283
- "@next/eslint-plugin-next": "^15.3.2",
279
+ "@lobehub/i18n-cli": "^1.22.0",
280
+ "@lobehub/lint": "^1.26.2",
281
+ "@lobehub/seo-cli": "^1.6.0",
282
+ "@next/bundle-analyzer": "^15.3.3",
283
+ "@next/eslint-plugin-next": "^15.3.3",
284
284
  "@peculiar/webcrypto": "^1.5.0",
285
285
  "@semantic-release/exec": "^6.0.3",
286
286
  "@testing-library/jest-dom": "^6.6.3",
@@ -293,13 +293,13 @@
293
293
  "@types/fs-extra": "^11.0.4",
294
294
  "@types/ip": "^1.1.3",
295
295
  "@types/json-schema": "^7.0.15",
296
- "@types/lodash": "^4.17.16",
296
+ "@types/lodash": "^4.17.17",
297
297
  "@types/lodash-es": "^4.17.12",
298
- "@types/node": "^22.15.19",
298
+ "@types/node": "^22.15.29",
299
299
  "@types/numeral": "^2.0.5",
300
300
  "@types/oidc-provider": "^8.8.1",
301
- "@types/pg": "^8.15.2",
302
- "@types/react": "^19.1.4",
301
+ "@types/pg": "^8.15.4",
302
+ "@types/react": "^19.1.6",
303
303
  "@types/react-dom": "^19.1.5",
304
304
  "@types/rtl-detect": "^1.0.3",
305
305
  "@types/semver": "^7.7.0",
@@ -325,7 +325,7 @@
325
325
  "fs-extra": "^11.3.0",
326
326
  "glob": "^11.0.2",
327
327
  "gray-matter": "^4.0.3",
328
- "happy-dom": "^17.4.7",
328
+ "happy-dom": "^17.5.6",
329
329
  "husky": "^9.1.7",
330
330
  "just-diff": "^6.0.2",
331
331
  "lint-staged": "^15.5.2",
@@ -351,7 +351,7 @@
351
351
  "unified": "^11.0.5",
352
352
  "unist-util-visit": "^5.0.0",
353
353
  "vite": "^5.4.19",
354
- "vitest": "^3.1.4",
354
+ "vitest": "^3.2.0",
355
355
  "vitest-canvas-mock": "^0.3.3"
356
356
  },
357
357
  "packageManager": "pnpm@10.10.0",
@@ -0,0 +1,93 @@
1
+ import { CrawlImpl, CrawlSuccessResult } from '../type';
2
+ import { NetworkConnectionError, PageNotFoundError, TimeoutError } from '../utils/errorType';
3
+ import { DEFAULT_TIMEOUT, withTimeout } from '../utils/withTimeout';
4
+
5
+ interface ExaResults {
6
+ author?: string;
7
+ favicon?: string;
8
+ id?: string;
9
+ image?: string;
10
+ publishedDate?: string;
11
+ summary?: string;
12
+ text: string;
13
+ title: string;
14
+ url: string;
15
+ }
16
+
17
+ interface ExaResponse {
18
+ requestId?: string;
19
+ results: ExaResults[];
20
+ }
21
+
22
+ export const exa: CrawlImpl = async (url) => {
23
+ // Get API key from environment variable
24
+ const apiKey = process.env.EXA_API_KEY;
25
+
26
+ let res: Response;
27
+
28
+ try {
29
+ res = await withTimeout(
30
+ fetch('https://api.exa.ai/contents', {
31
+ body: JSON.stringify({
32
+ livecrawl: 'fallback', // always, fallback
33
+ text: true,
34
+ urls: [url],
35
+ }),
36
+ headers: {
37
+ 'Content-Type': 'application/json',
38
+ 'x-api-key': !apiKey ? '' : apiKey,
39
+ },
40
+ method: 'POST',
41
+ }),
42
+ DEFAULT_TIMEOUT,
43
+ );
44
+ } catch (e) {
45
+ const error = e as Error;
46
+ if (error.message === 'fetch failed') {
47
+ throw new NetworkConnectionError();
48
+ }
49
+
50
+ if (error instanceof TimeoutError) {
51
+ throw error;
52
+ }
53
+
54
+ throw e;
55
+ }
56
+
57
+ if (!res.ok) {
58
+ if (res.status === 404) {
59
+ throw new PageNotFoundError(res.statusText);
60
+ }
61
+
62
+ throw new Error(`Exa request failed with status ${res.status}: ${res.statusText}`);
63
+ }
64
+
65
+ try {
66
+ const data = (await res.json()) as ExaResponse;
67
+
68
+ if (!data.results || data.results.length === 0) {
69
+ console.warn( 'Exa API returned no results for URL:', url )
70
+ return
71
+ }
72
+
73
+ const firstResult = data.results[0];
74
+
75
+ // Check if content is empty or too short
76
+ if (!firstResult.text || firstResult.text.length < 100) {
77
+ return;
78
+ }
79
+
80
+ return {
81
+ content: firstResult.text,
82
+ contentType: 'text',
83
+ length: firstResult.text.length,
84
+ siteName: new URL(url).hostname,
85
+ title: firstResult.title,
86
+ url: firstResult.url || url,
87
+ } satisfies CrawlSuccessResult;
88
+ } catch (error) {
89
+ console.error(error);
90
+ }
91
+
92
+ return;
93
+ };
@@ -0,0 +1,97 @@
1
+ import { CrawlImpl, CrawlSuccessResult } from '../type';
2
+ import { NetworkConnectionError, PageNotFoundError, TimeoutError } from '../utils/errorType';
3
+ import { DEFAULT_TIMEOUT, withTimeout } from '../utils/withTimeout';
4
+
5
+ interface FirecrawlMetadata {
6
+ description: string;
7
+ keywords: string;
8
+ language: string;
9
+ ogDescription?: string;
10
+ ogImage?: string;
11
+ ogLocaleAlternate?: string[];
12
+ ogSiteName?: string;
13
+ ogTitle?: string;
14
+ ogUrl?: string;
15
+ robots: string;
16
+ statusCode: number;
17
+ sourceURL: string;
18
+ title: string;
19
+ }
20
+
21
+ interface FirecrawlResults {
22
+ html?: string;
23
+ markdown?: string;
24
+ metadata: FirecrawlMetadata;
25
+ }
26
+
27
+ interface FirecrawlResponse {
28
+ success: boolean;
29
+ data: FirecrawlResults;
30
+ }
31
+
32
+ export const firecrawl: CrawlImpl = async (url) => {
33
+ // Get API key from environment variable
34
+ const apiKey = process.env.FIRECRAWL_API_KEY;
35
+ const baseUrl = process.env.FIRECRAWL_URL || 'https://api.firecrawl.dev/v1';
36
+
37
+ let res: Response;
38
+
39
+ try {
40
+ res = await withTimeout(
41
+ fetch(`${baseUrl}/scrape`, {
42
+ body: JSON.stringify({
43
+ formats: ["markdown"], // ["markdown", "html"]
44
+ url,
45
+ }),
46
+ headers: {
47
+ 'Authorization': !apiKey ? '' : `Bearer ${apiKey}`,
48
+ 'Content-Type': 'application/json',
49
+ },
50
+ method: 'POST',
51
+ }),
52
+ DEFAULT_TIMEOUT,
53
+ );
54
+ } catch (e) {
55
+ const error = e as Error;
56
+ if (error.message === 'fetch failed') {
57
+ throw new NetworkConnectionError();
58
+ }
59
+
60
+ if (error instanceof TimeoutError) {
61
+ throw error;
62
+ }
63
+
64
+ throw e;
65
+ }
66
+
67
+ if (!res.ok) {
68
+ if (res.status === 404) {
69
+ throw new PageNotFoundError(res.statusText);
70
+ }
71
+
72
+ throw new Error(`Firecrawl request failed with status ${res.status}: ${res.statusText}`);
73
+ }
74
+
75
+ try {
76
+ const data = (await res.json()) as FirecrawlResponse;
77
+
78
+ // Check if content is empty or too short
79
+ if (!data.data.markdown || data.data.markdown.length < 100) {
80
+ return;
81
+ }
82
+
83
+ return {
84
+ content: data.data.markdown,
85
+ contentType: 'text',
86
+ description: data.data.metadata.description,
87
+ length: data.data.markdown.length,
88
+ siteName: new URL(url).hostname,
89
+ title: data.data.metadata.title,
90
+ url: url,
91
+ } satisfies CrawlSuccessResult;
92
+ } catch (error) {
93
+ console.error(error);
94
+ }
95
+
96
+ return;
97
+ };
@@ -1,13 +1,19 @@
1
1
  import { browserless } from './browserless';
2
+ import { exa } from './exa';
3
+ import { firecrawl } from './firecrawl';
2
4
  import { jina } from './jina';
3
5
  import { naive } from './naive';
4
6
  import { search1api } from './search1api';
7
+ import { tavily } from './tavily';
5
8
 
6
9
  export const crawlImpls = {
7
10
  browserless,
11
+ exa,
12
+ firecrawl,
8
13
  jina,
9
14
  naive,
10
15
  search1api,
16
+ tavily,
11
17
  };
12
18
 
13
19
  export type CrawlImplType = keyof typeof crawlImpls;
@@ -0,0 +1,94 @@
1
+ import { CrawlImpl, CrawlSuccessResult } from '../type';
2
+ import { NetworkConnectionError, PageNotFoundError, TimeoutError } from '../utils/errorType';
3
+ import { DEFAULT_TIMEOUT, withTimeout } from '../utils/withTimeout';
4
+
5
+ interface TavilyResults {
6
+ images?: string[];
7
+ raw_content: string;
8
+ url: string;
9
+ }
10
+
11
+ interface TavilyFailedResults {
12
+ error?: string;
13
+ url: string;
14
+ }
15
+
16
+ interface TavilyResponse {
17
+ base_url: string;
18
+ failed_results?: TavilyFailedResults[];
19
+ response_time: number;
20
+ results: TavilyResults[];
21
+ }
22
+
23
+ export const tavily: CrawlImpl = async (url) => {
24
+ // Get API key from environment variable
25
+ const apiKey = process.env.TAVILY_API_KEY;
26
+
27
+ let res: Response;
28
+
29
+ try {
30
+ res = await withTimeout(
31
+ fetch('https://api.tavily.com/extract', {
32
+ body: JSON.stringify({
33
+ extract_depth: process.env.TAVILY_EXTRACT_DEPTH || 'basic', // basic or advanced
34
+ include_images: false,
35
+ urls: url,
36
+ }),
37
+ headers: {
38
+ 'Authorization': !apiKey ? '' : `Bearer ${apiKey}`,
39
+ 'Content-Type': 'application/json',
40
+ },
41
+ method: 'POST',
42
+ }),
43
+ DEFAULT_TIMEOUT,
44
+ );
45
+ } catch (e) {
46
+ const error = e as Error;
47
+ if (error.message === 'fetch failed') {
48
+ throw new NetworkConnectionError();
49
+ }
50
+
51
+ if (error instanceof TimeoutError) {
52
+ throw error;
53
+ }
54
+
55
+ throw e;
56
+ }
57
+
58
+ if (!res.ok) {
59
+ if (res.status === 404) {
60
+ throw new PageNotFoundError(res.statusText);
61
+ }
62
+
63
+ throw new Error(`Tavily request failed with status ${res.status}: ${res.statusText}`);
64
+ }
65
+
66
+ try {
67
+ const data = (await res.json()) as TavilyResponse;
68
+
69
+ if (!data.results || data.results.length === 0) {
70
+ console.warn( 'Tavily API returned no results for URL:', url )
71
+ return
72
+ }
73
+
74
+ const firstResult = data.results[0];
75
+
76
+ // Check if content is empty or too short
77
+ if (!firstResult.raw_content || firstResult.raw_content.length < 100) {
78
+ return;
79
+ }
80
+
81
+ return {
82
+ content: firstResult.raw_content,
83
+ contentType: 'text',
84
+ length: firstResult.raw_content.length,
85
+ siteName: new URL(url).hostname,
86
+ title: new URL(url).hostname,
87
+ url: firstResult.url || url,
88
+ } satisfies CrawlSuccessResult;
89
+ } catch (error) {
90
+ console.error(error);
91
+ }
92
+
93
+ return;
94
+ };
@@ -6,10 +6,10 @@ const modelscopeChatModels: AIChatModelCard[] = [
6
6
  functionCall: true,
7
7
  },
8
8
  contextWindowTokens: 131_072,
9
- description: 'DeepSeek-V3是DeepSeek第三代模型,在多项基准测试中表现优异。',
10
- displayName: 'DeepSeek-V3-0324',
9
+ description: 'DeepSeek R1 通过利用增加的计算资源和在后训练过程中引入算法优化机制,显著提高了其推理和推断能力的深度。该模型在各种基准评估中表现出色,包括数学、编程和一般逻辑方面。其整体性能现已接近领先模型,如 O3 和 Gemini 2.5 Pro。',
10
+ displayName: 'DeepSeek-R1-0528',
11
11
  enabled: true,
12
- id: 'deepseek-ai/DeepSeek-V3-0324',
12
+ id: 'deepseek-ai/DeepSeek-R1-0528',
13
13
  type: 'chat',
14
14
  },
15
15
  {
@@ -5,11 +5,11 @@ const ModelScope: ModelProviderCard = {
5
5
  chatModels: [
6
6
  {
7
7
  contextWindowTokens: 131_072,
8
- description: 'DeepSeek-V3是DeepSeek第三代模型,在多项基准测试中表现优异。',
9
- displayName: 'DeepSeek-V3-0324',
8
+ description: 'DeepSeek R1 通过利用增加的计算资源和在后训练过程中引入算法优化机制,显著提高了其推理和推断能力的深度。该模型在各种基准评估中表现出色,包括数学、编程和一般逻辑方面。其整体性能现已接近领先模型,如 O3 和 Gemini 2.5 Pro。',
9
+ displayName: 'DeepSeek-R1-0528',
10
10
  enabled: true,
11
11
  functionCall: true,
12
- id: 'deepseek-ai/DeepSeek-V3-0324',
12
+ id: 'deepseek-ai/DeepSeek-R1-0528',
13
13
  },
14
14
  {
15
15
  contextWindowTokens: 131_072,
@@ -479,5 +479,15 @@
479
479
  "bps": true,
480
480
  "folderMillis": 1746724476380,
481
481
  "hash": "0518cd9882f7ea38eb498b31c8dda73fb56bbc3aa55445ecbc7a9e716631d047"
482
+ },
483
+ {
484
+ "sql": [
485
+ "-- Custom SQL migration file, put your code below! --\nUPDATE agents SET chat_config = jsonb_set(chat_config, '{enableReasoningEffort}', 'false') WHERE chat_config ->> 'enableReasoningEffort' = 'true';\n",
486
+ "\nUPDATE agents SET params = params - 'reasoning_effort' WHERE params ? 'reasoning_effort';\n",
487
+ "\nDELETE FROM ai_providers WHERE id = 'doubao';"
488
+ ],
489
+ "bps": true,
490
+ "folderMillis": 1748925630721,
491
+ "hash": "15815e06e3b188933119f380ae12ef8694f2c5f8003cebb397ed00053a065be4"
482
492
  }
483
493
  ]
@@ -0,0 +1,6 @@
1
+ -- Custom SQL migration file, put your code below! --
2
+ UPDATE agents SET chat_config = jsonb_set(chat_config, '{enableReasoningEffort}', 'false') WHERE chat_config ->> 'enableReasoningEffort' = 'true';
3
+ --> statement-breakpoint
4
+ UPDATE agents SET params = params - 'reasoning_effort' WHERE params ? 'reasoning_effort';
5
+ --> statement-breakpoint
6
+ DELETE FROM ai_providers WHERE id = 'doubao';