@lobehub/chat 1.119.1 → 1.119.2

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 (227) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +5 -0
  3. package/package.json +5 -3
  4. package/packages/const/src/auth.ts +0 -36
  5. package/packages/const/src/index.ts +3 -1
  6. package/packages/database/src/models/__tests__/aiModel.test.ts +1 -2
  7. package/packages/database/src/models/aiModel.ts +2 -3
  8. package/packages/database/src/repositories/aiInfra/index.test.ts +1 -1
  9. package/packages/database/src/repositories/aiInfra/index.ts +4 -4
  10. package/packages/model-bank/src/aiModels/ai21.ts +1 -1
  11. package/packages/model-bank/src/aiModels/ai302.ts +1 -1
  12. package/packages/model-bank/src/aiModels/ai360.ts +1 -1
  13. package/packages/model-bank/src/aiModels/aihubmix.ts +2 -2
  14. package/packages/model-bank/src/aiModels/akashchat.ts +1 -1
  15. package/packages/model-bank/src/aiModels/anthropic.ts +1 -1
  16. package/packages/model-bank/src/aiModels/azure.ts +1 -1
  17. package/packages/model-bank/src/aiModels/azureai.ts +1 -1
  18. package/packages/model-bank/src/aiModels/baichuan.ts +1 -1
  19. package/packages/model-bank/src/aiModels/bedrock.ts +1 -1
  20. package/packages/model-bank/src/aiModels/bfl.ts +2 -3
  21. package/packages/model-bank/src/aiModels/cloudflare.ts +1 -1
  22. package/packages/model-bank/src/aiModels/cohere.ts +1 -1
  23. package/packages/model-bank/src/aiModels/deepseek.ts +1 -1
  24. package/packages/model-bank/src/aiModels/fal.ts +1 -1
  25. package/packages/model-bank/src/aiModels/fireworksai.ts +1 -1
  26. package/packages/model-bank/src/aiModels/giteeai.ts +1 -1
  27. package/packages/model-bank/src/aiModels/github.ts +1 -1
  28. package/packages/model-bank/src/aiModels/google.ts +2 -3
  29. package/packages/model-bank/src/aiModels/groq.ts +1 -1
  30. package/packages/model-bank/src/aiModels/higress.ts +1 -1
  31. package/packages/model-bank/src/aiModels/huggingface.ts +1 -1
  32. package/packages/model-bank/src/aiModels/hunyuan.ts +1 -1
  33. package/packages/model-bank/src/aiModels/index.ts +1 -1
  34. package/packages/model-bank/src/aiModels/infiniai.ts +1 -1
  35. package/packages/model-bank/src/aiModels/internlm.ts +1 -1
  36. package/packages/model-bank/src/aiModels/jina.ts +1 -1
  37. package/packages/model-bank/src/aiModels/lmstudio.ts +1 -1
  38. package/packages/model-bank/src/aiModels/lobehub.ts +1 -1
  39. package/packages/model-bank/src/aiModels/minimax.ts +1 -1
  40. package/packages/model-bank/src/aiModels/mistral.ts +1 -1
  41. package/packages/model-bank/src/aiModels/modelscope.ts +1 -1
  42. package/packages/model-bank/src/aiModels/moonshot.ts +1 -1
  43. package/packages/model-bank/src/aiModels/novita.ts +1 -1
  44. package/packages/model-bank/src/aiModels/nvidia.ts +1 -1
  45. package/packages/model-bank/src/aiModels/ollama.ts +1 -1
  46. package/packages/model-bank/src/aiModels/openai.ts +1 -1
  47. package/packages/model-bank/src/aiModels/openrouter.ts +1 -1
  48. package/packages/model-bank/src/aiModels/perplexity.ts +1 -1
  49. package/packages/model-bank/src/aiModels/ppio.ts +1 -1
  50. package/packages/model-bank/src/aiModels/qiniu.ts +1 -1
  51. package/packages/model-bank/src/aiModels/qwen.ts +1 -1
  52. package/packages/model-bank/src/aiModels/sambanova.ts +1 -1
  53. package/packages/model-bank/src/aiModels/search1api.ts +1 -1
  54. package/packages/model-bank/src/aiModels/sensenova.ts +1 -1
  55. package/packages/model-bank/src/aiModels/siliconcloud.ts +1 -1
  56. package/packages/model-bank/src/aiModels/spark.ts +1 -1
  57. package/packages/model-bank/src/aiModels/stepfun.ts +1 -1
  58. package/packages/model-bank/src/aiModels/taichu.ts +1 -1
  59. package/packages/model-bank/src/aiModels/tencentcloud.ts +1 -1
  60. package/packages/model-bank/src/aiModels/togetherai.ts +1 -1
  61. package/packages/model-bank/src/aiModels/upstage.ts +1 -1
  62. package/packages/model-bank/src/aiModels/v0.ts +1 -1
  63. package/packages/model-bank/src/aiModels/vertexai.ts +1 -1
  64. package/packages/model-bank/src/aiModels/vllm.ts +1 -1
  65. package/packages/model-bank/src/aiModels/volcengine.ts +1 -1
  66. package/packages/model-bank/src/aiModels/wenxin.ts +1 -1
  67. package/packages/model-bank/src/aiModels/xai.ts +1 -1
  68. package/packages/model-bank/src/aiModels/xinference.ts +1 -1
  69. package/packages/model-bank/src/aiModels/zeroone.ts +1 -1
  70. package/packages/model-bank/src/aiModels/zhipu.ts +1 -1
  71. package/packages/model-bank/src/index.ts +1 -0
  72. package/packages/model-bank/src/standard-parameters/index.ts +48 -0
  73. package/packages/{types/src → model-bank/src/types}/aiModel.ts +12 -1
  74. package/packages/model-bank/src/types/index.ts +1 -0
  75. package/packages/model-runtime/package.json +4 -1
  76. package/packages/model-runtime/src/BaseAI.ts +2 -2
  77. package/packages/model-runtime/src/ModelRuntime.test.ts +4 -4
  78. package/packages/model-runtime/src/RouterRuntime/createRuntime.ts +3 -7
  79. package/packages/model-runtime/src/ai302/index.ts +1 -1
  80. package/packages/model-runtime/src/aihubmix/index.ts +1 -2
  81. package/packages/model-runtime/src/anthropic/index.ts +1 -1
  82. package/packages/model-runtime/src/azureOpenai/index.ts +2 -3
  83. package/packages/model-runtime/src/azureai/index.ts +2 -3
  84. package/packages/model-runtime/src/bedrock/index.ts +1 -1
  85. package/packages/model-runtime/src/bfl/createImage.test.ts +4 -4
  86. package/packages/model-runtime/src/bfl/createImage.ts +2 -2
  87. package/packages/model-runtime/src/bfl/index.ts +1 -1
  88. package/packages/model-runtime/src/cloudflare/index.ts +1 -1
  89. package/packages/model-runtime/src/const/models.ts +64 -0
  90. package/packages/model-runtime/src/fal/index.test.ts +2 -3
  91. package/packages/model-runtime/src/fal/index.ts +1 -1
  92. package/packages/model-runtime/src/github/index.ts +1 -1
  93. package/packages/model-runtime/src/google/createImage.test.ts +1 -1
  94. package/packages/model-runtime/src/google/createImage.ts +1 -1
  95. package/packages/model-runtime/src/google/index.test.ts +1 -1
  96. package/packages/model-runtime/src/google/index.ts +4 -3
  97. package/packages/model-runtime/src/groq/index.ts +1 -1
  98. package/packages/model-runtime/src/helpers/parseToolCalls.ts +1 -2
  99. package/packages/model-runtime/src/huggingface/index.ts +1 -1
  100. package/packages/model-runtime/src/index.ts +3 -1
  101. package/packages/model-runtime/src/infiniai/index.ts +1 -1
  102. package/packages/model-runtime/src/ollama/index.test.ts +1 -1
  103. package/packages/model-runtime/src/ollama/index.ts +2 -3
  104. package/packages/model-runtime/src/openai/index.ts +16 -8
  105. package/packages/model-runtime/src/providerTestUtils.ts +1 -2
  106. package/packages/model-runtime/src/qiniu/index.test.ts +2 -3
  107. package/packages/model-runtime/src/siliconcloud/index.ts +1 -1
  108. package/packages/model-runtime/src/types/chat.ts +2 -22
  109. package/packages/model-runtime/src/{error.ts → types/error.ts} +29 -0
  110. package/packages/model-runtime/src/types/index.ts +4 -0
  111. package/packages/model-runtime/src/types/toolsCalling.ts +48 -0
  112. package/packages/model-runtime/src/types/type.ts +1 -1
  113. package/packages/model-runtime/src/types/usage.ts +27 -0
  114. package/packages/model-runtime/src/utils/anthropicHelpers.test.ts +2 -2
  115. package/packages/model-runtime/src/utils/anthropicHelpers.ts +1 -1
  116. package/packages/model-runtime/src/utils/createError.ts +1 -1
  117. package/packages/model-runtime/src/utils/errorResponse.test.ts +110 -0
  118. package/packages/model-runtime/src/utils/errorResponse.ts +64 -0
  119. package/packages/{utils/src → model-runtime/src/utils}/getFallbackModelProperty.ts +1 -1
  120. package/packages/model-runtime/src/utils/googleErrorParser.test.ts +1 -1
  121. package/packages/model-runtime/src/utils/googleErrorParser.ts +1 -1
  122. package/packages/model-runtime/src/utils/handleOpenAIError.ts +1 -1
  123. package/packages/model-runtime/src/utils/imageToBase64.test.ts +91 -0
  124. package/packages/model-runtime/src/utils/imageToBase64.ts +62 -0
  125. package/packages/model-runtime/src/utils/modelParse.test.ts +2 -2
  126. package/packages/model-runtime/src/utils/modelParse.ts +16 -10
  127. package/packages/model-runtime/src/utils/openaiCompatibleFactory/createImage.ts +1 -1
  128. package/packages/model-runtime/src/utils/openaiCompatibleFactory/index.ts +3 -3
  129. package/packages/model-runtime/src/utils/openaiHelpers.test.ts +2 -2
  130. package/packages/model-runtime/src/utils/openaiHelpers.ts +3 -4
  131. package/packages/model-runtime/src/utils/postProcessModelList.ts +2 -2
  132. package/packages/model-runtime/src/utils/safeParseJSON.test.ts +71 -0
  133. package/packages/model-runtime/src/utils/safeParseJSON.ts +12 -0
  134. package/packages/model-runtime/src/utils/streams/bedrock/claude.ts +1 -1
  135. package/packages/model-runtime/src/utils/streams/bedrock/llama.test.ts +1 -2
  136. package/packages/model-runtime/src/utils/streams/bedrock/llama.ts +1 -1
  137. package/packages/model-runtime/src/utils/streams/google-ai.test.ts +1 -1
  138. package/packages/model-runtime/src/utils/streams/google-ai.ts +1 -1
  139. package/packages/model-runtime/src/utils/streams/ollama.test.ts +1 -1
  140. package/packages/model-runtime/src/utils/streams/ollama.ts +2 -3
  141. package/packages/model-runtime/src/utils/streams/openai/openai.test.ts +1 -2
  142. package/packages/model-runtime/src/utils/streams/openai/openai.ts +1 -1
  143. package/packages/model-runtime/src/utils/streams/openai/responsesStream.ts +1 -1
  144. package/packages/model-runtime/src/utils/streams/protocol.ts +3 -3
  145. package/packages/model-runtime/src/utils/streams/vertex-ai.test.ts +1 -1
  146. package/packages/model-runtime/src/utils/streams/vertex-ai.ts +2 -2
  147. package/packages/model-runtime/src/utils/uuid.ts +7 -0
  148. package/packages/model-runtime/src/vertexai/index.ts +1 -1
  149. package/packages/types/src/agent/index.ts +2 -1
  150. package/packages/types/src/aiProvider.ts +10 -2
  151. package/packages/types/src/auth.ts +35 -0
  152. package/packages/types/src/discover/models.ts +1 -1
  153. package/packages/types/src/discover/providers.ts +1 -1
  154. package/packages/types/src/index.ts +4 -0
  155. package/packages/types/src/llm.ts +2 -47
  156. package/packages/types/src/session/agentSession.ts +3 -3
  157. package/packages/types/src/session/index.ts +2 -2
  158. package/packages/types/src/session/sessionGroup.ts +0 -2
  159. package/packages/types/src/user/settings/general.ts +1 -1
  160. package/packages/types/src/user/settings/modelProvider.ts +1 -1
  161. package/packages/utils/src/fetch/fetchSSE.ts +1 -1
  162. package/packages/utils/src/format.ts +2 -3
  163. package/packages/utils/src/index.ts +3 -1
  164. package/packages/utils/src/number.test.ts +1 -2
  165. package/packages/utils/src/number.ts +1 -2
  166. package/packages/utils/src/parseModels.test.ts +1 -2
  167. package/packages/utils/src/parseModels.ts +2 -3
  168. package/packages/utils/src/pricing.test.ts +1 -2
  169. package/packages/utils/src/pricing.ts +1 -1
  170. package/packages/utils/src/server/xor.ts +3 -1
  171. package/src/app/(backend)/middleware/auth/index.ts +1 -2
  172. package/src/app/(backend)/webapi/chat/vertexai/route.ts +1 -1
  173. package/src/app/(backend)/webapi/text-to-image/[provider]/route.ts +1 -2
  174. package/src/app/[variants]/(main)/discover/(list)/model/features/List/ModelTypeIcon.tsx +1 -2
  175. package/src/app/[variants]/(main)/image/@menu/components/SeedNumberInput/index.tsx +1 -1
  176. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/hooks/useAutoDimensions.ts +4 -3
  177. package/src/app/[variants]/(main)/settings/provider/features/ModelList/CreateNewModelModal/Form.tsx +1 -1
  178. package/src/app/[variants]/(main)/settings/provider/features/ModelList/ModelItem.tsx +1 -1
  179. package/src/app/[variants]/(main)/settings/provider/features/ModelList/SortModelModal/ListItem.tsx +1 -1
  180. package/src/app/[variants]/(main)/settings/provider/features/ModelList/SortModelModal/index.tsx +1 -1
  181. package/src/components/ModelSelect/index.tsx +1 -1
  182. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/type.ts +2 -5
  183. package/src/features/Conversation/Extras/Usage/UsageDetail/ModelCard.tsx +1 -1
  184. package/src/features/Conversation/Extras/Usage/UsageDetail/pricing.ts +3 -4
  185. package/src/features/Conversation/Extras/Usage/UsageDetail/tokens.test.ts +1 -1
  186. package/src/features/Conversation/Extras/Usage/UsageDetail/tokens.ts +3 -2
  187. package/src/libs/trpc/async/context.ts +2 -1
  188. package/src/libs/trpc/edge/context.ts +2 -6
  189. package/src/libs/trpc/lambda/context.ts +1 -1
  190. package/src/migrations/FromV5ToV6/types/v5.ts +2 -2
  191. package/src/migrations/FromV5ToV6/types/v6.ts +2 -1
  192. package/src/server/globalConfig/genServerAiProviderConfig.ts +3 -3
  193. package/src/server/modules/ModelRuntime/index.test.ts +1 -1
  194. package/src/server/modules/ModelRuntime/index.ts +1 -1
  195. package/src/server/routers/async/caller.ts +2 -1
  196. package/src/server/routers/async/image.ts +2 -2
  197. package/src/server/routers/lambda/aiModel.ts +1 -1
  198. package/src/server/services/chunk/index.ts +2 -1
  199. package/src/server/services/generation/index.ts +2 -2
  200. package/src/services/_auth.ts +2 -1
  201. package/src/services/aiModel/server.test.ts +1 -1
  202. package/src/services/aiModel/type.ts +1 -1
  203. package/src/services/chat.ts +1 -1
  204. package/src/services/upload.ts +3 -3
  205. package/src/store/agent/slices/chat/action.ts +1 -1
  206. package/src/store/aiInfra/slices/aiModel/action.ts +6 -6
  207. package/src/store/aiInfra/slices/aiModel/initialState.ts +1 -1
  208. package/src/store/aiInfra/slices/aiModel/selectors.test.ts +1 -1
  209. package/src/store/aiInfra/slices/aiModel/selectors.ts +2 -1
  210. package/src/store/aiInfra/slices/aiProvider/__tests__/action.test.ts +7 -7
  211. package/src/store/aiInfra/slices/aiProvider/action.ts +8 -8
  212. package/src/store/aiInfra/slices/aiProvider/initialState.ts +2 -1
  213. package/src/store/electron/actions/app.ts +1 -1
  214. package/src/store/image/slices/generationConfig/action.test.ts +1 -1
  215. package/src/store/image/slices/generationConfig/action.ts +1 -1
  216. package/src/store/image/slices/generationConfig/hooks.test.ts +1 -1
  217. package/src/store/image/slices/generationConfig/hooks.ts +6 -3
  218. package/src/store/image/slices/generationConfig/selectors.test.ts +1 -1
  219. package/src/store/user/slices/auth/action.ts +1 -1
  220. package/src/store/user/slices/auth/selectors.ts +3 -4
  221. package/src/store/user/slices/modelList/action.ts +8 -7
  222. package/src/store/user/slices/modelList/selectors/modelProvider.ts +8 -5
  223. package/src/store/user/slices/preference/selectors.ts +3 -2
  224. package/src/store/user/slices/settings/selectors/settings.ts +1 -2
  225. package/src/store/user/slices/sync/selectors.ts +1 -1
  226. package/packages/const/src/image.ts +0 -51
  227. /package/packages/{utils/src → model-runtime/src/utils}/getFallbackModelProperty.test.ts +0 -0
