@lobehub/chat 1.61.3 → 1.61.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.61.4](https://github.com/lobehub/lobe-chat/compare/v1.61.3...v1.61.4)
6
+
7
+ <sup>Released on **2025-02-18**</sup>
8
+
9
+ #### 💄 Styles
10
+
11
+ - **misc**: Improve perplexity models.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Styles
19
+
20
+ - **misc**: Improve perplexity models, closes [#6307](https://github.com/lobehub/lobe-chat/issues/6307) ([c99908d](https://github.com/lobehub/lobe-chat/commit/c99908d))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ### [Version 1.61.3](https://github.com/lobehub/lobe-chat/compare/v1.61.2...v1.61.3)
6
31
 
7
32
  <sup>Released on **2025-02-18**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "improvements": [
5
+ "Improve perplexity models."
6
+ ]
7
+ },
8
+ "date": "2025-02-18",
9
+ "version": "1.61.4"
10
+ },
2
11
  {
3
12
  "children": {
4
13
  "improvements": [
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "منتج API الجديد المدعوم من نموذج الاستدلال من DeepSeek."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "منتج API جديد مدعوم من نموذج الاستدلال DeepSeek."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "يوفر توازنًا بين الأداء والتكلفة، مناسب لمجموعة متنوعة من السيناريوهات."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "Нови API продукти, поддържани от модела за разсъждение на DeepSeek."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "Нов API продукт, поддържан от модела за разсъждение DeepSeek."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Баланс между производителност и разходи, подходящ за общи сценарии."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "Ein neues API-Produkt, das von DeepSeek-Inferenzmodellen unterstützt wird."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "Ein neues API-Produkt, das von dem DeepSeek-Inferenzmodell unterstützt wird."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Bietet ein ausgewogenes Verhältnis zwischen Leistung und Kosten, geeignet für allgemeine Szenarien."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "A new API product powered by the DeepSeek reasoning model."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "A new API product powered by the DeepSeek reasoning model."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Balances performance and cost, suitable for general scenarios."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "Nuevo producto API respaldado por el modelo de razonamiento de DeepSeek."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "Un nuevo producto API respaldado por el modelo de razonamiento DeepSeek."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Equilibrio entre rendimiento y costo, adecuado para escenarios generales."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "محصول جدید API که توسط مدل استدلال DeepSeek پشتیبانی می‌شود."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "محصول جدید API که توسط مدل استدلال DeepSeek پشتیبانی می‌شود."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "تعادل بین عملکرد و هزینه، مناسب برای سناریوهای عمومی."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "Nouveau produit API soutenu par le modèle de raisonnement DeepSeek."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "Nouveau produit API soutenu par le modèle de raisonnement DeepSeek."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Équilibre entre performance et coût, adapté à des scénarios généraux."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "Nuovo prodotto API supportato dal modello di ragionamento DeepSeek."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "Nuovo prodotto API supportato dal modello di ragionamento DeepSeek."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Equilibrio tra prestazioni e costi, adatto per scenari generali."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "DeepSeek推論モデルによってサポートされる新しいAPI製品です。"
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "DeepSeek推論モデルによってサポートされる新しいAPI製品。"
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "性能とコストのバランスを取り、一般的なシナリオに適しています。"
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "DeepSeek 추론 모델이 지원하는 새로운 API 제품입니다."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "DeepSeek 추론 모델이 지원하는 새로운 API 제품입니다."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "성능과 비용의 균형을 맞추어 일반적인 시나리오에 적합합니다."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "Een nieuw API-product ondersteund door het DeepSeek redeneringsmodel."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "Een nieuw API-product ondersteund door het DeepSeek redeneringsmodel."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Biedt een balans tussen prestaties en kosten, geschikt voor algemene scenario's."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "Nowy produkt API wspierany przez model wnioskowania DeepSeek."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "Nowy produkt API wspierany przez model wnioskowania DeepSeek."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Równoważy wydajność i koszty, odpowiedni do ogólnych scenariuszy."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "Novo produto API suportado pelo modelo de raciocínio da DeepSeek."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "Um novo produto de API suportado pelo modelo de raciocínio DeepSeek."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Equilibra desempenho e custo, adequado para cenários gerais."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "Новый API продукт, поддерживаемый моделью вывода DeepSeek."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "Новый API продукт, поддерживаемый моделью вывода DeepSeek."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Балансирует производительность и стоимость, подходит для общих сценариев."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "DeepSeek akıl yürütme modeli tarafından desteklenen yeni API ürünü."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "DeepSeek'in akıl yürütme modeli tarafından desteklenen yeni API ürünü."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Performans ve maliyet arasında denge sağlar, genel senaryolar için uygundur."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "Sản phẩm API mới được hỗ trợ bởi mô hình suy luận của DeepSeek."
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "Sản phẩm API mới được hỗ trợ bởi mô hình suy diễn DeepSeek."
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "Cân bằng hiệu suất và chi phí, phù hợp cho các tình huống chung."
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "由 DeepSeek 推理模型提供支持的新 API 产品。"
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "由 DeepSeek 推理模型提供支持的新 API 产品。"
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "平衡性能与成本,适合一般场景。"
1582
1585
  },
@@ -1577,6 +1577,9 @@
1577
1577
  "sonar-reasoning": {
1578
1578
  "description": "由 DeepSeek 推理模型提供支持的新 API 產品。"
1579
1579
  },
1580
+ "sonar-reasoning-pro": {
1581
+ "description": "由 DeepSeek 推理模型提供支援的新 API 產品。"
1582
+ },
1580
1583
  "step-1-128k": {
1581
1584
  "description": "平衡性能與成本,適合一般場景。"
1582
1585
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.61.3",
3
+ "version": "1.61.4",
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",
@@ -6,17 +6,28 @@ const perplexityChatModels: AIChatModelCard[] = [
6
6
  reasoning: true,
7
7
  },
8
8
  contextWindowTokens: 127_072,
9
- description:
10
- ' DeepSeek 推理模型提供支持的新 API 产品。',
9
+ description: '由 DeepSeek 推理模型提供支持的新 API 产品。',
10
+ displayName: 'Sonar Reasoning Pro',
11
+ enabled: true,
12
+ id: 'sonar-reasoning-pro',
13
+ maxOutput: 8192,
14
+ type: 'chat',
15
+ },
16
+ {
17
+ abilities: {
18
+ reasoning: true,
19
+ },
20
+ contextWindowTokens: 127_072,
21
+ description: '由 DeepSeek 推理模型提供支持的新 API 产品。',
11
22
  displayName: 'Sonar Reasoning',
12
23
  enabled: true,
13
24
  id: 'sonar-reasoning',
25
+ maxOutput: 8192,
14
26
  type: 'chat',
15
27
  },
16
28
  {
17
29
  contextWindowTokens: 200_000,
18
- description:
19
- '支持搜索上下文的高级搜索产品,支持高级查询和跟进。',
30
+ description: '支持搜索上下文的高级搜索产品,支持高级查询和跟进。',
20
31
  displayName: 'Sonar Pro',
21
32
  enabled: true,
22
33
  id: 'sonar-pro',
@@ -24,8 +35,7 @@ const perplexityChatModels: AIChatModelCard[] = [
24
35
  },
25
36
  {
26
37
  contextWindowTokens: 127_072,
27
- description:
28
- '基于搜索上下文的轻量级搜索产品,比 Sonar Pro 更快、更便宜。',
38
+ description: '基于搜索上下文的轻量级搜索产品,比 Sonar Pro 更快、更便宜。',
29
39
  displayName: 'Sonar',
30
40
  enabled: true,
31
41
  id: 'sonar',
@@ -5,24 +5,21 @@ const Perplexity: ModelProviderCard = {
5
5
  chatModels: [
6
6
  {
7
7
  contextWindowTokens: 127_072,
8
- description:
9
- '由 DeepSeek 推理模型提供支持的新 API 产品。',
8
+ description: '由 DeepSeek 推理模型提供支持的新 API 产品。',
10
9
  displayName: 'Sonar Reasoning',
11
10
  enabled: true,
12
11
  id: 'sonar-reasoning',
13
12
  },
14
13
  {
15
14
  contextWindowTokens: 200_000,
16
- description:
17
- '支持搜索上下文的高级搜索产品,支持高级查询和跟进。',
15
+ description: '支持搜索上下文的高级搜索产品,支持高级查询和跟进。',
18
16
  displayName: 'Sonar Pro',
19
17
  enabled: true,
20
18
  id: 'sonar-pro',
21
19
  },
22
20
  {
23
21
  contextWindowTokens: 127_072,
24
- description:
25
- '基于搜索上下文的轻量级搜索产品,比 Sonar Pro 更快、更便宜。',
22
+ description: '基于搜索上下文的轻量级搜索产品,比 Sonar Pro 更快、更便宜。',
26
23
  displayName: 'Sonar',
27
24
  enabled: true,
28
25
  id: 'sonar',
@@ -60,10 +57,16 @@ const Perplexity: ModelProviderCard = {
60
57
  placeholder: 'https://api.perplexity.ai',
61
58
  },
62
59
  settings: {
60
+ // perplexity doesn't support CORS
61
+ disableBrowserRequest: true,
63
62
  proxyUrl: {
64
63
  placeholder: 'https://api.perplexity.ai',
65
64
  },
66
65
  sdkType: 'openai',
66
+ smoothing: {
67
+ speed: 2,
68
+ text: true,
69
+ },
67
70
  },
68
71
  url: 'https://www.perplexity.ai',
69
72
  };
@@ -1,16 +1,18 @@
1
1
  // @vitest-environment node
2
- import OpenAI from 'openai';
3
- import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
3
 
5
- import { ChatStreamCallbacks, LobeOpenAICompatibleRuntime } from '@/libs/agent-runtime';
4
+ import { LobeOpenAICompatibleRuntime, ModelProvider } from '@/libs/agent-runtime';
5
+ import { testProvider } from '@/libs/agent-runtime/providerTestUtils';
6
6
 
7
- import * as debugStreamModule from '../utils/debugStream';
8
7
  import { LobePerplexityAI } from './index';
9
8
 
10
- const provider = 'perplexity';
11
- const defaultBaseURL = 'https://api.perplexity.ai';
12
- const bizErrorType = 'ProviderBizError';
13
- const invalidErrorType = 'InvalidProviderAPIKey';
9
+ testProvider({
10
+ Runtime: LobePerplexityAI,
11
+ provider: ModelProvider.Perplexity,
12
+ defaultBaseURL: 'https://api.perplexity.ai',
13
+ chatDebugEnv: 'DEBUG_PERPLEXITY_CHAT_COMPLETION',
14
+ chatModel: 'sonar',
15
+ });
14
16
 
15
17
  // Mock the console.error to avoid polluting test output
16
18
  vi.spyOn(console, 'error').mockImplementation(() => {});
@@ -31,221 +33,7 @@ afterEach(() => {
31
33
  });
32
34
 
33
35
  describe('LobePerplexityAI', () => {
34
- describe('init', () => {
35
- it('should correctly initialize with an API key', async () => {
36
- const instance = new LobePerplexityAI({ apiKey: 'test_api_key' });
37
- expect(instance).toBeInstanceOf(LobePerplexityAI);
38
- expect(instance.baseURL).toEqual(defaultBaseURL);
39
- });
40
- });
41
-
42
36
  describe('chat', () => {
43
- describe('Error', () => {
44
- it('should return OpenAIBizError with an openai error response when OpenAI.APIError is thrown', async () => {
45
- // Arrange
46
- const apiError = new OpenAI.APIError(
47
- 400,
48
- {
49
- status: 400,
50
- error: {
51
- message: 'Bad Request',
52
- },
53
- },
54
- 'Error message',
55
- {},
56
- );
57
-
58
- vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
59
-
60
- // Act
61
- try {
62
- await instance.chat({
63
- messages: [{ content: 'Hello', role: 'user' }],
64
- model: 'text-davinci-003',
65
- temperature: 0,
66
- });
67
- } catch (e) {
68
- expect(e).toEqual({
69
- endpoint: defaultBaseURL,
70
- error: {
71
- error: { message: 'Bad Request' },
72
- status: 400,
73
- },
74
- errorType: bizErrorType,
75
- provider,
76
- });
77
- }
78
- });
79
-
80
- it('should throw AgentRuntimeError with NoOpenAIAPIKey if no apiKey is provided', async () => {
81
- try {
82
- new LobePerplexityAI({});
83
- } catch (e) {
84
- expect(e).toEqual({ errorType: invalidErrorType });
85
- }
86
- });
87
-
88
- it('should return OpenAIBizError with the cause when OpenAI.APIError is thrown with cause', async () => {
89
- // Arrange
90
- const errorInfo = {
91
- stack: 'abc',
92
- cause: {
93
- message: 'api is undefined',
94
- },
95
- };
96
- const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
97
-
98
- vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
99
-
100
- // Act
101
- try {
102
- await instance.chat({
103
- messages: [{ content: 'Hello', role: 'user' }],
104
- model: 'text-davinci-003',
105
- temperature: 0,
106
- });
107
- } catch (e) {
108
- expect(e).toEqual({
109
- endpoint: defaultBaseURL,
110
- error: {
111
- cause: { message: 'api is undefined' },
112
- stack: 'abc',
113
- },
114
- errorType: bizErrorType,
115
- provider,
116
- });
117
- }
118
- });
119
-
120
- it('should return OpenAIBizError with an cause response with desensitize Url', async () => {
121
- // Arrange
122
- const errorInfo = {
123
- stack: 'abc',
124
- cause: { message: 'api is undefined' },
125
- };
126
- const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
127
-
128
- instance = new LobePerplexityAI({
129
- apiKey: 'test',
130
-
131
- baseURL: 'https://api.abc.com/v1',
132
- });
133
-
134
- vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
135
-
136
- // Act
137
- try {
138
- await instance.chat({
139
- messages: [{ content: 'Hello', role: 'user' }],
140
- model: 'gpt-3.5-turbo',
141
- temperature: 0,
142
- });
143
- } catch (e) {
144
- expect(e).toEqual({
145
- endpoint: 'https://api.***.com/v1',
146
- error: {
147
- cause: { message: 'api is undefined' },
148
- stack: 'abc',
149
- },
150
- errorType: bizErrorType,
151
- provider,
152
- });
153
- }
154
- });
155
-
156
- it('should throw an InvalidMoonshotAPIKey error type on 401 status code', async () => {
157
- // Mock the API call to simulate a 401 error
158
- const error = new Error('Unauthorized') as any;
159
- error.status = 401;
160
- vi.mocked(instance['client'].chat.completions.create).mockRejectedValue(error);
161
-
162
- try {
163
- await instance.chat({
164
- messages: [{ content: 'Hello', role: 'user' }],
165
- model: 'gpt-3.5-turbo',
166
- temperature: 0,
167
- });
168
- } catch (e) {
169
- // Expect the chat method to throw an error with InvalidMoonshotAPIKey
170
- expect(e).toEqual({
171
- endpoint: defaultBaseURL,
172
- error: new Error('Unauthorized'),
173
- errorType: invalidErrorType,
174
- provider,
175
- });
176
- }
177
- });
178
-
179
- it('should return AgentRuntimeError for non-OpenAI errors', async () => {
180
- // Arrange
181
- const genericError = new Error('Generic Error');
182
-
183
- vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(genericError);
184
-
185
- // Act
186
- try {
187
- await instance.chat({
188
- messages: [{ content: 'Hello', role: 'user' }],
189
- model: 'text-davinci-003',
190
- temperature: 0,
191
- });
192
- } catch (e) {
193
- expect(e).toEqual({
194
- endpoint: defaultBaseURL,
195
- errorType: 'AgentRuntimeError',
196
- provider,
197
- error: {
198
- name: genericError.name,
199
- cause: genericError.cause,
200
- message: genericError.message,
201
- stack: genericError.stack,
202
- },
203
- });
204
- }
205
- });
206
- });
207
-
208
- describe('DEBUG', () => {
209
- it('should call debugStream and return StreamingTextResponse when DEBUG_PERPLEXITY_CHAT_COMPLETION is 1', async () => {
210
- // Arrange
211
- const mockProdStream = new ReadableStream() as any; // 模拟的 prod 流
212
- const mockDebugStream = new ReadableStream({
213
- start(controller) {
214
- controller.enqueue('Debug stream content');
215
- controller.close();
216
- },
217
- }) as any;
218
- mockDebugStream.toReadableStream = () => mockDebugStream; // 添加 toReadableStream 方法
219
-
220
- // 模拟 chat.completions.create 返回值,包括模拟的 tee 方法
221
- (instance['client'].chat.completions.create as Mock).mockResolvedValue({
222
- tee: () => [mockProdStream, { toReadableStream: () => mockDebugStream }],
223
- });
224
-
225
- // 保存原始环境变量值
226
- const originalDebugValue = process.env.DEBUG_PERPLEXITY_CHAT_COMPLETION;
227
-
228
- // 模拟环境变量
229
- process.env.DEBUG_PERPLEXITY_CHAT_COMPLETION = '1';
230
- vi.spyOn(debugStreamModule, 'debugStream').mockImplementation(() => Promise.resolve());
231
-
232
- // 执行测试
233
- // 运行你的测试函数,确保它会在条件满足时调用 debugStream
234
- // 假设的测试函数调用,你可能需要根据实际情况调整
235
- await instance.chat({
236
- messages: [{ content: 'Hello', role: 'user' }],
237
- model: 'text-davinci-003',
238
- temperature: 0,
239
- });
240
-
241
- // 验证 debugStream 被调用
242
- expect(debugStreamModule.debugStream).toHaveBeenCalled();
243
-
244
- // 恢复原始环境变量值
245
- process.env.DEBUG_PERPLEXITY_CHAT_COMPLETION = originalDebugValue;
246
- });
247
- });
248
-
249
37
  it('should call chat method with temperature', async () => {
250
38
  vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(
251
39
  new ReadableStream() as any,