@lobehub/lobehub 2.0.0-next.100 → 2.0.0-next.102

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 (40) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +50 -0
  3. package/CLAUDE.md +1 -0
  4. package/changelog/v1.json +18 -0
  5. package/package.json +1 -1
  6. package/packages/model-bank/package.json +1 -0
  7. package/packages/model-bank/src/aiModels/aihubmix.ts +27 -0
  8. package/packages/model-bank/src/aiModels/google.ts +69 -10
  9. package/packages/model-bank/src/aiModels/index.ts +3 -0
  10. package/packages/model-bank/src/aiModels/infiniai.ts +5 -22
  11. package/packages/model-bank/src/aiModels/ollamacloud.ts +12 -0
  12. package/packages/model-bank/src/aiModels/siliconcloud.ts +0 -61
  13. package/packages/model-bank/src/aiModels/vertexai.ts +88 -1
  14. package/packages/model-bank/src/aiModels/zenmux.ts +1423 -0
  15. package/packages/model-bank/src/const/modelProvider.ts +1 -0
  16. package/packages/model-bank/src/standard-parameters/index.ts +9 -0
  17. package/packages/model-runtime/src/core/RouterRuntime/createRuntime.ts +42 -18
  18. package/packages/model-runtime/src/core/openaiCompatibleFactory/index.test.ts +2 -2
  19. package/packages/model-runtime/src/core/streams/bedrock/claude.ts +17 -3
  20. package/packages/model-runtime/src/core/streams/google/index.ts +7 -2
  21. package/packages/model-runtime/src/core/streams/openai/__snapshots__/responsesStream.test.ts.snap +166 -166
  22. package/packages/model-runtime/src/index.ts +1 -1
  23. package/packages/model-runtime/src/providers/anthropic/index.ts +1 -38
  24. package/packages/model-runtime/src/providers/anthropic/resolveCacheTTL.ts +44 -0
  25. package/packages/model-runtime/src/providers/bedrock/index.test.ts +127 -11
  26. package/packages/model-runtime/src/providers/bedrock/index.ts +47 -13
  27. package/packages/model-runtime/src/providers/google/createImage.ts +1 -0
  28. package/packages/model-runtime/src/providers/google/index.ts +11 -1
  29. package/packages/model-runtime/src/providers/zenmux/index.test.ts +320 -0
  30. package/packages/model-runtime/src/providers/zenmux/index.ts +84 -0
  31. package/packages/model-runtime/src/runtimeMap.ts +2 -0
  32. package/packages/types/src/user/settings/keyVaults.ts +1 -0
  33. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/ResolutionSelect.tsx +88 -0
  34. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/index.tsx +9 -0
  35. package/src/config/modelProviders/index.ts +3 -0
  36. package/src/config/modelProviders/zenmux.ts +21 -0
  37. package/src/envs/llm.ts +6 -0
  38. package/src/locales/default/image.ts +8 -0
  39. package/src/store/chat/slices/aiChat/actions/__tests__/conversationLifecycle.test.ts +3 -0
  40. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +11 -0
@@ -31,6 +31,7 @@ export { LobeQwenAI } from './providers/qwen';
31
31
  export { LobeStepfunAI } from './providers/stepfun';
32
32
  export { LobeTogetherAI } from './providers/togetherai';
33
33
  export { LobeVolcengineAI } from './providers/volcengine';
34
+ export { LobeZenMuxAI } from './providers/zenmux';
34
35
  export { LobeZeroOneAI } from './providers/zeroone';
35
36
  export { LobeZhipuAI } from './providers/zhipu';
36
37
  export * from './types';
@@ -40,4 +41,3 @@ export { AgentRuntimeError } from './utils/createError';
40
41
  export { getModelPropertyWithFallback } from './utils/getFallbackModelProperty';
41
42
  export { getModelPricing } from './utils/getModelPricing';
42
43
  export { parseDataUri } from './utils/uriParser';
43
-
@@ -21,6 +21,7 @@ import { MODEL_LIST_CONFIGS, processModelList } from '../../utils/modelParse';
21
21
  import { StreamingResponse } from '../../utils/response';
22
22
  import { createAnthropicGenerateObject } from './generateObject';
23
23
  import { handleAnthropicError } from './handleAnthropicError';