@@ -1,5 +1,4 @@
1
- import { responsesAPIModels } from '@/const/models';
2
-
1
+ import { responsesAPIModels } from '../const/models';
3
2
  import { ChatStreamPayload, ModelProvider } from '../types';
4
3
  import { processMultiProviderModelList } from '../utils/modelParse';
5
4
  import { createOpenAICompatibleRuntime } from '../utils/openaiCompatibleFactory';
@@ -19,7 +18,7 @@ const supportsFlexTier = (model: string) => {
19
18
  if (model.startsWith('o3-mini')) {
20
19
  return false;
21
20
  }
22
- return flexSupportedModels.some(supportedModel => model.startsWith(supportedModel));
21
+ return flexSupportedModels.some((supportedModel) => model.startsWith(supportedModel));
23
22
  };
24
23
 
25
24
  export const LobeOpenAI = createOpenAICompatibleRuntime({
@@ -54,7 +53,12 @@ export const LobeOpenAI = createOpenAICompatibleRuntime({
54
53
  } as any;
55
54
  }
56
55
 
57
- return { ...rest, model, ...(enableServiceTierFlex && supportsFlexTier(model) && { service_tier: 'flex' }), stream: payload.stream ?? true };
56
+ return {
57
+ ...rest,
58
+ model,
59
+ ...(enableServiceTierFlex && supportsFlexTier(model) && { service_tier: 'flex' }),
60
+ stream: payload.stream ?? true,
61
+ };
58
62
  },
59
63
  },
