mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-24 18:50:56 +08:00
Feat: more error blocks (#9960)
* refactor(utils): 提取 API 调用错误序列化逻辑到独立函数 将 serializeError 中的 API 调用错误处理逻辑提取为独立的 serializeAPICallError 函数,提高代码可维护性 * feat(错误处理): 添加下载错误的序列化支持 新增 SerializedAiSdkDownloadError 接口用于表示下载错误 实现 serializeDownloadError 方法处理 DownloadError 的序列化 在 serializeError 中添加对 DownloadError 的判断处理 * feat(错误类型): 添加序列化AI SDK错误类型检查函数 修改 isSerializedAiSdkAPICallError 新增 isSerializedAiSdkDownloadError 新增 SerializedAiSdkInvalidArgumentError * feat(错误处理): 添加对InvalidArgumentError的序列化支持 添加对InvalidArgumentError类型的序列化处理,包括定义序列化接口和实现序列化函数 * feat(错误处理): 添加对InvalidDataContentError的序列化支持 * feat(错误处理): 添加对InvalidMessageRoleError的序列化支持 新增对InvalidMessageRoleError错误的序列化处理,包括类型定义和序列化函数 * feat(错误处理): 添加对无效提示错误的序列化支持 新增 SerializedAiSdkInvalidPromptError 接口及序列化函数 在 serializeError 中添加对 InvalidPromptError 的处理逻辑 * feat(错误处理): 添加对无效工具输入错误的序列化支持 * feat(错误处理): 添加对JSON解析错误的序列化支持 * feat(错误处理): 添加消息转换错误的序列化支持 添加 SerializedAiSdkMessageConversionError 接口及序列化函数,用于处理消息转换错误的序列化 * feat(types): 添加 SerializedAiSdkNoAudioGeneratedError 类型及校验函数 * feat(错误处理): 添加对NoObjectGeneratedError的序列化支持 新增SerializedAiSdkNoObjectGeneratedError接口及序列化函数,用于处理AI SDK中对象未生成的错误情况 * feat(错误处理): 添加对NoSuchModelError的序列化支持 添加对AI SDK中NoSuchModelError类型的序列化支持,包括类型定义和序列化函数 * feat(错误处理): 添加对NoSuchProviderError的序列化支持 * feat(错误处理): 添加对NoSuchToolError的序列化支持 新增SerializedAiSdkNoSuchToolError接口及序列化函数,用于处理工具不存在错误 简化isSerializedAiSdkNoSuchProviderError的校验逻辑 * feat(错误处理): 添加序列化重试错误类型和函数 添加 SerializedAiSdkRetryError 接口和序列化函数,用于处理重试错误的序列化 * feat(types): 添加SerializedAiSdkTooManyEmbeddingValuesForCallError类型 添加未由aisdk导出的SerializedAiSdkTooManyEmbeddingValuesForCallError类型及其类型守卫,用于处理嵌入值过多错误 * feat(错误处理): 添加工具调用修复错误的序列化支持 * feat(错误处理): 添加类型验证错误的序列化支持 * feat(错误处理): 添加对不支持功能的错误序列化支持 * feat(types): 添加 AiSdkErrorUnion 类型用于聚合所有 AI SDK 错误类型 * refactor(types): 移除未使用的AiSdkErrorUnion类型并清理导入 * refactor(error): 重构错误处理逻辑,统一序列化方法 简化错误序列化逻辑,使用统一的方法处理所有可能的错误类型 移除重复的序列化函数,提高代码可维护性 更新错误类型定义,添加缺失的错误类型 * feat(error): 添加对InvalidToolInputError和NoSuchToolError的序列化支持 新增对AI SDK中InvalidToolInputError和NoSuchToolError错误的序列化处理,完善错误处理逻辑 * feat(错误处理): 完善AI SDK错误类型和错误详情展示 添加SerializedAiSdkNoSpeechGeneratedError类型并重命名相关函数 实现isSerializedAiSdkErrorUnion函数统一检查所有AI SDK错误类型 在ErrorBlock中扩展错误详情展示逻辑,支持所有AI SDK错误类型 * feat(i18n): 添加缺失的翻译字段 * docs(i18n): 添加待翻译的多语言文本字段 * fix(ErrorBlock): 修复重复的错误类型检查条件 * feat(types): 添加AISDKError到AiSdkErrorUnion类型中 * refactor(ErrorBlock): 移除未使用的类型验证错误显示逻辑 * fix(i18n): Auto update translations for PR #9960 * docs(i18n): 更新多语言翻译文件中的缺失翻译 * fix(i18n): 修正多语言文件中的翻译错误 更新法语、葡萄牙语、日语和俄语翻译文件,将中文词汇替换为正确的目标语言词汇 * fix(类型): 修正SerializedError和SerializedAiSdkJSONParseError的类型判断 移除SerializedAiSdkJSONParseError类型判断中冗余的'message'检查,因为父类型SerializedAiSdkError已包含此检查 * fix(错误处理): 修复类型验证错误判断并添加缺失的错误类型 修复 isSerializedAiSdkTypeValidationError 判断逻辑,排除包含 parameter 属性的情况 在 SerializedAiSdkErrorUnion 联合类型中添加缺失的 SerializedAiSdkNoSpeechGeneratedError 类型 --------- Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
parent
973cab57ab
commit
fd83834fca
@ -773,6 +773,7 @@
|
||||
"more": "More",
|
||||
"name": "Name",
|
||||
"no_results": "No results",
|
||||
"none": "None",
|
||||
"open": "Open",
|
||||
"paste": "Paste",
|
||||
"preview": "Preview",
|
||||
@ -817,6 +818,8 @@
|
||||
"openai-response": "OpenAI-Response"
|
||||
},
|
||||
"error": {
|
||||
"availableProviders": "Available Providers",
|
||||
"availableTools": "Available Tools",
|
||||
"backup": {
|
||||
"file_format": "Backup file format error"
|
||||
},
|
||||
@ -841,9 +844,13 @@
|
||||
"quota_exceeded": "Your daily {{quota}} free quota has been exhausted. Please go to the <provider>{{provider}}</provider> to obtain an API key and configure the API key to continue using.",
|
||||
"response": "Something went wrong. Please check if you have set your API key in the Settings > Providers"
|
||||
},
|
||||
"data": "data",
|
||||
"content": "Content",
|
||||
"data": "Data",
|
||||
"detail": "Error Details",
|
||||
"details": "Details",
|
||||
"errors": "Errors",
|
||||
"finishReason": "Finish Reason",
|
||||
"functionality": "Functionality",
|
||||
"http": {
|
||||
"400": "Request failed. Please check if the request parameters are correct. If you have changed the model settings, please reset them to the default settings",
|
||||
"401": "Authentication failed. Please check if your API key is correct",
|
||||
@ -855,16 +862,27 @@
|
||||
"503": "Service unavailable. Please try again later",
|
||||
"504": "Gateway timeout. Please try again later"
|
||||
},
|
||||
"lastError": "Last Error",
|
||||
"maxEmbeddingsPerCall": "Max Embeddings Per Call",
|
||||
"message": "Error Message",
|
||||
"missing_user_message": "Cannot switch model response: The original user message has been deleted. Please send a new message to get a response with this model.",
|
||||
"model": {
|
||||
"exists": "Model already exists",
|
||||
"not_exists": "Model does not exist"
|
||||
},
|
||||
"modelId": "Model ID",
|
||||
"modelType": "Model Type",
|
||||
"name": "Error name",
|
||||
"no_api_key": "API key is not configured",
|
||||
"originalError": "Original Error",
|
||||
"originalMessage": "Original Message",
|
||||
"parameter": "Parameter",
|
||||
"pause_placeholder": "Paused",
|
||||
"prompt": "Prompt",
|
||||
"provider": "Provider",
|
||||
"providerId": "Provider ID",
|
||||
"provider_disabled": "Model provider is not enabled",
|
||||
"reason": "Reason",
|
||||
"render": {
|
||||
"description": "Failed to render message content. Please check if the message content format is correct",
|
||||
"title": "Render Error"
|
||||
@ -872,13 +890,23 @@
|
||||
"requestBody": "Request Body",
|
||||
"requestBodyValues": "Request Body Values",
|
||||
"requestUrl": "Request URL",
|
||||
"response": "Response",
|
||||
"responseBody": "Response Body",
|
||||
"responseHeaders": "Response Header",
|
||||
"responses": "Responses",
|
||||
"role": "Role",
|
||||
"stack": "Stack Trace",
|
||||
"status": "Status Code",
|
||||
"statusCode": "Status code",
|
||||
"statusCode": "Status Code",
|
||||
"statusText": "Status Text",
|
||||
"text": "Text",
|
||||
"toolInput": "Tool Input",
|
||||
"toolName": "Tool Name",
|
||||
"unknown": "Unknown error",
|
||||
"user_message_not_found": "Cannot find original user message to resend"
|
||||
"usage": "Usage",
|
||||
"user_message_not_found": "Cannot find original user message to resend",
|
||||
"value": "Value",
|
||||
"values": "Values"
|
||||
},
|
||||
"export": {
|
||||
"assistant": "Assistant",
|
||||
|
||||
@ -773,6 +773,7 @@
|
||||
"more": "更多",
|
||||
"name": "名称",
|
||||
"no_results": "无结果",
|
||||
"none": "无",
|
||||
"open": "打开",
|
||||
"paste": "粘贴",
|
||||
"preview": "预览",
|
||||
@ -817,6 +818,8 @@
|
||||
"openai-response": "OpenAI-Response"
|
||||
},
|
||||
"error": {
|
||||
"availableProviders": "可用提供商",
|
||||
"availableTools": "可用工具",
|
||||
"backup": {
|
||||
"file_format": "备份文件格式错误"
|
||||
},
|
||||
@ -841,9 +844,13 @@
|
||||
"quota_exceeded": "您今日免费配额已用尽,请前往 <provider>{{provider}}</provider> 获取API密钥,配置API密钥后继续使用",
|
||||
"response": "出错了,如果没有配置 API 密钥,请前往设置 > 模型提供商中配置密钥"
|
||||
},
|
||||
"content": "内容",
|
||||
"data": "数据",
|
||||
"detail": "错误详情",
|
||||
"details": "详细信息",
|
||||
"errors": "错误",
|
||||
"finishReason": "结束原因",
|
||||
"functionality": "功能",
|
||||
"http": {
|
||||
"400": "请求错误,请检查请求参数是否正确。如果修改了模型设置,请重置到默认设置",
|
||||
"401": "身份验证失败,请检查 API 密钥是否正确",
|
||||
@ -855,16 +862,27 @@
|
||||
"503": "服务不可用,请稍后再试",
|
||||
"504": "网关超时,请稍后再试"
|
||||
},
|
||||
"lastError": "最后错误",
|
||||
"maxEmbeddingsPerCall": "每次调用的最大嵌入",
|
||||
"message": "错误信息",
|
||||
"missing_user_message": "无法切换模型响应:原始用户消息已被删除。请发送新消息以获取此模型的响应",
|
||||
"model": {
|
||||
"exists": "模型已存在",
|
||||
"not_exists": "模型不存在"
|
||||
},
|
||||
"modelId": "模型 ID",
|
||||
"modelType": "模型类型",
|
||||
"name": "错误名称",
|
||||
"no_api_key": "API 密钥未配置",
|
||||
"originalError": "原错误",
|
||||
"originalMessage": "原消息",
|
||||
"parameter": "参数",
|
||||
"pause_placeholder": "已中断",
|
||||
"prompt": "提示词",
|
||||
"provider": "提供商",
|
||||
"providerId": "提供商 ID",
|
||||
"provider_disabled": "模型提供商未启用",
|
||||
"reason": "原因",
|
||||
"render": {
|
||||
"description": "消息内容渲染失败,请检查消息内容格式是否正确",
|
||||
"title": "渲染错误"
|
||||
@ -872,13 +890,23 @@
|
||||
"requestBody": "请求内容",
|
||||
"requestBodyValues": "请求体",
|
||||
"requestUrl": "请求路径",
|
||||
"response": "响应",
|
||||
"responseBody": "响应内容",
|
||||
"responseHeaders": "响应首部",
|
||||
"responses": "响应",
|
||||
"role": "角色",
|
||||
"stack": "堆栈信息",
|
||||
"status": "状态码",
|
||||
"statusCode": "状态码",
|
||||
"statusText": "状态文本",
|
||||
"text": "文本",
|
||||
"toolInput": "工具输入",
|
||||
"toolName": "工具名",
|
||||
"unknown": "未知错误",
|
||||
"user_message_not_found": "无法找到原始用户消息"
|
||||
"usage": "用量",
|
||||
"user_message_not_found": "无法找到原始用户消息",
|
||||
"value": "值",
|
||||
"values": "值"
|
||||
},
|
||||
"export": {
|
||||
"assistant": "助手",
|
||||
|
||||
@ -773,6 +773,7 @@
|
||||
"more": "更多",
|
||||
"name": "名稱",
|
||||
"no_results": "沒有結果",
|
||||
"none": "無",
|
||||
"open": "開啟",
|
||||
"paste": "貼上",
|
||||
"preview": "預覽",
|
||||
@ -817,6 +818,8 @@
|
||||
"openai-response": "OpenAI-Response"
|
||||
},
|
||||
"error": {
|
||||
"availableProviders": "可用提供商",
|
||||
"availableTools": "可用工具",
|
||||
"backup": {
|
||||
"file_format": "備份檔案格式錯誤"
|
||||
},
|
||||
@ -841,9 +844,13 @@
|
||||
"quota_exceeded": "您今日{{quota}}免费配额已用尽,请前往 <provider>{{provider}}</provider> 获取API密钥,配置API密钥后继续使用",
|
||||
"response": "出現錯誤。如果尚未設定 API 金鑰,請前往設定 > 模型提供者中設定金鑰"
|
||||
},
|
||||
"content": "內容",
|
||||
"data": "数据",
|
||||
"detail": "錯誤詳情",
|
||||
"details": "詳細信息",
|
||||
"errors": "錯誤",
|
||||
"finishReason": "結束原因",
|
||||
"functionality": "功能",
|
||||
"http": {
|
||||
"400": "請求錯誤,請檢查請求參數是否正確。如果修改了模型設定,請重設到預設設定",
|
||||
"401": "身份驗證失敗,請檢查 API 金鑰是否正確",
|
||||
@ -855,16 +862,27 @@
|
||||
"503": "服務無法使用,請稍後再試",
|
||||
"504": "閘道器超時,請稍後再試"
|
||||
},
|
||||
"lastError": "最後錯誤",
|
||||
"maxEmbeddingsPerCall": "每次調用的最大嵌入",
|
||||
"message": "錯誤訊息",
|
||||
"missing_user_message": "無法切換模型回應:原始用戶訊息已被刪除。請發送新訊息以獲得此模型回應。",
|
||||
"model": {
|
||||
"exists": "模型已存在",
|
||||
"not_exists": "模型不存在"
|
||||
},
|
||||
"modelId": "模型 ID",
|
||||
"modelType": "模型類型",
|
||||
"name": "錯誤名稱",
|
||||
"no_api_key": "API 金鑰未設定",
|
||||
"originalError": "原錯誤",
|
||||
"originalMessage": "原消息",
|
||||
"parameter": "參數",
|
||||
"pause_placeholder": "回應已暫停",
|
||||
"prompt": "提示詞",
|
||||
"provider": "提供商",
|
||||
"providerId": "提供者 ID",
|
||||
"provider_disabled": "模型供應商未啟用",
|
||||
"reason": "原因",
|
||||
"render": {
|
||||
"description": "消息內容渲染失敗,請檢查消息內容格式是否正確",
|
||||
"title": "渲染錯誤"
|
||||
@ -872,13 +890,23 @@
|
||||
"requestBody": "請求內容",
|
||||
"requestBodyValues": "请求体",
|
||||
"requestUrl": "請求路徑",
|
||||
"response": "響應",
|
||||
"responseBody": "响应内容",
|
||||
"responseHeaders": "响应首部",
|
||||
"responses": "響應",
|
||||
"role": "角色",
|
||||
"stack": "堆棧信息",
|
||||
"status": "狀態碼",
|
||||
"statusCode": "狀態碼",
|
||||
"statusText": "狀態文本",
|
||||
"text": "文本",
|
||||
"toolInput": "工具輸入",
|
||||
"toolName": "工具名",
|
||||
"unknown": "未知錯誤",
|
||||
"user_message_not_found": "無法找到原始用戶訊息"
|
||||
"usage": "用量",
|
||||
"user_message_not_found": "無法找到原始用戶訊息",
|
||||
"value": "值",
|
||||
"values": "值"
|
||||
},
|
||||
"export": {
|
||||
"assistant": "助手",
|
||||
|
||||
@ -773,6 +773,7 @@
|
||||
"more": "Περισσότερα",
|
||||
"name": "Όνομα",
|
||||
"no_results": "Δεν βρέθηκαν αποτελέσματα",
|
||||
"none": "Χωρίς",
|
||||
"open": "Άνοιγμα",
|
||||
"paste": "Επικόλληση",
|
||||
"preview": "Προεπισκόπηση",
|
||||
@ -817,6 +818,8 @@
|
||||
"openai-response": "Απάντηση OpenAI"
|
||||
},
|
||||
"error": {
|
||||
"availableProviders": "Διαθέσιμοι πάροχοι",
|
||||
"availableTools": "Διαθέσιμα εργαλεία",
|
||||
"backup": {
|
||||
"file_format": "Λάθος μορφή αρχείου που επιστρέφεται"
|
||||
},
|
||||
@ -841,9 +844,13 @@
|
||||
"quota_exceeded": "Η ημερήσια δωρεάν ποσόστωση {{quota}} tokens σας έχει εξαντληθεί. Παρακαλώ μεταβείτε στο <provider>{{provider}}</provider> για να λάβετε ένα κλειδί API και να ρυθμίσετε το κλειδί API για να συνεχίσετε τη χρήση.",
|
||||
"response": "Σφάλμα. Εάν δεν έχετε ρυθμίσει το κλειδί API, πηγαίνετε στο ρυθμισμένα > παρέχοντας το πρόσωπο του μοντέλου"
|
||||
},
|
||||
"content": "Περιεχόμενο",
|
||||
"data": "δεδομένα",
|
||||
"detail": "Λεπτομέρειες σφάλματος",
|
||||
"details": "Λεπτομέρειες",
|
||||
"errors": "Λάθος",
|
||||
"finishReason": "Αιτία λήξης",
|
||||
"functionality": "λειτουργία",
|
||||
"http": {
|
||||
"400": "Σφάλμα ζητήματος, παρακαλώ ελέγξτε αν τα παράμετρα του ζητήματος είναι σωστά. Εάν έχετε αλλάξει τις ρυθμίσεις του μοντέλου, επαναφέρετε τις προεπιλεγμένες ρυθμίσεις.",
|
||||
"401": "Αποτυχία επιβεβαίωσης ταυτότητας, παρακαλώ ελέγξτε αν η κλειδί API είναι σωστή",
|
||||
@ -855,16 +862,27 @@
|
||||
"503": "Η υπηρεσία δεν είναι διαθέσιμη, παρακαλώ δοκιμάστε ξανά",
|
||||
"504": "Υπερχρονισμός φάρων, παρακαλώ δοκιμάστε ξανά"
|
||||
},
|
||||
"lastError": "Τελευταίο σφάλμα",
|
||||
"maxEmbeddingsPerCall": "Μέγιστες ενσωματώσεις ανά κλήση",
|
||||
"message": "Μήνυμα σφάλματος",
|
||||
"missing_user_message": "Αδυναμία εναλλαγής απάντησης μοντέλου: το αρχικό μήνυμα χρήστη έχει διαγραφεί. Παρακαλούμε στείλτε ένα νέο μήνυμα για να λάβετε απάντηση από αυτό το μοντέλο",
|
||||
"model": {
|
||||
"exists": "Το μοντέλο υπάρχει ήδη",
|
||||
"not_exists": "Το μοντέλο δεν υπάρχει"
|
||||
},
|
||||
"modelId": "Αναγνωριστικό μοντέλου",
|
||||
"modelType": "Τύπος μοντέλου",
|
||||
"name": "Λάθος όνομα",
|
||||
"no_api_key": "Δεν έχετε ρυθμίσει το κλειδί API",
|
||||
"originalError": "Αρχικό σφάλμα",
|
||||
"originalMessage": "Αρχικό μήνυμα",
|
||||
"parameter": "παράμετροι",
|
||||
"pause_placeholder": "Διακόπηκε",
|
||||
"prompt": "συμβουλές",
|
||||
"provider": "πάροχος",
|
||||
"providerId": "Αναγνωριστικό παρόχου",
|
||||
"provider_disabled": "Ο παρεχόμενος παροχός του μοντέλου δεν είναι ενεργοποιημένος",
|
||||
"reason": "αιτία",
|
||||
"render": {
|
||||
"description": "Απέτυχε η ώθηση της εξίσωσης, παρακαλώ ελέγξτε το σωστό μορφάτι της",
|
||||
"title": "Σφάλμα Παρασκήνιου"
|
||||
@ -872,13 +890,23 @@
|
||||
"requestBody": "Περιεχόμενο αιτήματος",
|
||||
"requestBodyValues": "Σώμα αιτήματος",
|
||||
"requestUrl": "Μονοπάτι αιτήματος",
|
||||
"response": "απάντηση",
|
||||
"responseBody": "απάντηση περιεχομένου",
|
||||
"responseHeaders": "Επικεφαλίδες απόκρισης",
|
||||
"responses": "ανταπόκριση",
|
||||
"role": "ρόλος",
|
||||
"stack": "Πληροφορίες στοίβας",
|
||||
"status": "Κωδικός κατάστασης",
|
||||
"statusCode": "Κωδικός κατάστασης",
|
||||
"statusText": "Κείμενο κατάστασης",
|
||||
"text": "κείμενο",
|
||||
"toolInput": "εισαγωγή εργαλείου",
|
||||
"toolName": "Όνομα εργαλείου",
|
||||
"unknown": "Άγνωστο σφάλμα",
|
||||
"user_message_not_found": "Αδυναμία εύρεσης της αρχικής μηνύματος χρήστη"
|
||||
"usage": "δοσολογία",
|
||||
"user_message_not_found": "Αδυναμία εύρεσης της αρχικής μηνύματος χρήστη",
|
||||
"value": "τιμή",
|
||||
"values": "τιμή"
|
||||
},
|
||||
"export": {
|
||||
"assistant": "βοηθός",
|
||||
|
||||
@ -773,6 +773,7 @@
|
||||
"more": "Más",
|
||||
"name": "Nombre",
|
||||
"no_results": "Sin resultados",
|
||||
"none": "无",
|
||||
"open": "Abrir",
|
||||
"paste": "Pegar",
|
||||
"preview": "Vista previa",
|
||||
@ -817,6 +818,8 @@
|
||||
"openai-response": "Respuesta de OpenAI"
|
||||
},
|
||||
"error": {
|
||||
"availableProviders": "Proveedores disponibles",
|
||||
"availableTools": "Herramientas disponibles",
|
||||
"backup": {
|
||||
"file_format": "Formato de archivo de copia de seguridad incorrecto"
|
||||
},
|
||||
@ -841,9 +844,13 @@
|
||||
"quota_exceeded": "Su cuota gratuita diaria de {{quota}} tokens se ha agotado. Por favor, vaya a <provider>{{provider}}</provider> para obtener una clave API y configurar la clave API para continuar usando.",
|
||||
"response": "Ha ocurrido un error, si no ha configurado la clave API, vaya a Configuración > Proveedor de modelos para configurar la clave"
|
||||
},
|
||||
"content": "contenido",
|
||||
"data": "datos",
|
||||
"detail": "Detalles del error",
|
||||
"details": "Detalles",
|
||||
"errors": "error",
|
||||
"finishReason": "Razón de finalización",
|
||||
"functionality": "función",
|
||||
"http": {
|
||||
"400": "Error en la solicitud, revise si los parámetros de la solicitud son correctos. Si modificó la configuración del modelo, restablezca a la configuración predeterminada",
|
||||
"401": "Fallo en la autenticación, revise si la clave API es correcta",
|
||||
@ -855,16 +862,27 @@
|
||||
"503": "Servicio no disponible, inténtelo de nuevo más tarde",
|
||||
"504": "Tiempo de espera de la puerta de enlace, inténtelo de nuevo más tarde"
|
||||
},
|
||||
"message": "错误信息",
|
||||
"lastError": "Último error",
|
||||
"maxEmbeddingsPerCall": "máximo de incrustaciones por llamada",
|
||||
"message": "Mensaje de error",
|
||||
"missing_user_message": "No se puede cambiar la respuesta del modelo: el mensaje original del usuario ha sido eliminado. Envíe un nuevo mensaje para obtener la respuesta de este modelo",
|
||||
"model": {
|
||||
"exists": "El modelo ya existe",
|
||||
"not_exists": "El modelo no existe"
|
||||
},
|
||||
"modelId": "ID del modelo",
|
||||
"modelType": "Tipo de modelo",
|
||||
"name": "Nombre de error",
|
||||
"no_api_key": "La clave API no está configurada",
|
||||
"originalError": "Error original",
|
||||
"originalMessage": "mensaje original",
|
||||
"parameter": "parámetro",
|
||||
"pause_placeholder": "Interrumpido",
|
||||
"prompt": "prompt",
|
||||
"provider": "proveedor",
|
||||
"providerId": "ID del proveedor",
|
||||
"provider_disabled": "El proveedor de modelos no está habilitado",
|
||||
"reason": "causa",
|
||||
"render": {
|
||||
"description": "Error al renderizar la fórmula, por favor, compruebe si el formato de la fórmula es correcto",
|
||||
"title": "Error de renderizado"
|
||||
@ -872,13 +890,23 @@
|
||||
"requestBody": "Contenido de la solicitud",
|
||||
"requestBodyValues": "Cuerpo de la solicitud",
|
||||
"requestUrl": "Ruta de solicitud",
|
||||
"response": "respuesta",
|
||||
"responseBody": "Contenido de la respuesta",
|
||||
"responseHeaders": "Encabezados de respuesta",
|
||||
"responses": "respuesta",
|
||||
"role": "Rol",
|
||||
"stack": "Información de la pila",
|
||||
"status": "código de estado",
|
||||
"statusCode": "código de estado",
|
||||
"status": "Estado",
|
||||
"statusCode": "Código de estado",
|
||||
"statusText": "Texto de estado",
|
||||
"text": "Texto",
|
||||
"toolInput": "Herramienta de entrada",
|
||||
"toolName": "Nombre de la herramienta",
|
||||
"unknown": "Error desconocido",
|
||||
"user_message_not_found": "No se pudo encontrar el mensaje original del usuario"
|
||||
"usage": "Cantidad de uso",
|
||||
"user_message_not_found": "No se pudo encontrar el mensaje original del usuario",
|
||||
"value": "Valor",
|
||||
"values": "Valor"
|
||||
},
|
||||
"export": {
|
||||
"assistant": "Asistente",
|
||||
|
||||
@ -773,6 +773,7 @@
|
||||
"more": "Plus",
|
||||
"name": "Nom",
|
||||
"no_results": "Aucun résultat",
|
||||
"none": "Aucun",
|
||||
"open": "Ouvrir",
|
||||
"paste": "Coller",
|
||||
"preview": "Aperçu",
|
||||
@ -817,6 +818,8 @@
|
||||
"openai-response": "Réponse OpenAI"
|
||||
},
|
||||
"error": {
|
||||
"availableProviders": "Fournisseurs disponibles",
|
||||
"availableTools": "Outils disponibles",
|
||||
"backup": {
|
||||
"file_format": "Le format du fichier de sauvegarde est incorrect"
|
||||
},
|
||||
@ -841,9 +844,13 @@
|
||||
"quota_exceeded": "Votre quota gratuit quotidien de {{quota}} tokens a été épuisé. Veuillez vous rendre sur <provider>{{provider}}</provider> pour obtenir une clé API et configurer la clé API pour continuer à utiliser.",
|
||||
"response": "Une erreur s'est produite, si l'API n'est pas configurée, veuillez aller dans Paramètres > Fournisseurs de modèles pour configurer la clé"
|
||||
},
|
||||
"content": "suivre l'instruction du système",
|
||||
"data": "données",
|
||||
"detail": "Détails de l'erreur",
|
||||
"details": "Informations détaillées",
|
||||
"errors": "erreur",
|
||||
"finishReason": "Raison de la fin",
|
||||
"functionality": "fonction",
|
||||
"http": {
|
||||
"400": "Erreur de requête, veuillez vérifier si les paramètres de la requête sont corrects. Si vous avez modifié les paramètres du modèle, réinitialisez-les aux paramètres par défaut.",
|
||||
"401": "Échec de l'authentification, veuillez vérifier que votre clé API est correcte.",
|
||||
@ -855,16 +862,27 @@
|
||||
"503": "Service indisponible, veuillez réessayer plus tard.",
|
||||
"504": "Délai d'expiration de la passerelle, veuillez réessayer plus tard."
|
||||
},
|
||||
"lastError": "Dernière erreur",
|
||||
"maxEmbeddingsPerCall": "Maximum d’intégrations par appel",
|
||||
"message": "Erreur message",
|
||||
"missing_user_message": "Impossible de changer de modèle de réponse : le message utilisateur d'origine a été supprimé. Veuillez envoyer un nouveau message pour obtenir une réponse de ce modèle.",
|
||||
"model": {
|
||||
"exists": "Le modèle existe déjà",
|
||||
"not_exists": "Le modèle n'existe pas"
|
||||
},
|
||||
"modelId": "ID du modèle",
|
||||
"modelType": "Type de modèle",
|
||||
"name": "Nom d'erreur",
|
||||
"no_api_key": "La clé API n'est pas configurée",
|
||||
"originalError": "Erreur d'origine",
|
||||
"originalMessage": "message original",
|
||||
"parameter": "paramètre",
|
||||
"pause_placeholder": "Прервано",
|
||||
"prompt": "mot-clé",
|
||||
"provider": "fournisseur",
|
||||
"providerId": "ID du fournisseur",
|
||||
"provider_disabled": "Le fournisseur de modèles n'est pas activé",
|
||||
"reason": "raison",
|
||||
"render": {
|
||||
"description": "La formule n'a pas été rendue avec succès, veuillez vérifier si le format de la formule est correct",
|
||||
"title": "Erreur de rendu"
|
||||
@ -872,13 +890,23 @@
|
||||
"requestBody": "Contenu de la demande",
|
||||
"requestBodyValues": "Corps de la requête",
|
||||
"requestUrl": "Chemin de la requête",
|
||||
"response": "réponse",
|
||||
"responseBody": "Contenu de la réponse",
|
||||
"responseHeaders": "En-têtes de réponse",
|
||||
"responses": "réponse",
|
||||
"role": "rôle",
|
||||
"stack": "Informations de la pile",
|
||||
"status": "Code d'état",
|
||||
"statusCode": "Code d'état",
|
||||
"statusText": "Texte d'état",
|
||||
"text": "texte",
|
||||
"toolInput": "entrée de l'outil",
|
||||
"toolName": "Nom de l'outil",
|
||||
"unknown": "Неизвестная ошибка",
|
||||
"user_message_not_found": "Impossible de trouver le message d'utilisateur original"
|
||||
"usage": "Quantité",
|
||||
"user_message_not_found": "Impossible de trouver le message d'utilisateur original",
|
||||
"value": "valeur",
|
||||
"values": "valeur"
|
||||
},
|
||||
"export": {
|
||||
"assistant": "Assistant",
|
||||
|
||||
@ -773,6 +773,7 @@
|
||||
"more": "もっと",
|
||||
"name": "名前",
|
||||
"no_results": "検索結果なし",
|
||||
"none": "無",
|
||||
"open": "開く",
|
||||
"paste": "貼り付け",
|
||||
"preview": "プレビュー",
|
||||
@ -817,6 +818,8 @@
|
||||
"openai-response": "OpenAI-Response"
|
||||
},
|
||||
"error": {
|
||||
"availableProviders": "利用可能なプロバイダー",
|
||||
"availableTools": "利用可能なツール",
|
||||
"backup": {
|
||||
"file_format": "バックアップファイルの形式エラー"
|
||||
},
|
||||
@ -841,9 +844,13 @@
|
||||
"quota_exceeded": "本日の{{quota}}無料クォータが使い果たされました。<provider>{{provider}}</provider>でAPIキーを取得し、APIキーを設定して使用を続けてください。",
|
||||
"response": "エラーが発生しました。APIキーが設定されていない場合は、設定 > プロバイダーでキーを設定してください"
|
||||
},
|
||||
"content": "内容",
|
||||
"data": "データ",
|
||||
"detail": "エラーの詳細",
|
||||
"details": "詳細",
|
||||
"errors": "エラー",
|
||||
"finishReason": "終了理由",
|
||||
"functionality": "機能",
|
||||
"http": {
|
||||
"400": "リクエストに失敗しました。リクエストパラメータが正しいか確認してください。モデルの設定を変更した場合は、デフォルトの設定にリセットしてください",
|
||||
"401": "認証に失敗しました。APIキーが正しいか確認してください",
|
||||
@ -855,16 +862,27 @@
|
||||
"503": "サービスが利用できません。後でもう一度試してください",
|
||||
"504": "ゲートウェイタイムアウトが発生しました。後でもう一度試してください"
|
||||
},
|
||||
"lastError": "最後のエラー",
|
||||
"maxEmbeddingsPerCall": "1回の呼び出しでの最大埋め込み数",
|
||||
"message": "エラーメッセージ",
|
||||
"missing_user_message": "モデル応答を切り替えられません:元のユーザーメッセージが削除されました。このモデルで応答を得るには、新しいメッセージを送信してください",
|
||||
"model": {
|
||||
"exists": "モデルが既に存在します",
|
||||
"not_exists": "モデルが存在しません"
|
||||
},
|
||||
"modelId": "モデル ID",
|
||||
"modelType": "モデルの種類",
|
||||
"name": "エラー名",
|
||||
"no_api_key": "APIキーが設定されていません",
|
||||
"originalError": "元のエラー",
|
||||
"originalMessage": "元のメッセージ",
|
||||
"parameter": "パラメータ",
|
||||
"pause_placeholder": "応答を一時停止しました",
|
||||
"prompt": "プロンプトを表示する",
|
||||
"provider": "プロバイダー",
|
||||
"providerId": "プロバイダーID",
|
||||
"provider_disabled": "モデルプロバイダーが有効になっていません",
|
||||
"reason": "原因",
|
||||
"render": {
|
||||
"description": "メッセージの内容のレンダリングに失敗しました。メッセージの内容の形式が正しいか確認してください",
|
||||
"title": "レンダリングエラー"
|
||||
@ -872,13 +890,23 @@
|
||||
"requestBody": "要求されたコンテンツ",
|
||||
"requestBodyValues": "リクエストボディ",
|
||||
"requestUrl": "リクエストパス",
|
||||
"response": "応答",
|
||||
"responseBody": "レスポンス内容",
|
||||
"responseHeaders": "レスポンスヘッダー",
|
||||
"responses": "応答",
|
||||
"role": "キャラクター",
|
||||
"stack": "スタック情報",
|
||||
"status": "ステータスコード",
|
||||
"statusCode": "ステータスコード",
|
||||
"statusText": "状態テキスト",
|
||||
"text": "テキスト",
|
||||
"toolInput": "<translate_input>\nツール入力\n</translate_input>",
|
||||
"toolName": "ツール名",
|
||||
"unknown": "不明なエラー",
|
||||
"user_message_not_found": "元のユーザーメッセージを見つけることができませんでした"
|
||||
"usage": "用量",
|
||||
"user_message_not_found": "元のユーザーメッセージを見つけることができませんでした",
|
||||
"value": "値",
|
||||
"values": "値"
|
||||
},
|
||||
"export": {
|
||||
"assistant": "アシスタント",
|
||||
|
||||
@ -773,6 +773,7 @@
|
||||
"more": "Mais",
|
||||
"name": "Nome",
|
||||
"no_results": "Nenhum resultado",
|
||||
"none": "Nenhum",
|
||||
"open": "Abrir",
|
||||
"paste": "Colar",
|
||||
"preview": "Pré-visualização",
|
||||
@ -817,6 +818,8 @@
|
||||
"openai-response": "Resposta OpenAI"
|
||||
},
|
||||
"error": {
|
||||
"availableProviders": "Provedores disponíveis",
|
||||
"availableTools": "Ferramentas disponíveis",
|
||||
"backup": {
|
||||
"file_format": "Formato do arquivo de backup está incorreto"
|
||||
},
|
||||
@ -841,9 +844,13 @@
|
||||
"quota_exceeded": "Sua cota gratuita diária de {{quota}} tokens foi esgotada. Por favor, vá para <provider>{{provider}}</provider> para obter uma chave API e configurar a chave API para continuar usando.",
|
||||
"response": "Ocorreu um erro, se a chave da API não foi configurada, por favor vá para Configurações > Provedores de Modelo para configurar a chave"
|
||||
},
|
||||
"content": "conteúdo",
|
||||
"data": "dados",
|
||||
"detail": "Detalhes do erro",
|
||||
"details": "Detalhes",
|
||||
"errors": "erro",
|
||||
"finishReason": "Motivo de término",
|
||||
"functionality": "funcionalidade",
|
||||
"http": {
|
||||
"400": "Erro na solicitação, por favor verifique se os parâmetros da solicitação estão corretos. Se você alterou as configurações do modelo, redefina para as configurações padrão",
|
||||
"401": "Falha na autenticação, por favor verifique se a chave da API está correta",
|
||||
@ -855,16 +862,27 @@
|
||||
"503": "Serviço indisponível, por favor tente novamente mais tarde",
|
||||
"504": "Tempo de espera do gateway excedido, por favor tente novamente mais tarde"
|
||||
},
|
||||
"lastError": "Último erro",
|
||||
"maxEmbeddingsPerCall": "Máximo de incorporações por chamada",
|
||||
"message": "Mensagem de erro",
|
||||
"missing_user_message": "Não é possível alternar a resposta do modelo: a mensagem original do usuário foi excluída. Envie uma nova mensagem para obter a resposta deste modelo",
|
||||
"model": {
|
||||
"exists": "O modelo já existe",
|
||||
"not_exists": "O modelo não existe"
|
||||
},
|
||||
"modelId": "ID do modelo",
|
||||
"modelType": "Tipo de modelo",
|
||||
"name": "Nome do erro",
|
||||
"no_api_key": "A chave da API não foi configurada",
|
||||
"originalError": "Erro original",
|
||||
"originalMessage": "Mensagem original",
|
||||
"parameter": "parâmetro",
|
||||
"pause_placeholder": "Interrompido",
|
||||
"prompt": "prompt",
|
||||
"provider": "fornecedor",
|
||||
"providerId": "ID do fornecedor",
|
||||
"provider_disabled": "O provedor de modelos está desativado",
|
||||
"reason": "causa",
|
||||
"render": {
|
||||
"description": "Falha ao renderizar a fórmula, por favor verifique se o formato da fórmula está correto",
|
||||
"title": "Erro de Renderização"
|
||||
@ -872,13 +890,23 @@
|
||||
"requestBody": "Conteúdo da solicitação",
|
||||
"requestBodyValues": "Corpo da solicitação",
|
||||
"requestUrl": "Caminho da solicitação",
|
||||
"response": "resposta",
|
||||
"responseBody": "Conteúdo da resposta",
|
||||
"responseHeaders": "Cabeçalho de resposta",
|
||||
"responses": "resposta",
|
||||
"role": "personagem",
|
||||
"stack": "Informações da pilha",
|
||||
"status": "Código de status",
|
||||
"statusCode": "Código de status",
|
||||
"statusText": "Texto de estado",
|
||||
"text": "texto",
|
||||
"toolInput": "ferramenta de entrada",
|
||||
"toolName": "Nome da ferramenta",
|
||||
"unknown": "Erro desconhecido",
|
||||
"user_message_not_found": "Não foi possível encontrar a mensagem original do usuário"
|
||||
"usage": "dosagem",
|
||||
"user_message_not_found": "Não foi possível encontrar a mensagem original do usuário",
|
||||
"value": "valor",
|
||||
"values": "valor"
|
||||
},
|
||||
"export": {
|
||||
"assistant": "Assistente",
|
||||
|
||||
@ -773,6 +773,7 @@
|
||||
"more": "Ещё",
|
||||
"name": "Имя",
|
||||
"no_results": "Результатов не найдено",
|
||||
"none": "без",
|
||||
"open": "Открыть",
|
||||
"paste": "Вставить",
|
||||
"preview": "Предварительный просмотр",
|
||||
@ -817,6 +818,8 @@
|
||||
"openai-response": "OpenAI-Response"
|
||||
},
|
||||
"error": {
|
||||
"availableProviders": "Доступные провайдеры",
|
||||
"availableTools": "Доступные инструменты",
|
||||
"backup": {
|
||||
"file_format": "Ошибка формата файла резервной копии"
|
||||
},
|
||||
@ -841,9 +844,13 @@
|
||||
"quota_exceeded": "Ваша ежедневная {{quota}} бесплатная квота исчерпана. Пожалуйста, перейдите в <provider>{{provider}}</provider> для получения ключа API и настройте ключ API для продолжения использования.",
|
||||
"response": "Что-то пошло не так. Пожалуйста, проверьте, установлен ли ваш ключ API в Настройки > Провайдеры"
|
||||
},
|
||||
"content": "Содержание",
|
||||
"data": "данные",
|
||||
"detail": "Детали ошибки",
|
||||
"details": "Подробности",
|
||||
"errors": "ошибка",
|
||||
"finishReason": "Причина завершения",
|
||||
"functionality": "функция",
|
||||
"http": {
|
||||
"400": "Не удалось выполнить запрос. Пожалуйста, проверьте, правильно ли настроены параметры запроса. Если вы изменили настройки модели, пожалуйста, сбросьте их до значений по умолчанию",
|
||||
"401": "Не удалось пройти аутентификацию. Пожалуйста, проверьте, правильно ли настроен ваш ключ API",
|
||||
@ -855,16 +862,27 @@
|
||||
"503": "Серверная ошибка. Пожалуйста, попробуйте позже",
|
||||
"504": "Серверная ошибка. Пожалуйста, попробуйте позже"
|
||||
},
|
||||
"lastError": "Последняя ошибка",
|
||||
"maxEmbeddingsPerCall": "Максимальное количество вложений на вызов",
|
||||
"message": "Сообщение об ошибке",
|
||||
"missing_user_message": "Невозможно изменить модель ответа: исходное сообщение пользователя было удалено. Пожалуйста, отправьте новое сообщение, чтобы получить ответ от этой модели",
|
||||
"model": {
|
||||
"exists": "Модель уже существует",
|
||||
"not_exists": "Модель не существует"
|
||||
},
|
||||
"name": "错误名称",
|
||||
"modelId": "ID модели",
|
||||
"modelType": "Тип модели",
|
||||
"name": "Название ошибки",
|
||||
"no_api_key": "Ключ API не настроен",
|
||||
"originalError": "Исходная ошибка",
|
||||
"originalMessage": "исходное сообщение",
|
||||
"parameter": "параметр",
|
||||
"pause_placeholder": "Получение ответа приостановлено",
|
||||
"prompt": "подсказка",
|
||||
"provider": "поставщик",
|
||||
"providerId": "ID поставщика",
|
||||
"provider_disabled": "Провайдер моделей не включен",
|
||||
"reason": "причина",
|
||||
"render": {
|
||||
"description": "Не удалось рендерить содержимое сообщения. Пожалуйста, проверьте, правильно ли формат содержимого сообщения",
|
||||
"title": "Ошибка рендеринга"
|
||||
@ -872,13 +890,23 @@
|
||||
"requestBody": "Запрашиваемый контент",
|
||||
"requestBodyValues": "Тело запроса",
|
||||
"requestUrl": "Путь запроса",
|
||||
"response": "ответ",
|
||||
"responseBody": "Содержание ответа",
|
||||
"responseHeaders": "Заголовки ответа",
|
||||
"responses": "отклик",
|
||||
"role": "роль",
|
||||
"stack": "Информация стека",
|
||||
"status": "Код статуса",
|
||||
"statusCode": "Код состояния",
|
||||
"statusText": "Текст состояния",
|
||||
"text": "текст",
|
||||
"toolInput": "ввод инструмента",
|
||||
"toolName": "имя инструмента",
|
||||
"unknown": "Неизвестная ошибка",
|
||||
"user_message_not_found": "Не удалось найти исходное сообщение пользователя"
|
||||
"usage": "Дозировка",
|
||||
"user_message_not_found": "Не удалось найти исходное сообщение пользователя",
|
||||
"value": "значение",
|
||||
"values": "значение"
|
||||
},
|
||||
"export": {
|
||||
"assistant": "Ассистент",
|
||||
|
||||
@ -6,10 +6,29 @@ import { useAppDispatch } from '@renderer/store'
|
||||
import { removeBlocksThunk } from '@renderer/store/thunk/messageThunk'
|
||||
import {
|
||||
isSerializedAiSdkAPICallError,
|
||||
isSerializedAiSdkDownloadError,
|
||||
isSerializedAiSdkError,
|
||||
isSerializedAiSdkErrorUnion,
|
||||
isSerializedAiSdkInvalidArgumentError,
|
||||
isSerializedAiSdkInvalidDataContentError,
|
||||
isSerializedAiSdkInvalidMessageRoleError,
|
||||
isSerializedAiSdkInvalidPromptError,
|
||||
isSerializedAiSdkInvalidToolInputError,
|
||||
isSerializedAiSdkJSONParseError,
|
||||
isSerializedAiSdkMessageConversionError,
|
||||
isSerializedAiSdkNoObjectGeneratedError,
|
||||
isSerializedAiSdkNoSpeechGeneratedError,
|
||||
isSerializedAiSdkNoSuchModelError,
|
||||
isSerializedAiSdkNoSuchProviderError,
|
||||
isSerializedAiSdkNoSuchToolError,
|
||||
isSerializedAiSdkRetryError,
|
||||
isSerializedAiSdkToolCallRepairError,
|
||||
isSerializedAiSdkTooManyEmbeddingValuesForCallError,
|
||||
isSerializedAiSdkTypeValidationError,
|
||||
isSerializedAiSdkUnsupportedFunctionalityError,
|
||||
isSerializedError,
|
||||
SerializedAiSdkAPICallError,
|
||||
SerializedAiSdkError,
|
||||
SerializedAiSdkErrorUnion,
|
||||
SerializedError
|
||||
} from '@renderer/types/error'
|
||||
import type { ErrorMessageBlock, Message } from '@renderer/types/newMessage'
|
||||
@ -167,10 +186,7 @@ const ErrorDetailModal: React.FC<ErrorDetailModalProps> = ({ open, onClose, erro
|
||||
|
||||
const renderErrorDetails = (error?: SerializedError) => {
|
||||
if (!error) return <div>{t('error.unknown')}</div>
|
||||
if (isSerializedAiSdkAPICallError(error)) {
|
||||
return <AiApiCallError error={error} />
|
||||
}
|
||||
if (isSerializedAiSdkError(error)) {
|
||||
if (isSerializedAiSdkErrorUnion(error)) {
|
||||
return <AiSdkError error={error} />
|
||||
}
|
||||
return (
|
||||
@ -290,7 +306,7 @@ const BuiltinError = ({ error }: { error: SerializedError }) => {
|
||||
}
|
||||
|
||||
// 作为 base,渲染公共字段,应当在 ErrorDetailList 中渲染
|
||||
const AiSdkError = ({ error }: { error: SerializedAiSdkError }) => {
|
||||
const AiSdkErrorBase = ({ error }: { error: SerializedAiSdkError }) => {
|
||||
const { t } = useTranslation()
|
||||
const cause = error.cause
|
||||
return (
|
||||
@ -306,60 +322,289 @@ const AiSdkError = ({ error }: { error: SerializedAiSdkError }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const AiApiCallError = ({ error }: { error: SerializedAiSdkAPICallError }) => {
|
||||
const AiSdkError = ({ error }: { error: SerializedAiSdkErrorUnion }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
// 这些字段是 unknown 类型,暂且不清楚都可能是什么类型,总之先覆盖下大部分场景
|
||||
const requestBodyValues = safeToString(error.requestBodyValues)
|
||||
const data = safeToString(error.data)
|
||||
|
||||
return (
|
||||
<ErrorDetailList>
|
||||
<AiSdkError error={error} />
|
||||
<AiSdkErrorBase error={error} />
|
||||
|
||||
{error.url && (
|
||||
{(isSerializedAiSdkAPICallError(error) || isSerializedAiSdkDownloadError(error)) && (
|
||||
<>
|
||||
{error.statusCode && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.statusCode')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.statusCode}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
{error.url && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.requestUrl')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.url}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkAPICallError(error) && (
|
||||
<>
|
||||
{error.requestBodyValues && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.requestBodyValues')}:</ErrorDetailLabel>
|
||||
<CodeViewer
|
||||
value={safeToString(error.requestBodyValues)}
|
||||
className="source-view"
|
||||
language="json"
|
||||
expanded
|
||||
/>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{error.responseHeaders && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.responseHeaders')}:</ErrorDetailLabel>
|
||||
<CodeViewer
|
||||
value={JSON.stringify(error.responseHeaders, null, 2)}
|
||||
className="source-view"
|
||||
language="json"
|
||||
expanded
|
||||
/>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{error.responseBody && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.responseBody')}:</ErrorDetailLabel>
|
||||
<CodeViewer value={error.responseBody} className="source-view" language="json" expanded />
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{error.data && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.data')}:</ErrorDetailLabel>
|
||||
<CodeViewer value={safeToString(error.data)} className="source-view" language="json" expanded />
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkDownloadError(error) && (
|
||||
<>
|
||||
{error.statusText && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.statusText')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.statusText}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkInvalidArgumentError(error) && (
|
||||
<>
|
||||
{error.parameter && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.parameter')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.parameter}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{(isSerializedAiSdkInvalidArgumentError(error) || isSerializedAiSdkTypeValidationError(error)) && (
|
||||
<>
|
||||
{error.value && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.value')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{safeToString(error.value)}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkInvalidDataContentError(error) && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.requestUrl')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.url}</ErrorDetailValue>
|
||||
<ErrorDetailLabel>{t('error.content')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{safeToString(error.content)}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{requestBodyValues && (
|
||||
{isSerializedAiSdkInvalidMessageRoleError(error) && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.requestBodyValues')}:</ErrorDetailLabel>
|
||||
<CodeViewer value={safeToString(error.requestBodyValues)} className="source-view" language="json" expanded />
|
||||
<ErrorDetailLabel>{t('error.role')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.role}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{error.statusCode && (
|
||||
{isSerializedAiSdkInvalidPromptError(error) && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.statusCode')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.statusCode}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
{error.responseHeaders && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.responseHeaders')}:</ErrorDetailLabel>
|
||||
<CodeViewer
|
||||
value={JSON.stringify(error.responseHeaders, null, 2)}
|
||||
className="source-view"
|
||||
language="json"
|
||||
expanded
|
||||
/>
|
||||
<ErrorDetailLabel>{t('error.prompt')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{safeToString(error.prompt)}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{error.responseBody && (
|
||||
{isSerializedAiSdkInvalidToolInputError(error) && (
|
||||
<>
|
||||
{error.toolName && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.toolName')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.toolName}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
{error.toolInput && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.toolInput')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.toolInput}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{(isSerializedAiSdkJSONParseError(error) || isSerializedAiSdkNoObjectGeneratedError(error)) && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.responseBody')}:</ErrorDetailLabel>
|
||||
<CodeViewer value={error.responseBody} className="source-view" language="json" expanded />
|
||||
<ErrorDetailLabel>{t('error.text')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.text}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{data && (
|
||||
{isSerializedAiSdkMessageConversionError(error) && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.data')}:</ErrorDetailLabel>
|
||||
<CodeViewer value={safeToString(error.data)} className="source-view" language="json" expanded />
|
||||
<ErrorDetailLabel>{t('error.originalMessage')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{safeToString(error.originalMessage)}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkNoSpeechGeneratedError(error) && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.responses')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.responses.join(', ')}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkNoObjectGeneratedError(error) && (
|
||||
<>
|
||||
{error.response && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.response')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{safeToString(error.response)}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
{error.usage && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.usage')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{safeToString(error.usage)}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
{error.finishReason && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.finishReason')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.finishReason}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{(isSerializedAiSdkNoSuchModelError(error) ||
|
||||
isSerializedAiSdkNoSuchProviderError(error) ||
|
||||
isSerializedAiSdkTooManyEmbeddingValuesForCallError(error)) && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.modelId')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.modelId}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{(isSerializedAiSdkNoSuchModelError(error) || isSerializedAiSdkNoSuchProviderError(error)) && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.modelType')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.modelType}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkNoSuchProviderError(error) && (
|
||||
<>
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.providerId')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.providerId}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.availableProviders')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.availableProviders.join(', ')}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkNoSuchToolError(error) && (
|
||||
<>
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.toolName')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.toolName}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
{error.availableTools && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.availableTools')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.availableTools?.join(', ') || t('common.none')}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkRetryError(error) && (
|
||||
<>
|
||||
{error.reason && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.reason')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.reason}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
{error.lastError && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.lastError')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{safeToString(error.lastError)}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
{error.errors && error.errors.length > 0 && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.errors')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.errors.map((e) => safeToString(e)).join('\n\n')}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkTooManyEmbeddingValuesForCallError(error) && (
|
||||
<>
|
||||
{error.provider && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.provider')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.provider}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
{error.maxEmbeddingsPerCall && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.maxEmbeddingsPerCall')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.maxEmbeddingsPerCall}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
{error.values && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.values')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{safeToString(error.values)}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkToolCallRepairError(error) && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.originalError')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{safeToString(error.originalError)}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
|
||||
{isSerializedAiSdkUnsupportedFunctionalityError(error) && (
|
||||
<ErrorDetailItem>
|
||||
<ErrorDetailLabel>{t('error.functionality')}:</ErrorDetailLabel>
|
||||
<ErrorDetailValue>{error.functionality}</ErrorDetailValue>
|
||||
</ErrorDetailItem>
|
||||
)}
|
||||
</ErrorDetailList>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { AISDKError, APICallError, ImageModel, LanguageModel } from 'ai'
|
||||
import type { ImageModel, LanguageModel } from 'ai'
|
||||
import { generateObject, generateText, ModelMessage, streamObject, streamText } from 'ai'
|
||||
|
||||
export type StreamTextParams = Omit<Parameters<typeof streamText>[0], 'model' | 'messages'> &
|
||||
@ -27,6 +27,3 @@ export type StreamObjectParams = Omit<Parameters<typeof streamObject>[0], 'model
|
||||
export type GenerateObjectParams = Omit<Parameters<typeof generateObject>[0], 'model'>
|
||||
|
||||
export type AiSdkModel = LanguageModel | ImageModel
|
||||
|
||||
// 该类型用于格式化错误信息,目前只处理 APICallError,待扩展
|
||||
export type AiSdkErrorUnion = AISDKError | APICallError
|
||||
|
||||
@ -1,3 +1,25 @@
|
||||
import {
|
||||
AISDKError,
|
||||
APICallError,
|
||||
DownloadError,
|
||||
FinishReason,
|
||||
InvalidArgumentError,
|
||||
InvalidDataContentError,
|
||||
InvalidMessageRoleError,
|
||||
InvalidPromptError,
|
||||
InvalidToolInputError,
|
||||
JSONParseError,
|
||||
MessageConversionError,
|
||||
NoObjectGeneratedError,
|
||||
NoSuchModelError,
|
||||
NoSuchProviderError,
|
||||
NoSuchToolError,
|
||||
RetryError,
|
||||
ToolCallRepairError,
|
||||
TypeValidationError,
|
||||
UnsupportedFunctionalityError
|
||||
} from 'ai'
|
||||
|
||||
import { Serializable } from './serialize'
|
||||
|
||||
export interface SerializedError {
|
||||
@ -6,7 +28,7 @@ export interface SerializedError {
|
||||
stack: string | null
|
||||
[key: string]: Serializable
|
||||
}
|
||||
export const isSerializedError = (error: Record<string, unknown>): error is SerializedAiSdkError => {
|
||||
export const isSerializedError = (error: Record<string, unknown>): error is SerializedError => {
|
||||
return 'name' in error && 'message' in error && 'stack' in error
|
||||
}
|
||||
export interface SerializedAiSdkError extends SerializedError {
|
||||
@ -28,5 +50,276 @@ export interface SerializedAiSdkAPICallError extends SerializedAiSdkError {
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkAPICallError = (error: SerializedError): error is SerializedAiSdkAPICallError => {
|
||||
return isSerializedAiSdkError(error) && 'url' in error && 'requestBodyValues' in error && 'isRetryable' in error
|
||||
return (
|
||||
isSerializedAiSdkError(error) &&
|
||||
'url' in error &&
|
||||
'requestBodyValues' in error &&
|
||||
'statusCode' in error &&
|
||||
'responseHeaders' in error &&
|
||||
'responseBody' in error &&
|
||||
'isRetryable' in error &&
|
||||
'data' in error
|
||||
)
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkDownloadError extends SerializedAiSdkError {
|
||||
readonly url: string
|
||||
readonly statusCode: number | null
|
||||
readonly statusText: string | null
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkDownloadError = (error: SerializedError): error is SerializedAiSdkDownloadError => {
|
||||
return isSerializedAiSdkError(error) && 'url' in error && 'statusCode' in error && 'statusText' in error
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkInvalidArgumentError extends SerializedAiSdkError {
|
||||
readonly parameter: string
|
||||
readonly value: Serializable
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkInvalidArgumentError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkInvalidArgumentError => {
|
||||
return isSerializedAiSdkError(error) && 'parameter' in error && 'value' in error
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkInvalidDataContentError extends SerializedAiSdkError {
|
||||
readonly content: Serializable
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkInvalidDataContentError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkInvalidDataContentError => {
|
||||
return isSerializedAiSdkError(error) && 'content' in error
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkInvalidMessageRoleError extends SerializedAiSdkError {
|
||||
readonly role: string
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkInvalidMessageRoleError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkInvalidMessageRoleError => {
|
||||
return isSerializedAiSdkError(error) && 'role' in error
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkInvalidPromptError extends SerializedAiSdkError {
|
||||
readonly prompt: Serializable
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkInvalidPromptError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkInvalidPromptError => {
|
||||
return isSerializedAiSdkError(error) && 'prompt' in error
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkInvalidToolInputError extends SerializedAiSdkError {
|
||||
readonly toolName: string
|
||||
readonly toolInput: string
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkInvalidToolInputError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkInvalidToolInputError => {
|
||||
return isSerializedAiSdkError(error) && 'toolName' in error && 'toolInput' in error
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkJSONParseError extends SerializedAiSdkError {
|
||||
readonly text: string
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkJSONParseError = (error: SerializedError): error is SerializedAiSdkJSONParseError => {
|
||||
return isSerializedAiSdkError(error) && 'text' in error
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkMessageConversionError extends SerializedAiSdkError {
|
||||
readonly originalMessage: Serializable
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkMessageConversionError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkMessageConversionError => {
|
||||
return isSerializedAiSdkError(error) && 'originalMessage' in error
|
||||
}
|
||||
|
||||
// This type is not exported by aisdk.
|
||||
// See https://github.com/vercel/ai/issues/8466
|
||||
export interface SerializedAiSdkNoSpeechGeneratedError extends SerializedAiSdkError {
|
||||
readonly responses: string[]
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkNoSpeechGeneratedError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkNoSpeechGeneratedError => {
|
||||
return isSerializedAiSdkError(error) && 'responses' in error
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkNoObjectGeneratedError extends SerializedAiSdkError {
|
||||
readonly text: string | null
|
||||
readonly response: Serializable
|
||||
readonly usage: Serializable
|
||||
readonly finishReason: FinishReason | null
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkNoObjectGeneratedError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkNoObjectGeneratedError => {
|
||||
return (
|
||||
isSerializedAiSdkError(error) &&
|
||||
'text' in error &&
|
||||
'response' in error &&
|
||||
'usage' in error &&
|
||||
'finishReason' in error
|
||||
)
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkNoSuchModelError extends SerializedAiSdkError {
|
||||
readonly modelId: string
|
||||
readonly modelType: NoSuchModelError['modelType']
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkNoSuchModelError = (error: SerializedError): error is SerializedAiSdkNoSuchModelError => {
|
||||
return isSerializedAiSdkError(error) && 'modelId' in error && 'modelType' in error
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkNoSuchProviderError extends SerializedAiSdkNoSuchModelError {
|
||||
readonly providerId: string
|
||||
readonly availableProviders: string[]
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkNoSuchProviderError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkNoSuchProviderError => {
|
||||
return isSerializedAiSdkNoSuchModelError(error) && 'providerId' in error && 'availableProviders' in error
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkNoSuchToolError extends SerializedAiSdkError {
|
||||
readonly toolName: string
|
||||
readonly availableTools: string[] | null
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkNoSuchToolError = (error: SerializedError): error is SerializedAiSdkNoSuchToolError => {
|
||||
return isSerializedAiSdkError(error) && 'toolName' in error && 'availableTools' in error
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkRetryError extends SerializedAiSdkError {
|
||||
readonly reason: string
|
||||
readonly lastError: Serializable
|
||||
readonly errors: Serializable[]
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkRetryError = (error: SerializedError): error is SerializedAiSdkRetryError => {
|
||||
return isSerializedAiSdkError(error) && 'reason' in error && 'lastError' in error && 'errors' in error
|
||||
}
|
||||
|
||||
// This type is not exported by aisdk.
|
||||
// See: https://github.com/vercel/ai/pull/8464
|
||||
export interface SerializedAiSdkTooManyEmbeddingValuesForCallError extends SerializedAiSdkError {
|
||||
readonly provider: string
|
||||
readonly modelId: string
|
||||
readonly maxEmbeddingsPerCall: number
|
||||
readonly values: Serializable[]
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkTooManyEmbeddingValuesForCallError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkTooManyEmbeddingValuesForCallError => {
|
||||
return (
|
||||
isSerializedAiSdkError(error) &&
|
||||
'provider' in error &&
|
||||
'modelId' in error &&
|
||||
'maxEmbeddingsPerCall' in error &&
|
||||
'values' in error
|
||||
)
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkToolCallRepairError extends SerializedAiSdkError {
|
||||
readonly originalError: SerializedAiSdkNoSuchToolError | SerializedAiSdkInvalidToolInputError
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkToolCallRepairError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkToolCallRepairError => {
|
||||
return isSerializedAiSdkError(error) && 'originalError' in error
|
||||
}
|
||||
export interface SerializedAiSdkTypeValidationError extends SerializedAiSdkError {
|
||||
readonly value: Serializable
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkTypeValidationError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkTypeValidationError => {
|
||||
return isSerializedAiSdkError(error) && 'value' in error && !('parameter' in error)
|
||||
}
|
||||
|
||||
export interface SerializedAiSdkUnsupportedFunctionalityError extends SerializedAiSdkError {
|
||||
readonly functionality: string
|
||||
}
|
||||
|
||||
export const isSerializedAiSdkUnsupportedFunctionalityError = (
|
||||
error: SerializedError
|
||||
): error is SerializedAiSdkUnsupportedFunctionalityError => {
|
||||
return isSerializedAiSdkError(error) && 'functionality' in error
|
||||
}
|
||||
|
||||
export type AiSdkErrorUnion =
|
||||
| AISDKError
|
||||
| APICallError
|
||||
| DownloadError
|
||||
| InvalidArgumentError
|
||||
| InvalidDataContentError
|
||||
| InvalidMessageRoleError
|
||||
| InvalidPromptError
|
||||
| InvalidToolInputError
|
||||
| JSONParseError
|
||||
| MessageConversionError
|
||||
| NoObjectGeneratedError
|
||||
| NoSuchModelError
|
||||
| NoSuchProviderError
|
||||
| NoSuchToolError
|
||||
| RetryError
|
||||
| ToolCallRepairError
|
||||
| TypeValidationError
|
||||
| UnsupportedFunctionalityError
|
||||
|
||||
export type SerializedAiSdkErrorUnion =
|
||||
| SerializedAiSdkAPICallError
|
||||
| SerializedAiSdkDownloadError
|
||||
| SerializedAiSdkInvalidArgumentError
|
||||
| SerializedAiSdkInvalidDataContentError
|
||||
| SerializedAiSdkInvalidMessageRoleError
|
||||
| SerializedAiSdkInvalidPromptError
|
||||
| SerializedAiSdkInvalidToolInputError
|
||||
| SerializedAiSdkJSONParseError
|
||||
| SerializedAiSdkMessageConversionError
|
||||
| SerializedAiSdkNoSpeechGeneratedError
|
||||
| SerializedAiSdkNoObjectGeneratedError
|
||||
| SerializedAiSdkNoSuchModelError
|
||||
| SerializedAiSdkNoSuchProviderError
|
||||
| SerializedAiSdkNoSuchToolError
|
||||
| SerializedAiSdkRetryError
|
||||
| SerializedAiSdkToolCallRepairError
|
||||
| SerializedAiSdkTypeValidationError
|
||||
| SerializedAiSdkUnsupportedFunctionalityError
|
||||
|
||||
export const isSerializedAiSdkErrorUnion = (error: SerializedError): error is SerializedAiSdkErrorUnion => {
|
||||
return (
|
||||
isSerializedAiSdkAPICallError(error) ||
|
||||
isSerializedAiSdkDownloadError(error) ||
|
||||
isSerializedAiSdkInvalidArgumentError(error) ||
|
||||
isSerializedAiSdkInvalidDataContentError(error) ||
|
||||
isSerializedAiSdkInvalidMessageRoleError(error) ||
|
||||
isSerializedAiSdkInvalidPromptError(error) ||
|
||||
isSerializedAiSdkInvalidToolInputError(error) ||
|
||||
isSerializedAiSdkJSONParseError(error) ||
|
||||
isSerializedAiSdkMessageConversionError(error) ||
|
||||
isSerializedAiSdkNoObjectGeneratedError(error) ||
|
||||
isSerializedAiSdkNoSuchModelError(error) ||
|
||||
isSerializedAiSdkNoSuchProviderError(error) ||
|
||||
isSerializedAiSdkNoSuchToolError(error) ||
|
||||
isSerializedAiSdkRetryError(error) ||
|
||||
isSerializedAiSdkToolCallRepairError(error) ||
|
||||
isSerializedAiSdkTypeValidationError(error) ||
|
||||
isSerializedAiSdkUnsupportedFunctionalityError(error)
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
import { loggerService } from '@logger'
|
||||
import {
|
||||
AiSdkErrorUnion,
|
||||
isSerializedAiSdkAPICallError,
|
||||
SerializedAiSdkAPICallError,
|
||||
SerializedAiSdkError,
|
||||
SerializedAiSdkInvalidToolInputError,
|
||||
SerializedAiSdkNoSuchToolError,
|
||||
SerializedError
|
||||
} from '@renderer/types/error'
|
||||
import { AISDKError, APICallError } from 'ai'
|
||||
import { InvalidToolInputError, NoSuchToolError } from 'ai'
|
||||
import { t } from 'i18next'
|
||||
import z from 'zod'
|
||||
|
||||
import { safeSerialize } from './serialize'
|
||||
|
||||
const logger = loggerService.withContext('Utils:error')
|
||||
// const logger = loggerService.withContext('Utils:error')
|
||||
|
||||
export function getErrorDetails(err: any, seen = new WeakSet()): any {
|
||||
// Handle circular references
|
||||
@ -95,33 +96,77 @@ export const formatMcpError = (error: any) => {
|
||||
return error.message
|
||||
}
|
||||
|
||||
export const serializeError = (error: AISDKError): SerializedError => {
|
||||
const baseError = {
|
||||
name: error.name,
|
||||
message: error.message,
|
||||
const getBaseError = (error: Error) => {
|
||||
return {
|
||||
name: error.name ?? null,
|
||||
message: error.message ?? null,
|
||||
stack: error.stack ?? null,
|
||||
cause: error.cause ? String(error.cause) : null
|
||||
} as const
|
||||
}
|
||||
|
||||
const serializeInvalidToolInputError = (error: InvalidToolInputError): SerializedAiSdkInvalidToolInputError => {
|
||||
const baseError = getBaseError(error)
|
||||
return {
|
||||
...baseError,
|
||||
toolName: error.toolName,
|
||||
toolInput: error.toolInput
|
||||
} satisfies SerializedAiSdkInvalidToolInputError
|
||||
}
|
||||
|
||||
const serializeNoSuchToolError = (error: NoSuchToolError): SerializedAiSdkNoSuchToolError => {
|
||||
const baseError = getBaseError(error)
|
||||
return {
|
||||
...baseError,
|
||||
toolName: error.toolName ?? null,
|
||||
availableTools: error.availableTools ?? null
|
||||
} satisfies SerializedAiSdkNoSuchToolError
|
||||
}
|
||||
|
||||
export const serializeError = (error: AiSdkErrorUnion): SerializedError => {
|
||||
// 统一所有可能的错误字段
|
||||
const serializedError: SerializedError = {
|
||||
name: error.name ?? null,
|
||||
message: error.message ?? null,
|
||||
stack: error.stack ?? null,
|
||||
cause: safeSerialize(error.cause)
|
||||
}
|
||||
if (APICallError.isInstance(error)) {
|
||||
let content = error.message === '' ? error.responseBody || 'Unknown error' : error.message
|
||||
try {
|
||||
const obj = JSON.parse(content)
|
||||
content = obj.error.message
|
||||
} catch (e: any) {
|
||||
logger.warn('Error parsing error response body:', e)
|
||||
}
|
||||
return {
|
||||
...baseError,
|
||||
url: error.url,
|
||||
requestBodyValues: safeSerialize(error.requestBodyValues),
|
||||
statusCode: error.statusCode ?? null,
|
||||
responseBody: content,
|
||||
isRetryable: error.isRetryable,
|
||||
data: safeSerialize(error.data),
|
||||
responseHeaders: error.responseHeaders ?? null
|
||||
} satisfies SerializedAiSdkAPICallError
|
||||
}
|
||||
return baseError
|
||||
|
||||
if ('url' in error) serializedError.url = error.url
|
||||
if ('requestBodyValues' in error) serializedError.requestBodyValues = safeSerialize(error.requestBodyValues)
|
||||
if ('statusCode' in error) serializedError.statusCode = error.statusCode ?? null
|
||||
if ('responseBody' in error) serializedError.responseBody = error.responseBody ?? null
|
||||
if ('isRetryable' in error) serializedError.isRetryable = error.isRetryable
|
||||
if ('data' in error) serializedError.data = safeSerialize(error.data)
|
||||
if ('responseHeaders' in error) serializedError.responseHeaders = error.responseHeaders ?? null
|
||||
if ('statusText' in error) serializedError.statusText = error.statusText ?? null
|
||||
if ('parameter' in error) serializedError.parameter = error.parameter
|
||||
if ('value' in error) serializedError.value = safeSerialize(error.value)
|
||||
if ('content' in error) serializedError.content = safeSerialize(error.content)
|
||||
if ('role' in error) serializedError.role = error.role
|
||||
if ('prompt' in error) serializedError.prompt = safeSerialize(error.prompt)
|
||||
if ('toolName' in error) serializedError.toolName = error.toolName
|
||||
if ('toolInput' in error) serializedError.toolInput = error.toolInput
|
||||
if ('text' in error) serializedError.text = error.text ?? null
|
||||
if ('originalMessage' in error) serializedError.originalMessage = safeSerialize(error.originalMessage)
|
||||
if ('response' in error) serializedError.response = error.response ?? null
|
||||
if ('usage' in error) serializedError.usage = safeSerialize(error.usage)
|
||||
if ('finishReason' in error) serializedError.finishReason = error.finishReason ?? null
|
||||
if ('modelId' in error) serializedError.modelId = error.modelId
|
||||
if ('modelType' in error) serializedError.modelType = error.modelType
|
||||
if ('providerId' in error) serializedError.providerId = error.providerId
|
||||
if ('availableProviders' in error) serializedError.availableProviders = error.availableProviders
|
||||
if ('availableTools' in error) serializedError.availableTools = error.availableTools ?? null
|
||||
if ('reason' in error) serializedError.reason = error.reason
|
||||
if ('lastError' in error) serializedError.lastError = safeSerialize(error.lastError)
|
||||
if ('errors' in error) serializedError.errors = error.errors.map((err: unknown) => safeSerialize(err))
|
||||
if ('originalError' in error)
|
||||
serializedError.originalError = InvalidToolInputError.isInstance(error.originalError)
|
||||
? serializeInvalidToolInputError(error.originalError)
|
||||
: serializeNoSuchToolError(error.originalError)
|
||||
if ('functionality' in error) serializedError.functionality = error.functionality
|
||||
|
||||
return serializedError
|
||||
}
|
||||
/**
|
||||
* 格式化 Zod 验证错误信息为可读的字符串
|
||||
|
||||
Loading…
Reference in New Issue
Block a user