24
+ import { resolveCacheTTL } from './resolveCacheTTL';
24
25
 
25
26
  export interface AnthropicModelCard {
26
27
  created_at: string;
@@ -33,44 +34,6 @@ type anthropicTools = Anthropic.Tool | Anthropic.WebSearchTool20250305;
33
34
  const modelsWithSmallContextWindow = new Set(['claude-3-opus-20240229', 'claude-3-haiku-20240307']);
34
35
 
35
36
  const DEFAULT_BASE_URL = 'https://api.anthropic.com';
36
- const DEFAULT_CACHE_TTL = '5m' as const;
37
-
38
- type CacheTTL = Anthropic.Messages.CacheControlEphemeral['ttl'];
39
-
40
- /**
41
- * Resolves cache TTL from Anthropic payload or request settings
42
- * Returns the first valid TTL found in system messages or content blocks
43
- */
44
- const resolveCacheTTL = (
45
- requestPayload: ChatStreamPayload,
46
- anthropicPayload: Anthropic.MessageCreateParams,
47
- ): CacheTTL | undefined => {
48
- // Check system messages for cache TTL
49
- if (Array.isArray(anthropicPayload.system)) {
50
- for (const block of anthropicPayload.system) {
51
- const ttl = block.cache_control?.ttl;
52
- if (ttl) return ttl;
53
- }
54
- }
55
-
56
- // Check message content blocks for cache TTL
57
- for (const message of anthropicPayload.messages ?? []) {
58
- if (!Array.isArray(message.content)) continue;
59
-
60
- for (const block of message.content) {
61
- // Message content blocks might have cache_control property
62
- const ttl = ('cache_control' in block && block.cache_control?.ttl) as CacheTTL | undefined;
63
- if (ttl) return ttl;
64
- }
65
- }
66
-
67
- // Use default TTL if context caching is enabled
68
- if (requestPayload.enabledContextCaching) {
69
- return DEFAULT_CACHE_TTL;
70
- }
71
-
72
- return undefined;
73
- };
74
37
 
75
38
  interface AnthropicAIParams extends ClientOptions {
76
39
  id?: string;
@@ -0,0 +1,44 @@
1
+ import Anthropic from '@anthropic-ai/sdk';
2
+
3
+ import { ChatStreamPayload } from '../../types';
4
+
5
+ type CacheTTL = Anthropic.Messages.CacheControlEphemeral['ttl'];
6
+
7
+ const DEFAULT_CACHE_TTL = '5m' as const;
8
+
9
+ /**
10
+ * Resolves cache TTL from Anthropic payload or request settings.
11
+ * Returns the first valid TTL found in system messages or content blocks.
12
+ */
13
+ export const resolveCacheTTL = (
14
+ requestPayload: ChatStreamPayload,
15
+ anthropicPayload: {
16
+ messages: Anthropic.MessageCreateParams['messages'];
17
+ system: Anthropic.MessageCreateParams['system'];
18
+ },
19
+ ): CacheTTL | undefined => {
20
+ // Check system messages for cache TTL
21
+ if (Array.isArray(anthropicPayload.system)) {
22
+ for (const block of anthropicPayload.system) {
23
+ const ttl = block.cache_control?.ttl;
24
+ if (ttl) return ttl;
25
+ }
26
+ }
27
+
28
+ // Check message content blocks for cache TTL
29
+ for (const message of anthropicPayload.messages ?? []) {
30
+ if (!Array.isArray(message.content)) continue;
31
+
32
+ for (const block of message.content) {
33
+ const ttl = ('cache_control' in block && block.cache_control?.ttl) as CacheTTL | undefined;
34
+ if (ttl) return ttl;
35
+ }
36
+ }
37
+
38
+ // Use default TTL if context caching is enabled
39
+ if (requestPayload.enabledContextCaching) {
40
+ return DEFAULT_CACHE_TTL;
41
+ }
42
+
43
+ return undefined;
44
+ };
@@ -173,7 +173,18 @@ describe('LobeBedrockAI', () => {
173
173
  body: JSON.stringify({
174
174
  anthropic_version: 'bedrock-2023-05-31',
175
175
  max_tokens: 4096,
176
- messages: [{ content: 'Hello', role: 'user' }],
176
+ messages: [
177
+ {
178
+ content: [
179
+ {
180
+ cache_control: { type: 'ephemeral' },
181
+ text: 'Hello',
182
+ type: 'text',
183
+ },
184
+ ],
185
+ role: 'user',
186
+ },
187
+ ],
177
188
  temperature: 0,
178
189
  top_p: 1,
179
190
  }),
@@ -211,8 +222,25 @@ describe('LobeBedrockAI', () => {
211
222
  body: JSON.stringify({
212
223
  anthropic_version: 'bedrock-2023-05-31',
213
224
  max_tokens: 4096,
214
- messages: [{ content: 'Hello', role: 'user' }],
215
- system: 'You are an awesome greeter',
225
+ messages: [
226
+ {
227
+ content: [
228
+ {
229
+ cache_control: { type: 'ephemeral' },
230
+ text: 'Hello',
231
+ type: 'text',
232
+ },
233
+ ],
234
+ role: 'user',
235
+ },
236
+ ],
237
+ system: [
238
+ {
239
+ cache_control: { type: 'ephemeral' },
240
+ text: 'You are an awesome greeter',
241
+ type: 'text',
242
+ },
243
+ ],
216
244
  temperature: 0,
217
245
  top_p: 1,
218
246
  }),
@@ -248,7 +276,18 @@ describe('LobeBedrockAI', () => {
248
276
  body: JSON.stringify({
249
277
  anthropic_version: 'bedrock-2023-05-31',
250
278
  max_tokens: 2048,
251
- messages: [{ content: 'Hello', role: 'user' }],
279
+ messages: [
280
+ {
281
+ content: [
282
+ {
283
+ cache_control: { type: 'ephemeral' },
284
+ text: 'Hello',
285
+ type: 'text',
286
+ },
287
+ ],
288
+ role: 'user',
289
+ },
290
+ ],
252
291
  temperature: 0.25,
253
292
  top_p: 1,
254
293
  }),
@@ -327,7 +366,18 @@ describe('LobeBedrockAI', () => {
327
366
  body: JSON.stringify({
328
367
  anthropic_version: 'bedrock-2023-05-31',
329
368
  max_tokens: 4096,
330
- messages: [{ content: 'Hello', role: 'user' }],
369
+ messages: [
370
+ {
371
+ content: [
372
+ {
373
+ cache_control: { type: 'ephemeral' },
374
+ text: 'Hello',
375
+ type: 'text',
376
+ },
377
+ ],
378
+ role: 'user',
379
+ },
380
+ ],
331
381
  temperature: 0,
332
382
  }),
333
383
  contentType: 'application/json',
@@ -363,7 +413,18 @@ describe('LobeBedrockAI', () => {
363
413
  body: JSON.stringify({
364
414
  anthropic_version: 'bedrock-2023-05-31',
365
415
  max_tokens: 2048,
366
- messages: [{ content: 'Hello', role: 'user' }],
416
+ messages: [
417
+ {
418
+ content: [
419
+ {
420
+ cache_control: { type: 'ephemeral' },
421
+ text: 'Hello',
422
+ type: 'text',
423
+ },
424
+ ],
425
+ role: 'user',
426
+ },
427
+ ],
367
428
  temperature: 0.25,
368
429
  top_p: 1,
369
430
  }),
@@ -418,7 +479,18 @@ describe('LobeBedrockAI', () => {
418
479
  body: JSON.stringify({
419
480
  anthropic_version: 'bedrock-2023-05-31',
420
481
  max_tokens: 4096,
421
- messages: [{ content: 'Hello', role: 'user' }],
482
+ messages: [
483
+ {
484
+ content: [
485
+ {
486
+ cache_control: { type: 'ephemeral' },
487
+ text: 'Hello',
488
+ type: 'text',
489
+ },
490
+ ],
491
+ role: 'user',
492
+ },
493
+ ],
422
494
  temperature: 0.4, // temperature / 2, top_p omitted due to conflict
423
495
  }),
424
496
  contentType: 'application/json',
@@ -450,7 +522,18 @@ describe('LobeBedrockAI', () => {
450
522
  body: JSON.stringify({
451
523
  anthropic_version: 'bedrock-2023-05-31',
452
524
  max_tokens: 4096,
453
- messages: [{ content: 'Hello', role: 'user' }],
525
+ messages: [
526
+ {
527
+ content: [
528
+ {
529
+ cache_control: { type: 'ephemeral' },
530
+ text: 'Hello',
531
+ type: 'text',
532
+ },
533
+ ],
534
+ role: 'user',
535
+ },
536
+ ],
454
537
  top_p: 0.9, // temperature omitted since not provided
455
538
  }),
456
539
  contentType: 'application/json',
@@ -483,7 +566,18 @@ describe('LobeBedrockAI', () => {
483
566
  body: JSON.stringify({
484
567
  anthropic_version: 'bedrock-2023-05-31',
485
568
  max_tokens: 4096,
486
- messages: [{ content: 'Hello', role: 'user' }],
569
+ messages: [
570
+ {
571
+ content: [
572
+ {
573
+ cache_control: { type: 'ephemeral' },
574
+ text: 'Hello',
575
+ type: 'text',
576
+ },
577
+ ],
578
+ role: 'user',
579
+ },
580
+ ],
487
581
  temperature: 0.4, // temperature / 2
488
582
  top_p: 0.9, // both parameters allowed for older models
489
583
  }),
@@ -517,7 +611,18 @@ describe('LobeBedrockAI', () => {
517
611
  body: JSON.stringify({
518
612
  anthropic_version: 'bedrock-2023-05-31',
519
613
  max_tokens: 4096,
520
- messages: [{ content: 'Hello', role: 'user' }],
614
+ messages: [
615
+ {
616
+ content: [
617
+ {
618
+ cache_control: { type: 'ephemeral' },
619
+ text: 'Hello',
620
+ type: 'text',
621
+ },
622
+ ],
623
+ role: 'user',
624
+ },
625
+ ],
521
626
  temperature: 0.3, // temperature / 2, top_p omitted due to conflict
522
627
  }),
523
628
  contentType: 'application/json',
@@ -550,7 +655,18 @@ describe('LobeBedrockAI', () => {
550
655
  body: JSON.stringify({
551
656
  anthropic_version: 'bedrock-2023-05-31',
552
657
  max_tokens: 4096,
553
- messages: [{ content: 'Hello', role: 'user' }],
658
+ messages: [
659
+ {
660
+ content: [
661
+ {
662
+ cache_control: { type: 'ephemeral' },
663
+ text: 'Hello',
664
+ type: 'text',
665
+ },
666
+ ],
667
+ role: 'user',
668
+ },
669
+ ],
554
670
  temperature: 0.35, // temperature / 2, top_p omitted due to conflict
555
671
  }),
556
672
  contentType: 'application/json',
@@ -23,7 +23,9 @@ import {
23
23
  import { AgentRuntimeErrorType } from '../../types/error';
24
24
  import { AgentRuntimeError } from '../../utils/createError';
25
25
  import { debugStream } from '../../utils/debugStream';
26
+ import { getModelPricing } from '../../utils/getModelPricing';
26
27
  import { StreamingResponse } from '../../utils/response';
28
+ import { resolveCacheTTL } from '../anthropic/resolveCacheTTL';
27
29
 
28
30
  /**
29
31
  * A prompt constructor for HuggingFace LLama 2 chat models.
@@ -148,7 +150,16 @@ export class LobeBedrockAI implements LobeRuntimeAI {
148
150
  payload: ChatStreamPayload,
149
151
  options?: ChatMethodOptions,
150
152
  ): Promise<Response> => {
151
- const { max_tokens, messages, model, temperature, top_p, tools } = payload;
153
+ const {
154
+ enabledContextCaching = true,
155
+ max_tokens,
156
+ messages,
157
+ model,
158
+ temperature,
159
+ top_p,
160
+ tools,
161
+ } = payload;
162
+ const inputStartAt = Date.now();
152
163
  const system_message = messages.find((m) => m.role === 'system');
153
164
  const user_messages = messages.filter((m) => m.role !== 'system');
154
165
 
@@ -159,17 +170,29 @@ export class LobeBedrockAI implements LobeRuntimeAI {
159
170
  { hasConflict, normalizeTemperature: true, preferTemperature: true },
160
171
  );
161
172
 
173
+ const systemPrompts = !!system_message?.content
174
+ ? ([
175
+ {
176
+ cache_control: enabledContextCaching ? { type: 'ephemeral' } : undefined,
177
+ text: system_message.content as string,
178
+ type: 'text',
179
+ },
180
+ ] as any)
181
+ : undefined;
182
+
183
+ const anthropicPayload = {
184
+ anthropic_version: 'bedrock-2023-05-31',
185
+ max_tokens: max_tokens || 4096,
186
+ messages: await buildAnthropicMessages(user_messages, { enabledContextCaching }),
187
+ system: systemPrompts,
188
+ temperature: resolvedParams.temperature,
189
+ tools: buildAnthropicTools(tools, { enabledContextCaching }),
190
+ top_p: resolvedParams.top_p,
191
+ };
192
+
162
193
  const command = new InvokeModelWithResponseStreamCommand({
163
194
  accept: 'application/json',
164
- body: JSON.stringify({
165
- anthropic_version: 'bedrock-2023-05-31',
166
- max_tokens: max_tokens || 4096,
167
- messages: await buildAnthropicMessages(user_messages),
168
- system: system_message?.content as string,
169
- temperature: resolvedParams.temperature,
170
- tools: buildAnthropicTools(tools),
171
- top_p: resolvedParams.top_p,
172
- }),
195
+ body: JSON.stringify(anthropicPayload),
173
196
  contentType: 'application/json',
174
197
  modelId: model,
175
198
  });
@@ -186,10 +209,21 @@ export class LobeBedrockAI implements LobeRuntimeAI {
186
209
  debugStream(debug).catch(console.error);
187
210
  }
188
211
 
212
+ const pricing = await getModelPricing(payload.model, ModelProvider.Bedrock);
213
+ const cacheTTL = resolveCacheTTL({ ...payload, enabledContextCaching }, anthropicPayload);
214
+ const pricingOptions = cacheTTL ? { lookupParams: { ttl: cacheTTL } } : undefined;
215
+
189
216
  // Respond with the stream
190
- return StreamingResponse(AWSBedrockClaudeStream(prod, options?.callback), {
191
- headers: options?.headers,
192
- });
217
+ return StreamingResponse(
218
+ AWSBedrockClaudeStream(prod, {
219
+ callbacks: options?.callback,
220
+ inputStartAt,
221
+ payload: { model, pricing, pricingOptions, provider: ModelProvider.Bedrock },
222
+ }),
223
+ {
224
+ headers: options?.headers,
225
+ },
226
+ );
193
227
  } catch (e) {
194
228
  const err = e as Error & { $metadata: any };
195
229
 
@@ -147,6 +147,7 @@ async function generateImageByChatModel(
147
147
  ? {
148
148
  imageConfig: {
149
149
  aspectRatio: params.aspectRatio,
150
+ imageSize: params.resolution,
150
151
  },
151
152
  }
152
153
  : {}),
@@ -38,6 +38,8 @@ const modelsWithModalities = new Set([
38
38
  'gemini-2.0-flash-preview-image-generation',
39
39
  'gemini-2.5-flash-image-preview',
40
40
  'gemini-2.5-flash-image',
41
+ 'gemini-3-pro-image-preview',
42
+ 'nano-banana-pro-preview',
41
43
  ]);
42
44
 
43
45
  const modelsDisableInstuction = new Set([
@@ -51,6 +53,11 @@ const modelsDisableInstuction = new Set([
51
53
  'gemma-3-12b-it',
52
54
  'gemma-3-27b-it',
53
55
  'gemma-3n-e4b-it',
56
+ // ZenMux
57
+ 'google/gemini-2.5-flash-image-free',
58
+ 'google/gemini-2.5-flash-image',
59
+ 'google/gemini-3-pro-image-preview-free',
60
+ 'google/gemini-3-pro-image-preview',
54
61
  ]);
55
62
 
56
63
  const PRO_THINKING_MIN = 128;
@@ -203,7 +210,10 @@ export class LobeGoogleAI implements LobeRuntimeAI {
203
210
  includeThoughts:
204
211
  (!!thinkingBudget ||
205
212
  !!thinkingLevel ||
206
- (model && (model.includes('-3-pro-image') || model.includes('thinking')))) &&
213
+ (model &&
214
+ (model.includes('-3-pro-image') ||
215
+ model.includes('nano-banana-pro') ||
216
+ model.includes('thinking')))) &&
207
217
  resolvedThinkingBudget !== 0
208
218
  ? true
209
219
  : undefined,