60
64
  debug: {
@@ -97,13 +101,17 @@ export const LobeOpenAI = createOpenAICompatibleRuntime({
97
101
  tools: openaiTools as any,
98
102
  // computer-use series must set truncation as auto
99
103
  ...(model.startsWith('computer-use') && { truncation: 'auto' }),
100
- text: verbosity
101
- ? { verbosity }
102
- : undefined,
104
+ text: verbosity ? { verbosity } : undefined,
103
105
  }) as any;
104
106
  }
105
107
 
106
- return { ...rest, model, ...(enableServiceTierFlex && supportsFlexTier(model) && { service_tier: 'flex' }), stream: payload.stream ?? true, tools: openaiTools } as any;
108
+ return {
109
+ ...rest,
110
+ model,
111
+ ...(enableServiceTierFlex && supportsFlexTier(model) && { service_tier: 'flex' }),
112
+ stream: payload.stream ?? true,
113
+ tools: openaiTools,
114
+ } as any;
107
115
  },
108
116
  },
109
117
  });
@@ -1,8 +1,7 @@
1
1
  import OpenAI from 'openai';
2
2
  import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
3
 
4
- import { LobeOpenAICompatibleRuntime } from '@/libs/model-runtime';
5
-
4
+ import { LobeOpenAICompatibleRuntime } from './BaseAI';
6
5
  import * as debugStreamModule from './utils/debugStream';
7
6
 
8
7
  interface TesstProviderParams {
@@ -1,7 +1,6 @@
1
1
  // @vitest-environment node
2
- import { ModelProvider } from '@/libs/model-runtime';
3
- import { testProvider } from '@/libs/model-runtime/providerTestUtils';
4
-
2
+ import { testProvider } from '../providerTestUtils';
3
+ import { ModelProvider } from '../types';
5
4
  import { LobeQiniuAI } from './index';
6
5
 
7
6
  const provider = ModelProvider.Qiniu;
@@ -1,5 +1,5 @@
1
- import { AgentRuntimeErrorType } from '../error';
2
1
  import { ChatCompletionErrorPayload, ModelProvider } from '../types';
2
+ import { AgentRuntimeErrorType } from '../types/error';
3
3
  import { processMultiProviderModelList } from '../utils/modelParse';
4
4
  import { createOpenAICompatibleRuntime } from '../utils/openaiCompatibleFactory';
5
5
 
@@ -1,25 +1,5 @@
1
- import type { PartialDeep } from 'type-fest';
2
-
3
- import { ModelTokensUsage, ToolFunction } from '@/types/message';
4
-
5
- export interface MessageToolCall {
6
- /**
7
- * The function that the model called.
8
- */
9
- function: ToolFunction;
10
-
11
- /**
12
- * The ID of the tool call.
13
- */
14
- id: string;
15
-
16
- /**
17
- * The type of the tool. Currently, only `function` is supported.
18
- */
19
- type: 'function' | string;
20
- }
21
-
22
- export type MessageToolCallChunk = PartialDeep<MessageToolCall> & { index: number };
1
+ import { MessageToolCall, MessageToolCallChunk } from './toolsCalling';
2
+ import { ModelTokensUsage } from './usage';
23
3
 
24
4
  export type LLMRoleType = 'user' | 'system' | 'assistant' | 'function' | 'tool';
25
5
 
@@ -37,3 +37,32 @@ export const AGENT_RUNTIME_ERROR_SET = new Set<string>(Object.values(AgentRuntim
37
37
 
38
38
  export type ILobeAgentRuntimeErrorType =
39
39
  (typeof AgentRuntimeErrorType)[keyof typeof AgentRuntimeErrorType];
40
+
41
+ /* eslint-disable sort-keys-fix/sort-keys-fix */
42
+ export const StandardErrorType = {
43
+ // ******* Client Error ******* //
44
+ BadRequest: 400,
45
+ Unauthorized: 401,
46
+ Forbidden: 403,
47
+ ContentNotFound: 404,
48
+ MethodNotAllowed: 405,
49
+ TooManyRequests: 429,
50
+
51
+ // ******* Server Error ******* //
52
+ InternalServerError: 500,
53
+ BadGateway: 502,
54
+ ServiceUnavailable: 503,
55
+ GatewayTimeout: 504,
56
+ } as const;
57
+ /* eslint-enable */
58
+
59
+ export type ErrorType = (typeof StandardErrorType)[keyof typeof StandardErrorType];
60
+
61
+ /**
62
+ * 聊天消息错误对象
63
+ */
64
+ export interface ChatMessageError {
65
+ body?: any;
66
+ message: string;
67
+ type: ErrorType | ILobeAgentRuntimeErrorType;
68
+ }
@@ -1,6 +1,10 @@
1
1
  export * from './chat';
2
2
  export * from './embeddings';
3
+ export * from './error';
4
+ export * from './image';
3
5
  export * from './model';
4
6
  export * from './textToImage';
7
+ export * from './toolsCalling';
5
8
  export * from './tts';
6
9
  export * from './type';
10
+ export * from './usage';
@@ -0,0 +1,48 @@
1
+ import { z } from 'zod';
2
+ import type { PartialDeep } from 'type-fest';
3
+
4
+ /**
5
+ * The function that the model called.
6
+ */
7
+ export interface ToolFunction {
8
+ /**
9
+ * The arguments to call the function with, as generated by the model in JSON
10
+ * format. Note that the model does not always generate valid JSON, and may
11
+ * hallucinate parameters not defined by your function schema. Validate the
12
+ * arguments in your code before calling your function.
13
+ */
14
+ arguments: string;
15
+
16
+ /**
17
+ * The name of the function to call.
18
+ */
19
+ name: string;
20
+ }
21
+
22
+ export interface MessageToolCall {
23
+ /**
24
+ * The function that the model called.
25
+ */
26
+ function: ToolFunction;
27
+
28
+ /**
29
+ * The ID of the tool call.
30
+ */
31
+ id: string;
32
+
33
+ /**
34
+ * The type of the tool. Currently, only `function` is supported.
35
+ */
36
+ type: 'function' | string;
37
+ }
38
+
39
+ export const MessageToolCallSchema = z.object({
40
+ function: z.object({
41
+ arguments: z.string(),
42
+ name: z.string(),
43
+ }),
44
+ id: z.string(),
45
+ type: z.string(),
46
+ });
47
+
48
+ export type MessageToolCallChunk = PartialDeep<MessageToolCall> & { index: number };
@@ -1,7 +1,7 @@
1
1
  import OpenAI from 'openai';
2
2
 
3
- import { ILobeAgentRuntimeErrorType } from '../error';
4
3
  import { ChatStreamPayload } from './chat';
4
+ import { ILobeAgentRuntimeErrorType } from './error';
5
5
 
6
6
  export interface AgentInitErrorPayload {
7
7
  error: object;
@@ -0,0 +1,27 @@
1
+ export interface ModelTokensUsage {
2
+ acceptedPredictionTokens?: number;
3
+ inputAudioTokens?: number;
4
+ inputCacheMissTokens?: number;
5
+ inputCachedTokens?: number;
6
+ /**
7
+ * currently only pplx has citation_tokens
8
+ */
9
+ inputCitationTokens?: number;
10
+ /**
11
+ * user prompt image
12
+ */
13
+ inputImageTokens?: number;
14
+ /**
15
+ * user prompt input
16
+ */
17
+ inputTextTokens?: number;
18
+ inputWriteCacheTokens?: number;
19
+ outputAudioTokens?: number;
20
+ outputImageTokens?: number;
21
+ outputReasoningTokens?: number;
22
+ outputTextTokens?: number;
23
+ rejectedPredictionTokens?: number;
24
+ totalInputTokens?: number;
25
+ totalOutputTokens?: number;
26
+ totalTokens?: number;
27
+ }
@@ -1,8 +1,8 @@
1
- import { imageUrlToBase64 } from '@lobechat/utils';
2
1
  import { OpenAI } from 'openai';
3
2
  import { describe, expect, it, vi } from 'vitest';
4
3
 
5
4
  import { OpenAIChatMessage, UserMessageContentPart } from '../types/chat';
5
+ import { imageUrlToBase64 } from '../utils/imageToBase64';
6
6
  import {
7
7
  buildAnthropicBlock,
8
8
  buildAnthropicMessage,
@@ -19,7 +19,7 @@ vi.mock('./uriParser', () => ({
19
19
  type: 'base64',
20
20
  }),
21
21
  }));
22
- vi.mock('@lobechat/utils');
22
+ vi.mock('../utils/imageToBase64');
23
23
 
24
24
  describe('anthropicHelpers', () => {
25
25
  describe('buildAnthropicBlock', () => {
@@ -1,8 +1,8 @@
1
1
  import Anthropic from '@anthropic-ai/sdk';
2
- import { imageUrlToBase64 } from '@lobechat/utils';
3
2
  import OpenAI from 'openai';
4
3
 
5
4
  import { OpenAIChatMessage, UserMessageContentPart } from '../types';
5
+ import { imageUrlToBase64 } from '../utils/imageToBase64';
6
6
  import { parseDataUri } from './uriParser';
7
7
 
8
8
  export const buildAnthropicBlock = async (
@@ -1,9 +1,9 @@
1
- import { ILobeAgentRuntimeErrorType } from '../error';
2
1
  import {
3
2
  AgentInitErrorPayload,
4
3
  ChatCompletionErrorPayload,
5
4
  CreateImageErrorPayload,
6
5
  } from '../types';
6
+ import { ILobeAgentRuntimeErrorType } from '../types/error';
7
7
 
8
8
  export const AgentRuntimeError = {
9
9
  chat: (error: ChatCompletionErrorPayload): ChatCompletionErrorPayload => error,
@@ -0,0 +1,110 @@
1
+ import { AgentRuntimeErrorType } from '@lobechat/model-runtime';
2
+ import { ChatErrorType } from '@lobechat/types';
3
+ import { describe, expect, it, vi } from 'vitest';
4
+
5
+ import { createErrorResponse } from './errorResponse';
6
+
7
+ describe('createErrorResponse', () => {
8
+ // 测试包含Invalid的错误类型
9
+ it('returns a 401 status for Invalid error type', () => {
10
+ const errorType = 'InvalidTestError';
11
+ const response = createErrorResponse(errorType as any);
12
+ expect(response.status).toBe(401);
13
+ });
14
+
15
+ it('returns a 403 status for LocationNotSupportError error type', () => {
16
+ const errorType = AgentRuntimeErrorType.LocationNotSupportError;
17
+ const response = createErrorResponse(errorType);
18
+ expect(response.status).toBe(403);
19
+ });
20
+
21
+ it('returns a 404 status for ModelNotFound error type', () => {
22
+ const errorType = AgentRuntimeErrorType.ModelNotFound;
23
+ const response = createErrorResponse(errorType);
24
+ expect(response.status).toBe(404);
25
+ });
26
+
27
+ it('returns a 429 status for InsufficientQuota error type', () => {
28
+ const errorType = AgentRuntimeErrorType.InsufficientQuota;
29
+ const response = createErrorResponse(errorType);
30
+ expect(response.status).toBe(429);
31
+ });
32
+
33
+ it('returns a 429 status for QuotaLimitReached error type', () => {
34
+ const errorType = AgentRuntimeErrorType.QuotaLimitReached;
35
+ const response = createErrorResponse(errorType);
36
+ expect(response.status).toBe(429);
37
+ });
38
+
39
+ it('returns a 400 status for ExceededContextWindow error type', () => {
40
+ const errorType = AgentRuntimeErrorType.ExceededContextWindow;
41
+ const response = createErrorResponse(errorType);
42
+ expect(response.status).toBe(400);
43
+ });
44
+
45
+ describe('Provider Biz Error', () => {
46
+ it('returns a 471 status for ProviderBizError error type', () => {
47
+ const errorType = AgentRuntimeErrorType.ProviderBizError;
48
+ const response = createErrorResponse(errorType);
49
+ expect(response.status).toBe(471);
50
+ });
51
+
52
+ it('returns a 470 status for AgentRuntimeError error type', () => {
53
+ const errorType = AgentRuntimeErrorType.AgentRuntimeError;
54
+ const response = createErrorResponse(errorType);
55
+ expect(response.status).toBe(470);
56
+ });
57
+
58
+ it('returns a 472 status for OllamaBizError error type', () => {
59
+ const errorType = AgentRuntimeErrorType.OllamaBizError;
60
+ const response = createErrorResponse(errorType);
61
+ expect(response.status).toBe(472);
62
+ });
63
+
64
+ it('returns a 472 status for OllamaServiceUnavailable error type', () => {
65
+ const errorType = ChatErrorType.OllamaServiceUnavailable;
66
+ const response = createErrorResponse(errorType);
67
+ expect(response.status).toBe(472);
68
+ });
69
+ });
70
+
71
+ // 测试状态码不在200-599范围内的情况
72
+ it('logs an error when the status code is not a number or not in the range of 200-599', () => {
73
+ const errorType = 'Unknown Error';
74
+ const consoleSpy = vi.spyOn(console, 'error');
75
+ try {
76
+ createErrorResponse(errorType as any);
77
+ } catch (e) {}
78
+ expect(consoleSpy).toHaveBeenCalled();
79
+ consoleSpy.mockRestore();
80
+ });
81
+
82
+ // 测试默认情况
83
+ it('returns the same error type as status for unknown error types', () => {
84
+ const errorType = 500; // 假设500是一个未知的错误类型
85
+ const response = createErrorResponse(errorType as any);
86
+ expect(response.status).toBe(errorType);
87
+ });
88
+
89
+ // 测试返回的Response对象是否包含正确的body和errorType
90
+ it('returns a Response object with the correct body and errorType', () => {
91
+ const errorType = ChatErrorType.NoOpenAIAPIKey;
92
+ const body = { message: 'No API key provided' };
93
+ const response = createErrorResponse(errorType, body);
94
+ return response.json().then((data) => {
95
+ expect(data).toEqual({
96
+ body,
97
+ errorType,
98
+ });
99
+ });
100
+ });
101
+
102
+ // 测试没有提供body时,返回的Response对象的body是否为undefined
103
+ it('returns a Response object with an undefined body when no body is provided', () => {
104
+ const errorType = ChatErrorType.NoOpenAIAPIKey;
105
+ const response = createErrorResponse(errorType);
106
+ return response.json().then((data) => {
107
+ expect(data.body).toBeUndefined();
108
+ });
109
+ });
110
+ });
@@ -0,0 +1,64 @@
1
+ import { ChatErrorType, ErrorResponse, ErrorType } from '@lobechat/types';
2
+
3
+ import { AgentRuntimeErrorType, ILobeAgentRuntimeErrorType } from '../types';
4
+
5
+ const getStatus = (errorType: ILobeAgentRuntimeErrorType | ErrorType) => {
6
+ // InvalidAccessCode / InvalidAzureAPIKey / InvalidOpenAIAPIKey / InvalidZhipuAPIKey ....
7
+ if (errorType.toString().includes('Invalid')) return 401;
8
+
9
+ switch (errorType) {
10
+ case AgentRuntimeErrorType.InvalidProviderAPIKey: {
11
+ return 401;
12
+ }
13
+
14
+ case AgentRuntimeErrorType.ExceededContextWindow: {
15
+ return 400;
16
+ }
17
+
18
+ case AgentRuntimeErrorType.LocationNotSupportError: {
19
+ return 403;
20
+ }
21
+
22
+ case AgentRuntimeErrorType.ModelNotFound: {
23
+ return 404;
24
+ }
25
+
26
+ case AgentRuntimeErrorType.InsufficientQuota:
27
+ case AgentRuntimeErrorType.QuotaLimitReached: {
28
+ return 429;
29
+ }
30
+
31
+ // define the 471~480 as provider error
32
+ case AgentRuntimeErrorType.AgentRuntimeError: {
33
+ return 470;
34
+ }
35
+
36
+ case AgentRuntimeErrorType.ProviderBizError: {
37
+ return 471;
38
+ }
39
+
40
+ // all local provider connection error
41
+ case AgentRuntimeErrorType.OllamaServiceUnavailable:
42
+ case ChatErrorType.OllamaServiceUnavailable:
43
+ case AgentRuntimeErrorType.OllamaBizError: {
44
+ return 472;
45
+ }
46
+ }
47
+
48
+ return errorType as number;
49
+ };
50
+
51
+ export const createErrorResponse = (errorType: ILobeAgentRuntimeErrorType, body?: any) => {
52
+ const statusCode = getStatus(errorType);
53
+
54
+ const data: ErrorResponse = { body, errorType };
55
+
56
+ if (typeof statusCode !== 'number' || statusCode < 200 || statusCode > 599) {
57
+ console.error(
58
+ `current StatusCode: \`${statusCode}\` .`,
59
+ 'Please go to `./utils/errorResponse.ts` to defined the statusCode.',
60
+ );
61
+ }
62
+
63
+ return new Response(JSON.stringify(data), { status: statusCode });
64
+ };
@@ -1,4 +1,4 @@
1
- import { AiFullModelCard } from '@/types/aiModel';
1
+ import type { AiFullModelCard } from 'model-bank';
2
2
 
3
3
  /**
4
4
  * Get the model property value, first from the specified provider, and then from other providers as a fallback.
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
 
3
- import { AgentRuntimeErrorType } from '../error';
3
+ import { AgentRuntimeErrorType } from '../types/error';
4
4
  import {
5
5
  cleanErrorMessage,
6
6
  extractStatusCodeFromError,
@@ -1,4 +1,4 @@
1
- import { AgentRuntimeErrorType, ILobeAgentRuntimeErrorType } from '../error';
1
+ import { AgentRuntimeErrorType, ILobeAgentRuntimeErrorType } from '../types/error';
2
2
 
3
3
  export interface ParsedError {
4
4
  error: any;
@@ -1,6 +1,6 @@
1
1
  import OpenAI from 'openai';
2
2
 
3
- import { AgentRuntimeErrorType } from '../error';
3
+ import { AgentRuntimeErrorType } from '../types/error';
4
4
 
5
5
  export const handleOpenAIError = (
6
6
  error: any,
@@ -0,0 +1,91 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+
3
+ import { imageToBase64, imageUrlToBase64 } from './imageToBase64';
4
+
5
+ describe('imageToBase64', () => {
6
+ let mockImage: HTMLImageElement;
7
+ let mockCanvas: HTMLCanvasElement;
8
+ let mockContext: CanvasRenderingContext2D;
9
+
10
+ beforeEach(() => {
11
+ mockImage = {
12
+ width: 200,
13
+ height: 100,
14
+ } as HTMLImageElement;
15
+
16
+ mockContext = {
17
+ drawImage: vi.fn(),
18
+ } as unknown as CanvasRenderingContext2D;
19
+
20
+ mockCanvas = {
21
+ width: 0,
22
+ height: 0,
23
+ getContext: vi.fn().mockReturnValue(mockContext),
24
+ toDataURL: vi.fn().mockReturnValue('data:image/webp;base64,mockBase64Data'),
25
+ } as unknown as HTMLCanvasElement;
26
+
27
+ vi.spyOn(document, 'createElement').mockReturnValue(mockCanvas);
28
+ });
29
+
30
+ afterEach(() => {
31
+ vi.restoreAllMocks();
32
+ });
33
+
34
+ it('should convert image to base64 with correct size and type', () => {
35
+ const result = imageToBase64({ img: mockImage, size: 100, type: 'image/jpeg' });
36
+
37
+ expect(document.createElement).toHaveBeenCalledWith('canvas');
38
+ expect(mockCanvas.width).toBe(100);
39
+ expect(mockCanvas.height).toBe(100);
40
+ expect(mockCanvas.getContext).toHaveBeenCalledWith('2d');
41
+ expect(mockContext.drawImage).toHaveBeenCalledWith(mockImage, 50, 0, 100, 100, 0, 0, 100, 100);
42
+ expect(mockCanvas.toDataURL).toHaveBeenCalledWith('image/jpeg');
43
+ expect(result).toBe('data:image/webp;base64,mockBase64Data');
44
+ });
45
+
46
+ it('should use default type when not specified', () => {
47
+ imageToBase64({ img: mockImage, size: 100 });
48
+ expect(mockCanvas.toDataURL).toHaveBeenCalledWith('image/webp');
49
+ });
50
+
51
+ it('should handle taller images correctly', () => {
52
+ mockImage.width = 100;
53
+ mockImage.height = 200;
54
+ imageToBase64({ img: mockImage, size: 100 });
55
+ expect(mockContext.drawImage).toHaveBeenCalledWith(mockImage, 0, 50, 100, 100, 0, 0, 100, 100);
56
+ });
57
+ });
58
+
59
+ describe('imageUrlToBase64', () => {
60
+ const mockFetch = vi.fn();
61
+ const mockArrayBuffer = new ArrayBuffer(8);
62
+
63
+ beforeEach(() => {
64
+ global.fetch = mockFetch;
65
+ global.btoa = vi.fn().mockReturnValue('mockBase64String');
66
+ });
67
+
68
+ afterEach(() => {
69
+ vi.restoreAllMocks();
70
+ });
71
+
72
+ it('should convert image URL to base64 string', async () => {
73
+ mockFetch.mockResolvedValue({
74
+ arrayBuffer: () => Promise.resolve(mockArrayBuffer),
75
+ blob: () => Promise.resolve(new Blob([mockArrayBuffer], { type: 'image/jpg' })),
76
+ });
77
+
78
+ const result = await imageUrlToBase64('https://example.com/image.jpg');
79
+
80
+ expect(mockFetch).toHaveBeenCalledWith('https://example.com/image.jpg');
81
+ expect(global.btoa).toHaveBeenCalled();
82
+ expect(result).toEqual({ base64: 'mockBase64String', mimeType: 'image/jpg' });
83
+ });
84
+
85
+ it('should throw an error when fetch fails', async () => {
86
+ const mockError = new Error('Fetch failed');
87
+ mockFetch.mockRejectedValue(mockError);
88
+
89
+ await expect(imageUrlToBase64('https://example.com/image.jpg')).rejects.toThrow('Fetch failed');
90
+ });
91
+ });
@@ -0,0 +1,62 @@
1
+ export const imageToBase64 = ({
2
+ size,
3
+ img,
4
+ type = 'image/webp',
5
+ }: {
6
+ img: HTMLImageElement;
7
+ size: number;
8
+ type?: string;
9
+ }) => {
10
+ const canvas = document.createElement('canvas');
11
+ const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
12
+ let startX = 0;
13
+ let startY = 0;
14
+
15
+ if (img.width > img.height) {
16
+ startX = (img.width - img.height) / 2;
17
+ } else {
18
+ startY = (img.height - img.width) / 2;
19
+ }
20
+
21
+ canvas.width = size;
22
+ canvas.height = size;
23
+
24
+ ctx.drawImage(
25
+ img,
26
+ startX,
27
+ startY,
28
+ Math.min(img.width, img.height),
29
+ Math.min(img.width, img.height),
30
+ 0,
31
+ 0,
32
+ size,
33
+ size,
34
+ );
35
+
36
+ return canvas.toDataURL(type);
37
+ };
38
+
39
+ export const imageUrlToBase64 = async (
40
+ imageUrl: string,
41
+ ): Promise<{ base64: string; mimeType: string }> => {
42
+ try {
43
+ const res = await fetch(imageUrl);
44
+ const blob = await res.blob();
45
+ const arrayBuffer = await blob.arrayBuffer();
46
+
47
+ const base64 =
48
+ typeof btoa === 'function'
49
+ ? btoa(
50
+ new Uint8Array(arrayBuffer).reduce(
51
+ (data, byte) => data + String.fromCharCode(byte),
52
+ '',
53
+ ),
54
+ )
55
+ : Buffer.from(arrayBuffer).toString('base64');
56
+
57
+ return { base64, mimeType: blob.type };
58
+ } catch (error) {
59
+ console.error('Error converting image to base64:', error);
60
+ throw error;
61
+ }
62
+ };
@@ -4,7 +4,7 @@ import type { ChatModelCard } from '@/types/llm';
4
4
 
5
5
  import {
6
6
  MODEL_LIST_CONFIGS,
7
- PROVIDER_DETECTION_CONFIG,
7
+ MODEL_OWNER_DETECTION_CONFIG,
8
8
  detectModelProvider,
9
9
  processModelList,
10
10
  processMultiProviderModelList,
@@ -754,7 +754,7 @@ describe('modelParse', () => {
754
754
  describe('MODEL_LIST_CONFIGS and PROVIDER_DETECTION_CONFIG', () => {
755
755
  it('should have matching keys in both configuration objects', () => {
756
756
  const modelConfigKeys = Object.keys(MODEL_LIST_CONFIGS);
757
- const providerDetectionKeys = Object.keys(PROVIDER_DETECTION_CONFIG);
757
+ const providerDetectionKeys = Object.keys(MODEL_OWNER_DETECTION_CONFIG);
758
758
  expect(modelConfigKeys.sort()).toEqual(providerDetectionKeys.sort());
759
759
  });
760
760
  });