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:
Phantom 2025-09-05 22:24:13 +08:00 committed by GitHub
parent 973cab57ab
commit fd83834fca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 919 additions and 87 deletions

View File

@ -773,6 +773,7 @@
"more": "More", "more": "More",
"name": "Name", "name": "Name",
"no_results": "No results", "no_results": "No results",
"none": "None",
"open": "Open", "open": "Open",
"paste": "Paste", "paste": "Paste",
"preview": "Preview", "preview": "Preview",
@ -817,6 +818,8 @@
"openai-response": "OpenAI-Response" "openai-response": "OpenAI-Response"
}, },
"error": { "error": {
"availableProviders": "Available Providers",
"availableTools": "Available Tools",
"backup": { "backup": {
"file_format": "Backup file format error" "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.", "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" "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", "detail": "Error Details",
"details": "Details", "details": "Details",
"errors": "Errors",
"finishReason": "Finish Reason",
"functionality": "Functionality",
"http": { "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", "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", "401": "Authentication failed. Please check if your API key is correct",
@ -855,16 +862,27 @@
"503": "Service unavailable. Please try again later", "503": "Service unavailable. Please try again later",
"504": "Gateway timeout. Please try again later" "504": "Gateway timeout. Please try again later"
}, },
"lastError": "Last Error",
"maxEmbeddingsPerCall": "Max Embeddings Per Call",
"message": "Error Message", "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.", "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": { "model": {
"exists": "Model already exists", "exists": "Model already exists",
"not_exists": "Model does not exist" "not_exists": "Model does not exist"
}, },
"modelId": "Model ID",
"modelType": "Model Type",
"name": "Error name", "name": "Error name",
"no_api_key": "API key is not configured", "no_api_key": "API key is not configured",
"originalError": "Original Error",
"originalMessage": "Original Message",
"parameter": "Parameter",
"pause_placeholder": "Paused", "pause_placeholder": "Paused",
"prompt": "Prompt",
"provider": "Provider",
"providerId": "Provider ID",
"provider_disabled": "Model provider is not enabled", "provider_disabled": "Model provider is not enabled",
"reason": "Reason",
"render": { "render": {
"description": "Failed to render message content. Please check if the message content format is correct", "description": "Failed to render message content. Please check if the message content format is correct",
"title": "Render Error" "title": "Render Error"
@ -872,13 +890,23 @@
"requestBody": "Request Body", "requestBody": "Request Body",
"requestBodyValues": "Request Body Values", "requestBodyValues": "Request Body Values",
"requestUrl": "Request URL", "requestUrl": "Request URL",
"response": "Response",
"responseBody": "Response Body", "responseBody": "Response Body",
"responseHeaders": "Response Header", "responseHeaders": "Response Header",
"responses": "Responses",
"role": "Role",
"stack": "Stack Trace", "stack": "Stack Trace",
"status": "Status Code", "status": "Status Code",
"statusCode": "Status code", "statusCode": "Status Code",
"statusText": "Status Text",
"text": "Text",
"toolInput": "Tool Input",
"toolName": "Tool Name",
"unknown": "Unknown error", "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": { "export": {
"assistant": "Assistant", "assistant": "Assistant",

View File

@ -773,6 +773,7 @@
"more": "更多", "more": "更多",
"name": "名称", "name": "名称",
"no_results": "无结果", "no_results": "无结果",
"none": "无",
"open": "打开", "open": "打开",
"paste": "粘贴", "paste": "粘贴",
"preview": "预览", "preview": "预览",
@ -817,6 +818,8 @@
"openai-response": "OpenAI-Response" "openai-response": "OpenAI-Response"
}, },
"error": { "error": {
"availableProviders": "可用提供商",
"availableTools": "可用工具",
"backup": { "backup": {
"file_format": "备份文件格式错误" "file_format": "备份文件格式错误"
}, },
@ -841,9 +844,13 @@
"quota_exceeded": "您今日免费配额已用尽,请前往 <provider>{{provider}}</provider> 获取API密钥配置API密钥后继续使用", "quota_exceeded": "您今日免费配额已用尽,请前往 <provider>{{provider}}</provider> 获取API密钥配置API密钥后继续使用",
"response": "出错了,如果没有配置 API 密钥,请前往设置 > 模型提供商中配置密钥" "response": "出错了,如果没有配置 API 密钥,请前往设置 > 模型提供商中配置密钥"
}, },
"content": "内容",
"data": "数据", "data": "数据",
"detail": "错误详情", "detail": "错误详情",
"details": "详细信息", "details": "详细信息",
"errors": "错误",
"finishReason": "结束原因",
"functionality": "功能",
"http": { "http": {
"400": "请求错误,请检查请求参数是否正确。如果修改了模型设置,请重置到默认设置", "400": "请求错误,请检查请求参数是否正确。如果修改了模型设置,请重置到默认设置",
"401": "身份验证失败,请检查 API 密钥是否正确", "401": "身份验证失败,请检查 API 密钥是否正确",
@ -855,16 +862,27 @@
"503": "服务不可用,请稍后再试", "503": "服务不可用,请稍后再试",
"504": "网关超时,请稍后再试" "504": "网关超时,请稍后再试"
}, },
"lastError": "最后错误",
"maxEmbeddingsPerCall": "每次调用的最大嵌入",
"message": "错误信息", "message": "错误信息",
"missing_user_message": "无法切换模型响应:原始用户消息已被删除。请发送新消息以获取此模型的响应", "missing_user_message": "无法切换模型响应:原始用户消息已被删除。请发送新消息以获取此模型的响应",
"model": { "model": {
"exists": "模型已存在", "exists": "模型已存在",
"not_exists": "模型不存在" "not_exists": "模型不存在"
}, },
"modelId": "模型 ID",
"modelType": "模型类型",
"name": "错误名称", "name": "错误名称",
"no_api_key": "API 密钥未配置", "no_api_key": "API 密钥未配置",
"originalError": "原错误",
"originalMessage": "原消息",
"parameter": "参数",
"pause_placeholder": "已中断", "pause_placeholder": "已中断",
"prompt": "提示词",
"provider": "提供商",
"providerId": "提供商 ID",
"provider_disabled": "模型提供商未启用", "provider_disabled": "模型提供商未启用",
"reason": "原因",
"render": { "render": {
"description": "消息内容渲染失败,请检查消息内容格式是否正确", "description": "消息内容渲染失败,请检查消息内容格式是否正确",
"title": "渲染错误" "title": "渲染错误"
@ -872,13 +890,23 @@
"requestBody": "请求内容", "requestBody": "请求内容",
"requestBodyValues": "请求体", "requestBodyValues": "请求体",
"requestUrl": "请求路径", "requestUrl": "请求路径",
"response": "响应",
"responseBody": "响应内容", "responseBody": "响应内容",
"responseHeaders": "响应首部", "responseHeaders": "响应首部",
"responses": "响应",
"role": "角色",
"stack": "堆栈信息", "stack": "堆栈信息",
"status": "状态码", "status": "状态码",
"statusCode": "状态码", "statusCode": "状态码",
"statusText": "状态文本",
"text": "文本",
"toolInput": "工具输入",
"toolName": "工具名",
"unknown": "未知错误", "unknown": "未知错误",
"user_message_not_found": "无法找到原始用户消息" "usage": "用量",
"user_message_not_found": "无法找到原始用户消息",
"value": "值",
"values": "值"
}, },
"export": { "export": {
"assistant": "助手", "assistant": "助手",

View File

@ -773,6 +773,7 @@
"more": "更多", "more": "更多",
"name": "名稱", "name": "名稱",
"no_results": "沒有結果", "no_results": "沒有結果",
"none": "無",
"open": "開啟", "open": "開啟",
"paste": "貼上", "paste": "貼上",
"preview": "預覽", "preview": "預覽",
@ -817,6 +818,8 @@
"openai-response": "OpenAI-Response" "openai-response": "OpenAI-Response"
}, },
"error": { "error": {
"availableProviders": "可用提供商",
"availableTools": "可用工具",
"backup": { "backup": {
"file_format": "備份檔案格式錯誤" "file_format": "備份檔案格式錯誤"
}, },
@ -841,9 +844,13 @@
"quota_exceeded": "您今日{{quota}}免费配额已用尽,请前往 <provider>{{provider}}</provider> 获取API密钥配置API密钥后继续使用", "quota_exceeded": "您今日{{quota}}免费配额已用尽,请前往 <provider>{{provider}}</provider> 获取API密钥配置API密钥后继续使用",
"response": "出現錯誤。如果尚未設定 API 金鑰,請前往設定 > 模型提供者中設定金鑰" "response": "出現錯誤。如果尚未設定 API 金鑰,請前往設定 > 模型提供者中設定金鑰"
}, },
"content": "內容",
"data": "数据", "data": "数据",
"detail": "錯誤詳情", "detail": "錯誤詳情",
"details": "詳細信息", "details": "詳細信息",
"errors": "錯誤",
"finishReason": "結束原因",
"functionality": "功能",
"http": { "http": {
"400": "請求錯誤,請檢查請求參數是否正確。如果修改了模型設定,請重設到預設設定", "400": "請求錯誤,請檢查請求參數是否正確。如果修改了模型設定,請重設到預設設定",
"401": "身份驗證失敗,請檢查 API 金鑰是否正確", "401": "身份驗證失敗,請檢查 API 金鑰是否正確",
@ -855,16 +862,27 @@
"503": "服務無法使用,請稍後再試", "503": "服務無法使用,請稍後再試",
"504": "閘道器超時,請稍後再試" "504": "閘道器超時,請稍後再試"
}, },
"lastError": "最後錯誤",
"maxEmbeddingsPerCall": "每次調用的最大嵌入",
"message": "錯誤訊息", "message": "錯誤訊息",
"missing_user_message": "無法切換模型回應:原始用戶訊息已被刪除。請發送新訊息以獲得此模型回應。", "missing_user_message": "無法切換模型回應:原始用戶訊息已被刪除。請發送新訊息以獲得此模型回應。",
"model": { "model": {
"exists": "模型已存在", "exists": "模型已存在",
"not_exists": "模型不存在" "not_exists": "模型不存在"
}, },
"modelId": "模型 ID",
"modelType": "模型類型",
"name": "錯誤名稱", "name": "錯誤名稱",
"no_api_key": "API 金鑰未設定", "no_api_key": "API 金鑰未設定",
"originalError": "原錯誤",
"originalMessage": "原消息",
"parameter": "參數",
"pause_placeholder": "回應已暫停", "pause_placeholder": "回應已暫停",
"prompt": "提示詞",
"provider": "提供商",
"providerId": "提供者 ID",
"provider_disabled": "模型供應商未啟用", "provider_disabled": "模型供應商未啟用",
"reason": "原因",
"render": { "render": {
"description": "消息內容渲染失敗,請檢查消息內容格式是否正確", "description": "消息內容渲染失敗,請檢查消息內容格式是否正確",
"title": "渲染錯誤" "title": "渲染錯誤"
@ -872,13 +890,23 @@
"requestBody": "請求內容", "requestBody": "請求內容",
"requestBodyValues": "请求体", "requestBodyValues": "请求体",
"requestUrl": "請求路徑", "requestUrl": "請求路徑",
"response": "響應",
"responseBody": "响应内容", "responseBody": "响应内容",
"responseHeaders": "响应首部", "responseHeaders": "响应首部",
"responses": "響應",
"role": "角色",
"stack": "堆棧信息", "stack": "堆棧信息",
"status": "狀態碼", "status": "狀態碼",
"statusCode": "狀態碼", "statusCode": "狀態碼",
"statusText": "狀態文本",
"text": "文本",
"toolInput": "工具輸入",
"toolName": "工具名",
"unknown": "未知錯誤", "unknown": "未知錯誤",
"user_message_not_found": "無法找到原始用戶訊息" "usage": "用量",
"user_message_not_found": "無法找到原始用戶訊息",
"value": "值",
"values": "值"
}, },
"export": { "export": {
"assistant": "助手", "assistant": "助手",

View File

@ -773,6 +773,7 @@
"more": "Περισσότερα", "more": "Περισσότερα",
"name": "Όνομα", "name": "Όνομα",
"no_results": "Δεν βρέθηκαν αποτελέσματα", "no_results": "Δεν βρέθηκαν αποτελέσματα",
"none": "Χωρίς",
"open": "Άνοιγμα", "open": "Άνοιγμα",
"paste": "Επικόλληση", "paste": "Επικόλληση",
"preview": "Προεπισκόπηση", "preview": "Προεπισκόπηση",
@ -817,6 +818,8 @@
"openai-response": "Απάντηση OpenAI" "openai-response": "Απάντηση OpenAI"
}, },
"error": { "error": {
"availableProviders": "Διαθέσιμοι πάροχοι",
"availableTools": "Διαθέσιμα εργαλεία",
"backup": { "backup": {
"file_format": "Λάθος μορφή αρχείου που επιστρέφεται" "file_format": "Λάθος μορφή αρχείου που επιστρέφεται"
}, },
@ -841,9 +844,13 @@
"quota_exceeded": "Η ημερήσια δωρεάν ποσόστωση {{quota}} tokens σας έχει εξαντληθεί. Παρακαλώ μεταβείτε στο <provider>{{provider}}</provider> για να λάβετε ένα κλειδί API και να ρυθμίσετε το κλειδί API για να συνεχίσετε τη χρήση.", "quota_exceeded": "Η ημερήσια δωρεάν ποσόστωση {{quota}} tokens σας έχει εξαντληθεί. Παρακαλώ μεταβείτε στο <provider>{{provider}}</provider> για να λάβετε ένα κλειδί API και να ρυθμίσετε το κλειδί API για να συνεχίσετε τη χρήση.",
"response": "Σφάλμα. Εάν δεν έχετε ρυθμίσει το κλειδί API, πηγαίνετε στο ρυθμισμένα > παρέχοντας το πρόσωπο του μοντέλου" "response": "Σφάλμα. Εάν δεν έχετε ρυθμίσει το κλειδί API, πηγαίνετε στο ρυθμισμένα > παρέχοντας το πρόσωπο του μοντέλου"
}, },
"content": "Περιεχόμενο",
"data": "δεδομένα", "data": "δεδομένα",
"detail": "Λεπτομέρειες σφάλματος", "detail": "Λεπτομέρειες σφάλματος",
"details": "Λεπτομέρειες", "details": "Λεπτομέρειες",
"errors": "Λάθος",
"finishReason": "Αιτία λήξης",
"functionality": "λειτουργία",
"http": { "http": {
"400": "Σφάλμα ζητήματος, παρακαλώ ελέγξτε αν τα παράμετρα του ζητήματος είναι σωστά. Εάν έχετε αλλάξει τις ρυθμίσεις του μοντέλου, επαναφέρετε τις προεπιλεγμένες ρυθμίσεις.", "400": "Σφάλμα ζητήματος, παρακαλώ ελέγξτε αν τα παράμετρα του ζητήματος είναι σωστά. Εάν έχετε αλλάξει τις ρυθμίσεις του μοντέλου, επαναφέρετε τις προεπιλεγμένες ρυθμίσεις.",
"401": "Αποτυχία επιβεβαίωσης ταυτότητας, παρακαλώ ελέγξτε αν η κλειδί API είναι σωστή", "401": "Αποτυχία επιβεβαίωσης ταυτότητας, παρακαλώ ελέγξτε αν η κλειδί API είναι σωστή",
@ -855,16 +862,27 @@
"503": "Η υπηρεσία δεν είναι διαθέσιμη, παρακαλώ δοκιμάστε ξανά", "503": "Η υπηρεσία δεν είναι διαθέσιμη, παρακαλώ δοκιμάστε ξανά",
"504": "Υπερχρονισμός φάρων, παρακαλώ δοκιμάστε ξανά" "504": "Υπερχρονισμός φάρων, παρακαλώ δοκιμάστε ξανά"
}, },
"lastError": "Τελευταίο σφάλμα",
"maxEmbeddingsPerCall": "Μέγιστες ενσωματώσεις ανά κλήση",
"message": "Μήνυμα σφάλματος", "message": "Μήνυμα σφάλματος",
"missing_user_message": "Αδυναμία εναλλαγής απάντησης μοντέλου: το αρχικό μήνυμα χρήστη έχει διαγραφεί. Παρακαλούμε στείλτε ένα νέο μήνυμα για να λάβετε απάντηση από αυτό το μοντέλο", "missing_user_message": "Αδυναμία εναλλαγής απάντησης μοντέλου: το αρχικό μήνυμα χρήστη έχει διαγραφεί. Παρακαλούμε στείλτε ένα νέο μήνυμα για να λάβετε απάντηση από αυτό το μοντέλο",
"model": { "model": {
"exists": "Το μοντέλο υπάρχει ήδη", "exists": "Το μοντέλο υπάρχει ήδη",
"not_exists": "Το μοντέλο δεν υπάρχει" "not_exists": "Το μοντέλο δεν υπάρχει"
}, },
"modelId": "Αναγνωριστικό μοντέλου",
"modelType": "Τύπος μοντέλου",
"name": "Λάθος όνομα", "name": "Λάθος όνομα",
"no_api_key": "Δεν έχετε ρυθμίσει το κλειδί API", "no_api_key": "Δεν έχετε ρυθμίσει το κλειδί API",
"originalError": "Αρχικό σφάλμα",
"originalMessage": "Αρχικό μήνυμα",
"parameter": "παράμετροι",
"pause_placeholder": "Διακόπηκε", "pause_placeholder": "Διακόπηκε",
"prompt": "συμβουλές",
"provider": "πάροχος",
"providerId": "Αναγνωριστικό παρόχου",
"provider_disabled": "Ο παρεχόμενος παροχός του μοντέλου δεν είναι ενεργοποιημένος", "provider_disabled": "Ο παρεχόμενος παροχός του μοντέλου δεν είναι ενεργοποιημένος",
"reason": "αιτία",
"render": { "render": {
"description": "Απέτυχε η ώθηση της εξίσωσης, παρακαλώ ελέγξτε το σωστό μορφάτι της", "description": "Απέτυχε η ώθηση της εξίσωσης, παρακαλώ ελέγξτε το σωστό μορφάτι της",
"title": "Σφάλμα Παρασκήνιου" "title": "Σφάλμα Παρασκήνιου"
@ -872,13 +890,23 @@
"requestBody": "Περιεχόμενο αιτήματος", "requestBody": "Περιεχόμενο αιτήματος",
"requestBodyValues": "Σώμα αιτήματος", "requestBodyValues": "Σώμα αιτήματος",
"requestUrl": "Μονοπάτι αιτήματος", "requestUrl": "Μονοπάτι αιτήματος",
"response": "απάντηση",
"responseBody": "απάντηση περιεχομένου", "responseBody": "απάντηση περιεχομένου",
"responseHeaders": "Επικεφαλίδες απόκρισης", "responseHeaders": "Επικεφαλίδες απόκρισης",
"responses": "ανταπόκριση",
"role": "ρόλος",
"stack": "Πληροφορίες στοίβας", "stack": "Πληροφορίες στοίβας",
"status": "Κωδικός κατάστασης", "status": "Κωδικός κατάστασης",
"statusCode": "Κωδικός κατάστασης", "statusCode": "Κωδικός κατάστασης",
"statusText": "Κείμενο κατάστασης",
"text": "κείμενο",
"toolInput": "εισαγωγή εργαλείου",
"toolName": "Όνομα εργαλείου",
"unknown": "Άγνωστο σφάλμα", "unknown": "Άγνωστο σφάλμα",
"user_message_not_found": "Αδυναμία εύρεσης της αρχικής μηνύματος χρήστη" "usage": "δοσολογία",
"user_message_not_found": "Αδυναμία εύρεσης της αρχικής μηνύματος χρήστη",
"value": "τιμή",
"values": "τιμή"
}, },
"export": { "export": {
"assistant": "βοηθός", "assistant": "βοηθός",

View File

@ -773,6 +773,7 @@
"more": "Más", "more": "Más",
"name": "Nombre", "name": "Nombre",
"no_results": "Sin resultados", "no_results": "Sin resultados",
"none": "无",
"open": "Abrir", "open": "Abrir",
"paste": "Pegar", "paste": "Pegar",
"preview": "Vista previa", "preview": "Vista previa",
@ -817,6 +818,8 @@
"openai-response": "Respuesta de OpenAI" "openai-response": "Respuesta de OpenAI"
}, },
"error": { "error": {
"availableProviders": "Proveedores disponibles",
"availableTools": "Herramientas disponibles",
"backup": { "backup": {
"file_format": "Formato de archivo de copia de seguridad incorrecto" "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.", "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" "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", "data": "datos",
"detail": "Detalles del error", "detail": "Detalles del error",
"details": "Detalles", "details": "Detalles",
"errors": "error",
"finishReason": "Razón de finalización",
"functionality": "función",
"http": { "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", "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", "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", "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" "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", "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": { "model": {
"exists": "El modelo ya existe", "exists": "El modelo ya existe",
"not_exists": "El modelo no existe" "not_exists": "El modelo no existe"
}, },
"modelId": "ID del modelo",
"modelType": "Tipo de modelo",
"name": "Nombre de error", "name": "Nombre de error",
"no_api_key": "La clave API no está configurada", "no_api_key": "La clave API no está configurada",
"originalError": "Error original",
"originalMessage": "mensaje original",
"parameter": "parámetro",
"pause_placeholder": "Interrumpido", "pause_placeholder": "Interrumpido",
"prompt": "prompt",
"provider": "proveedor",
"providerId": "ID del proveedor",
"provider_disabled": "El proveedor de modelos no está habilitado", "provider_disabled": "El proveedor de modelos no está habilitado",
"reason": "causa",
"render": { "render": {
"description": "Error al renderizar la fórmula, por favor, compruebe si el formato de la fórmula es correcto", "description": "Error al renderizar la fórmula, por favor, compruebe si el formato de la fórmula es correcto",
"title": "Error de renderizado" "title": "Error de renderizado"
@ -872,13 +890,23 @@
"requestBody": "Contenido de la solicitud", "requestBody": "Contenido de la solicitud",
"requestBodyValues": "Cuerpo de la solicitud", "requestBodyValues": "Cuerpo de la solicitud",
"requestUrl": "Ruta de solicitud", "requestUrl": "Ruta de solicitud",
"response": "respuesta",
"responseBody": "Contenido de la respuesta", "responseBody": "Contenido de la respuesta",
"responseHeaders": "Encabezados de respuesta", "responseHeaders": "Encabezados de respuesta",
"responses": "respuesta",
"role": "Rol",
"stack": "Información de la pila", "stack": "Información de la pila",
"status": "código de estado", "status": "Estado",
"statusCode": "código de estado", "statusCode": "Código de estado",
"statusText": "Texto de estado",
"text": "Texto",
"toolInput": "Herramienta de entrada",
"toolName": "Nombre de la herramienta",
"unknown": "Error desconocido", "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": { "export": {
"assistant": "Asistente", "assistant": "Asistente",

View File

@ -773,6 +773,7 @@
"more": "Plus", "more": "Plus",
"name": "Nom", "name": "Nom",
"no_results": "Aucun résultat", "no_results": "Aucun résultat",
"none": "Aucun",
"open": "Ouvrir", "open": "Ouvrir",
"paste": "Coller", "paste": "Coller",
"preview": "Aperçu", "preview": "Aperçu",
@ -817,6 +818,8 @@
"openai-response": "Réponse OpenAI" "openai-response": "Réponse OpenAI"
}, },
"error": { "error": {
"availableProviders": "Fournisseurs disponibles",
"availableTools": "Outils disponibles",
"backup": { "backup": {
"file_format": "Le format du fichier de sauvegarde est incorrect" "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.", "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é" "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", "data": "données",
"detail": "Détails de l'erreur", "detail": "Détails de l'erreur",
"details": "Informations détaillées", "details": "Informations détaillées",
"errors": "erreur",
"finishReason": "Raison de la fin",
"functionality": "fonction",
"http": { "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.", "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.", "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.", "503": "Service indisponible, veuillez réessayer plus tard.",
"504": "Délai d'expiration de la passerelle, veuillez réessayer plus tard." "504": "Délai d'expiration de la passerelle, veuillez réessayer plus tard."
}, },
"lastError": "Dernière erreur",
"maxEmbeddingsPerCall": "Maximum dintégrations par appel",
"message": "Erreur message", "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.", "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": { "model": {
"exists": "Le modèle existe déjà", "exists": "Le modèle existe déjà",
"not_exists": "Le modèle n'existe pas" "not_exists": "Le modèle n'existe pas"
}, },
"modelId": "ID du modèle",
"modelType": "Type de modèle",
"name": "Nom d'erreur", "name": "Nom d'erreur",
"no_api_key": "La clé API n'est pas configurée", "no_api_key": "La clé API n'est pas configurée",
"originalError": "Erreur d'origine",
"originalMessage": "message original",
"parameter": "paramètre",
"pause_placeholder": "Прервано", "pause_placeholder": "Прервано",
"prompt": "mot-clé",
"provider": "fournisseur",
"providerId": "ID du fournisseur",
"provider_disabled": "Le fournisseur de modèles n'est pas activé", "provider_disabled": "Le fournisseur de modèles n'est pas activé",
"reason": "raison",
"render": { "render": {
"description": "La formule n'a pas été rendue avec succès, veuillez vérifier si le format de la formule est correct", "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" "title": "Erreur de rendu"
@ -872,13 +890,23 @@
"requestBody": "Contenu de la demande", "requestBody": "Contenu de la demande",
"requestBodyValues": "Corps de la requête", "requestBodyValues": "Corps de la requête",
"requestUrl": "Chemin de la requête", "requestUrl": "Chemin de la requête",
"response": "réponse",
"responseBody": "Contenu de la réponse", "responseBody": "Contenu de la réponse",
"responseHeaders": "En-têtes de réponse", "responseHeaders": "En-têtes de réponse",
"responses": "réponse",
"role": "rôle",
"stack": "Informations de la pile", "stack": "Informations de la pile",
"status": "Code d'état", "status": "Code d'état",
"statusCode": "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": "Неизвестная ошибка", "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": { "export": {
"assistant": "Assistant", "assistant": "Assistant",

View File

@ -773,6 +773,7 @@
"more": "もっと", "more": "もっと",
"name": "名前", "name": "名前",
"no_results": "検索結果なし", "no_results": "検索結果なし",
"none": "無",
"open": "開く", "open": "開く",
"paste": "貼り付け", "paste": "貼り付け",
"preview": "プレビュー", "preview": "プレビュー",
@ -817,6 +818,8 @@
"openai-response": "OpenAI-Response" "openai-response": "OpenAI-Response"
}, },
"error": { "error": {
"availableProviders": "利用可能なプロバイダー",
"availableTools": "利用可能なツール",
"backup": { "backup": {
"file_format": "バックアップファイルの形式エラー" "file_format": "バックアップファイルの形式エラー"
}, },
@ -841,9 +844,13 @@
"quota_exceeded": "本日の{{quota}}無料クォータが使い果たされました。<provider>{{provider}}</provider>でAPIキーを取得し、APIキーを設定して使用を続けてください。", "quota_exceeded": "本日の{{quota}}無料クォータが使い果たされました。<provider>{{provider}}</provider>でAPIキーを取得し、APIキーを設定して使用を続けてください。",
"response": "エラーが発生しました。APIキーが設定されていない場合は、設定 > プロバイダーでキーを設定してください" "response": "エラーが発生しました。APIキーが設定されていない場合は、設定 > プロバイダーでキーを設定してください"
}, },
"content": "内容",
"data": "データ", "data": "データ",
"detail": "エラーの詳細", "detail": "エラーの詳細",
"details": "詳細", "details": "詳細",
"errors": "エラー",
"finishReason": "終了理由",
"functionality": "機能",
"http": { "http": {
"400": "リクエストに失敗しました。リクエストパラメータが正しいか確認してください。モデルの設定を変更した場合は、デフォルトの設定にリセットしてください", "400": "リクエストに失敗しました。リクエストパラメータが正しいか確認してください。モデルの設定を変更した場合は、デフォルトの設定にリセットしてください",
"401": "認証に失敗しました。APIキーが正しいか確認してください", "401": "認証に失敗しました。APIキーが正しいか確認してください",
@ -855,16 +862,27 @@
"503": "サービスが利用できません。後でもう一度試してください", "503": "サービスが利用できません。後でもう一度試してください",
"504": "ゲートウェイタイムアウトが発生しました。後でもう一度試してください" "504": "ゲートウェイタイムアウトが発生しました。後でもう一度試してください"
}, },
"lastError": "最後のエラー",
"maxEmbeddingsPerCall": "1回の呼び出しでの最大埋め込み数",
"message": "エラーメッセージ", "message": "エラーメッセージ",
"missing_user_message": "モデル応答を切り替えられません:元のユーザーメッセージが削除されました。このモデルで応答を得るには、新しいメッセージを送信してください", "missing_user_message": "モデル応答を切り替えられません:元のユーザーメッセージが削除されました。このモデルで応答を得るには、新しいメッセージを送信してください",
"model": { "model": {
"exists": "モデルが既に存在します", "exists": "モデルが既に存在します",
"not_exists": "モデルが存在しません" "not_exists": "モデルが存在しません"
}, },
"modelId": "モデル ID",
"modelType": "モデルの種類",
"name": "エラー名", "name": "エラー名",
"no_api_key": "APIキーが設定されていません", "no_api_key": "APIキーが設定されていません",
"originalError": "元のエラー",
"originalMessage": "元のメッセージ",
"parameter": "パラメータ",
"pause_placeholder": "応答を一時停止しました", "pause_placeholder": "応答を一時停止しました",
"prompt": "プロンプトを表示する",
"provider": "プロバイダー",
"providerId": "プロバイダーID",
"provider_disabled": "モデルプロバイダーが有効になっていません", "provider_disabled": "モデルプロバイダーが有効になっていません",
"reason": "原因",
"render": { "render": {
"description": "メッセージの内容のレンダリングに失敗しました。メッセージの内容の形式が正しいか確認してください", "description": "メッセージの内容のレンダリングに失敗しました。メッセージの内容の形式が正しいか確認してください",
"title": "レンダリングエラー" "title": "レンダリングエラー"
@ -872,13 +890,23 @@
"requestBody": "要求されたコンテンツ", "requestBody": "要求されたコンテンツ",
"requestBodyValues": "リクエストボディ", "requestBodyValues": "リクエストボディ",
"requestUrl": "リクエストパス", "requestUrl": "リクエストパス",
"response": "応答",
"responseBody": "レスポンス内容", "responseBody": "レスポンス内容",
"responseHeaders": "レスポンスヘッダー", "responseHeaders": "レスポンスヘッダー",
"responses": "応答",
"role": "キャラクター",
"stack": "スタック情報", "stack": "スタック情報",
"status": "ステータスコード", "status": "ステータスコード",
"statusCode": "ステータスコード", "statusCode": "ステータスコード",
"statusText": "状態テキスト",
"text": "テキスト",
"toolInput": "<translate_input>\nツール入力\n</translate_input>",
"toolName": "ツール名",
"unknown": "不明なエラー", "unknown": "不明なエラー",
"user_message_not_found": "元のユーザーメッセージを見つけることができませんでした" "usage": "用量",
"user_message_not_found": "元のユーザーメッセージを見つけることができませんでした",
"value": "値",
"values": "値"
}, },
"export": { "export": {
"assistant": "アシスタント", "assistant": "アシスタント",

View File

@ -773,6 +773,7 @@
"more": "Mais", "more": "Mais",
"name": "Nome", "name": "Nome",
"no_results": "Nenhum resultado", "no_results": "Nenhum resultado",
"none": "Nenhum",
"open": "Abrir", "open": "Abrir",
"paste": "Colar", "paste": "Colar",
"preview": "Pré-visualização", "preview": "Pré-visualização",
@ -817,6 +818,8 @@
"openai-response": "Resposta OpenAI" "openai-response": "Resposta OpenAI"
}, },
"error": { "error": {
"availableProviders": "Provedores disponíveis",
"availableTools": "Ferramentas disponíveis",
"backup": { "backup": {
"file_format": "Formato do arquivo de backup está incorreto" "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.", "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" "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", "data": "dados",
"detail": "Detalhes do erro", "detail": "Detalhes do erro",
"details": "Detalhes", "details": "Detalhes",
"errors": "erro",
"finishReason": "Motivo de término",
"functionality": "funcionalidade",
"http": { "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", "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", "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", "503": "Serviço indisponível, por favor tente novamente mais tarde",
"504": "Tempo de espera do gateway excedido, 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", "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", "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": { "model": {
"exists": "O modelo já existe", "exists": "O modelo já existe",
"not_exists": "O modelo não existe" "not_exists": "O modelo não existe"
}, },
"modelId": "ID do modelo",
"modelType": "Tipo de modelo",
"name": "Nome do erro", "name": "Nome do erro",
"no_api_key": "A chave da API não foi configurada", "no_api_key": "A chave da API não foi configurada",
"originalError": "Erro original",
"originalMessage": "Mensagem original",
"parameter": "parâmetro",
"pause_placeholder": "Interrompido", "pause_placeholder": "Interrompido",
"prompt": "prompt",
"provider": "fornecedor",
"providerId": "ID do fornecedor",
"provider_disabled": "O provedor de modelos está desativado", "provider_disabled": "O provedor de modelos está desativado",
"reason": "causa",
"render": { "render": {
"description": "Falha ao renderizar a fórmula, por favor verifique se o formato da fórmula está correto", "description": "Falha ao renderizar a fórmula, por favor verifique se o formato da fórmula está correto",
"title": "Erro de Renderização" "title": "Erro de Renderização"
@ -872,13 +890,23 @@
"requestBody": "Conteúdo da solicitação", "requestBody": "Conteúdo da solicitação",
"requestBodyValues": "Corpo da solicitação", "requestBodyValues": "Corpo da solicitação",
"requestUrl": "Caminho da solicitação", "requestUrl": "Caminho da solicitação",
"response": "resposta",
"responseBody": "Conteúdo da resposta", "responseBody": "Conteúdo da resposta",
"responseHeaders": "Cabeçalho de resposta", "responseHeaders": "Cabeçalho de resposta",
"responses": "resposta",
"role": "personagem",
"stack": "Informações da pilha", "stack": "Informações da pilha",
"status": "Código de status", "status": "Código de status",
"statusCode": "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", "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": { "export": {
"assistant": "Assistente", "assistant": "Assistente",

View File

@ -773,6 +773,7 @@
"more": "Ещё", "more": "Ещё",
"name": "Имя", "name": "Имя",
"no_results": "Результатов не найдено", "no_results": "Результатов не найдено",
"none": "без",
"open": "Открыть", "open": "Открыть",
"paste": "Вставить", "paste": "Вставить",
"preview": "Предварительный просмотр", "preview": "Предварительный просмотр",
@ -817,6 +818,8 @@
"openai-response": "OpenAI-Response" "openai-response": "OpenAI-Response"
}, },
"error": { "error": {
"availableProviders": "Доступные провайдеры",
"availableTools": "Доступные инструменты",
"backup": { "backup": {
"file_format": "Ошибка формата файла резервной копии" "file_format": "Ошибка формата файла резервной копии"
}, },
@ -841,9 +844,13 @@
"quota_exceeded": "Ваша ежедневная {{quota}} бесплатная квота исчерпана. Пожалуйста, перейдите в <provider>{{provider}}</provider> для получения ключа API и настройте ключ API для продолжения использования.", "quota_exceeded": "Ваша ежедневная {{quota}} бесплатная квота исчерпана. Пожалуйста, перейдите в <provider>{{provider}}</provider> для получения ключа API и настройте ключ API для продолжения использования.",
"response": "Что-то пошло не так. Пожалуйста, проверьте, установлен ли ваш ключ API в Настройки > Провайдеры" "response": "Что-то пошло не так. Пожалуйста, проверьте, установлен ли ваш ключ API в Настройки > Провайдеры"
}, },
"content": "Содержание",
"data": "данные", "data": "данные",
"detail": "Детали ошибки", "detail": "Детали ошибки",
"details": "Подробности", "details": "Подробности",
"errors": "ошибка",
"finishReason": "Причина завершения",
"functionality": "функция",
"http": { "http": {
"400": "Не удалось выполнить запрос. Пожалуйста, проверьте, правильно ли настроены параметры запроса. Если вы изменили настройки модели, пожалуйста, сбросьте их до значений по умолчанию", "400": "Не удалось выполнить запрос. Пожалуйста, проверьте, правильно ли настроены параметры запроса. Если вы изменили настройки модели, пожалуйста, сбросьте их до значений по умолчанию",
"401": "Не удалось пройти аутентификацию. Пожалуйста, проверьте, правильно ли настроен ваш ключ API", "401": "Не удалось пройти аутентификацию. Пожалуйста, проверьте, правильно ли настроен ваш ключ API",
@ -855,16 +862,27 @@
"503": "Серверная ошибка. Пожалуйста, попробуйте позже", "503": "Серверная ошибка. Пожалуйста, попробуйте позже",
"504": "Серверная ошибка. Пожалуйста, попробуйте позже" "504": "Серверная ошибка. Пожалуйста, попробуйте позже"
}, },
"lastError": "Последняя ошибка",
"maxEmbeddingsPerCall": "Максимальное количество вложений на вызов",
"message": "Сообщение об ошибке", "message": "Сообщение об ошибке",
"missing_user_message": "Невозможно изменить модель ответа: исходное сообщение пользователя было удалено. Пожалуйста, отправьте новое сообщение, чтобы получить ответ от этой модели", "missing_user_message": "Невозможно изменить модель ответа: исходное сообщение пользователя было удалено. Пожалуйста, отправьте новое сообщение, чтобы получить ответ от этой модели",
"model": { "model": {
"exists": "Модель уже существует", "exists": "Модель уже существует",
"not_exists": "Модель не существует" "not_exists": "Модель не существует"
}, },
"name": "错误名称", "modelId": "ID модели",
"modelType": "Тип модели",
"name": "Название ошибки",
"no_api_key": "Ключ API не настроен", "no_api_key": "Ключ API не настроен",
"originalError": "Исходная ошибка",
"originalMessage": "исходное сообщение",
"parameter": "параметр",
"pause_placeholder": "Получение ответа приостановлено", "pause_placeholder": "Получение ответа приостановлено",
"prompt": "подсказка",
"provider": "поставщик",
"providerId": "ID поставщика",
"provider_disabled": "Провайдер моделей не включен", "provider_disabled": "Провайдер моделей не включен",
"reason": "причина",
"render": { "render": {
"description": "Не удалось рендерить содержимое сообщения. Пожалуйста, проверьте, правильно ли формат содержимого сообщения", "description": "Не удалось рендерить содержимое сообщения. Пожалуйста, проверьте, правильно ли формат содержимого сообщения",
"title": "Ошибка рендеринга" "title": "Ошибка рендеринга"
@ -872,13 +890,23 @@
"requestBody": "Запрашиваемый контент", "requestBody": "Запрашиваемый контент",
"requestBodyValues": "Тело запроса", "requestBodyValues": "Тело запроса",
"requestUrl": "Путь запроса", "requestUrl": "Путь запроса",
"response": "ответ",
"responseBody": "Содержание ответа", "responseBody": "Содержание ответа",
"responseHeaders": "Заголовки ответа", "responseHeaders": "Заголовки ответа",
"responses": "отклик",
"role": "роль",
"stack": "Информация стека", "stack": "Информация стека",
"status": "Код статуса", "status": "Код статуса",
"statusCode": "Код состояния", "statusCode": "Код состояния",
"statusText": "Текст состояния",
"text": "текст",
"toolInput": "ввод инструмента",
"toolName": "имя инструмента",
"unknown": "Неизвестная ошибка", "unknown": "Неизвестная ошибка",
"user_message_not_found": "Не удалось найти исходное сообщение пользователя" "usage": "Дозировка",
"user_message_not_found": "Не удалось найти исходное сообщение пользователя",
"value": "значение",
"values": "значение"
}, },
"export": { "export": {
"assistant": "Ассистент", "assistant": "Ассистент",

View File

@ -6,10 +6,29 @@ import { useAppDispatch } from '@renderer/store'
import { removeBlocksThunk } from '@renderer/store/thunk/messageThunk' import { removeBlocksThunk } from '@renderer/store/thunk/messageThunk'
import { import {
isSerializedAiSdkAPICallError, isSerializedAiSdkAPICallError,
isSerializedAiSdkDownloadError,
isSerializedAiSdkError, isSerializedAiSdkError,
isSerializedAiSdkErrorUnion,
isSerializedAiSdkInvalidArgumentError,
isSerializedAiSdkInvalidDataContentError,
isSerializedAiSdkInvalidMessageRoleError,
isSerializedAiSdkInvalidPromptError,
isSerializedAiSdkInvalidToolInputError,
isSerializedAiSdkJSONParseError,
isSerializedAiSdkMessageConversionError,
isSerializedAiSdkNoObjectGeneratedError,
isSerializedAiSdkNoSpeechGeneratedError,
isSerializedAiSdkNoSuchModelError,
isSerializedAiSdkNoSuchProviderError,
isSerializedAiSdkNoSuchToolError,
isSerializedAiSdkRetryError,
isSerializedAiSdkToolCallRepairError,
isSerializedAiSdkTooManyEmbeddingValuesForCallError,
isSerializedAiSdkTypeValidationError,
isSerializedAiSdkUnsupportedFunctionalityError,
isSerializedError, isSerializedError,
SerializedAiSdkAPICallError,
SerializedAiSdkError, SerializedAiSdkError,
SerializedAiSdkErrorUnion,
SerializedError SerializedError
} from '@renderer/types/error' } from '@renderer/types/error'
import type { ErrorMessageBlock, Message } from '@renderer/types/newMessage' import type { ErrorMessageBlock, Message } from '@renderer/types/newMessage'
@ -167,10 +186,7 @@ const ErrorDetailModal: React.FC<ErrorDetailModalProps> = ({ open, onClose, erro
const renderErrorDetails = (error?: SerializedError) => { const renderErrorDetails = (error?: SerializedError) => {
if (!error) return <div>{t('error.unknown')}</div> if (!error) return <div>{t('error.unknown')}</div>
if (isSerializedAiSdkAPICallError(error)) { if (isSerializedAiSdkErrorUnion(error)) {
return <AiApiCallError error={error} />
}
if (isSerializedAiSdkError(error)) {
return <AiSdkError error={error} /> return <AiSdkError error={error} />
} }
return ( return (
@ -290,7 +306,7 @@ const BuiltinError = ({ error }: { error: SerializedError }) => {
} }
// 作为 base渲染公共字段应当在 ErrorDetailList 中渲染 // 作为 base渲染公共字段应当在 ErrorDetailList 中渲染
const AiSdkError = ({ error }: { error: SerializedAiSdkError }) => { const AiSdkErrorBase = ({ error }: { error: SerializedAiSdkError }) => {
const { t } = useTranslation() const { t } = useTranslation()
const cause = error.cause const cause = error.cause
return ( return (
@ -306,60 +322,289 @@ const AiSdkError = ({ error }: { error: SerializedAiSdkError }) => {
) )
} }
const AiApiCallError = ({ error }: { error: SerializedAiSdkAPICallError }) => { const AiSdkError = ({ error }: { error: SerializedAiSdkErrorUnion }) => {
const { t } = useTranslation() const { t } = useTranslation()
// 这些字段是 unknown 类型,暂且不清楚都可能是什么类型,总之先覆盖下大部分场景
const requestBodyValues = safeToString(error.requestBodyValues)
const data = safeToString(error.data)
return ( return (
<ErrorDetailList> <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> <ErrorDetailItem>
<ErrorDetailLabel>{t('error.requestUrl')}:</ErrorDetailLabel> <ErrorDetailLabel>{t('error.content')}:</ErrorDetailLabel>
<ErrorDetailValue>{error.url}</ErrorDetailValue> <ErrorDetailValue>{safeToString(error.content)}</ErrorDetailValue>
</ErrorDetailItem> </ErrorDetailItem>
)} )}
{requestBodyValues && ( {isSerializedAiSdkInvalidMessageRoleError(error) && (
<ErrorDetailItem> <ErrorDetailItem>
<ErrorDetailLabel>{t('error.requestBodyValues')}:</ErrorDetailLabel> <ErrorDetailLabel>{t('error.role')}:</ErrorDetailLabel>
<CodeViewer value={safeToString(error.requestBodyValues)} className="source-view" language="json" expanded /> <ErrorDetailValue>{error.role}</ErrorDetailValue>
</ErrorDetailItem> </ErrorDetailItem>
)} )}
{error.statusCode && ( {isSerializedAiSdkInvalidPromptError(error) && (
<ErrorDetailItem> <ErrorDetailItem>
<ErrorDetailLabel>{t('error.statusCode')}:</ErrorDetailLabel> <ErrorDetailLabel>{t('error.prompt')}:</ErrorDetailLabel>
<ErrorDetailValue>{error.statusCode}</ErrorDetailValue> <ErrorDetailValue>{safeToString(error.prompt)}</ErrorDetailValue>
</ErrorDetailItem>
)}
{error.responseHeaders && (
<ErrorDetailItem>
<ErrorDetailLabel>{t('error.responseHeaders')}:</ErrorDetailLabel>
<CodeViewer
value={JSON.stringify(error.responseHeaders, null, 2)}
className="source-view"
language="json"
expanded
/>
</ErrorDetailItem> </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> <ErrorDetailItem>
<ErrorDetailLabel>{t('error.responseBody')}:</ErrorDetailLabel> <ErrorDetailLabel>{t('error.text')}:</ErrorDetailLabel>
<CodeViewer value={error.responseBody} className="source-view" language="json" expanded /> <ErrorDetailValue>{error.text}</ErrorDetailValue>
</ErrorDetailItem> </ErrorDetailItem>
)} )}
{data && ( {isSerializedAiSdkMessageConversionError(error) && (
<ErrorDetailItem> <ErrorDetailItem>
<ErrorDetailLabel>{t('error.data')}:</ErrorDetailLabel> <ErrorDetailLabel>{t('error.originalMessage')}:</ErrorDetailLabel>
<CodeViewer value={safeToString(error.data)} className="source-view" language="json" expanded /> <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> </ErrorDetailItem>
)} )}
</ErrorDetailList> </ErrorDetailList>

View File

@ -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' import { generateObject, generateText, ModelMessage, streamObject, streamText } from 'ai'
export type StreamTextParams = Omit<Parameters<typeof streamText>[0], 'model' | 'messages'> & 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 GenerateObjectParams = Omit<Parameters<typeof generateObject>[0], 'model'>
export type AiSdkModel = LanguageModel | ImageModel export type AiSdkModel = LanguageModel | ImageModel
// 该类型用于格式化错误信息,目前只处理 APICallError待扩展
export type AiSdkErrorUnion = AISDKError | APICallError

View File

@ -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' import { Serializable } from './serialize'
export interface SerializedError { export interface SerializedError {
@ -6,7 +28,7 @@ export interface SerializedError {
stack: string | null stack: string | null
[key: string]: Serializable [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 return 'name' in error && 'message' in error && 'stack' in error
} }
export interface SerializedAiSdkError extends SerializedError { export interface SerializedAiSdkError extends SerializedError {
@ -28,5 +50,276 @@ export interface SerializedAiSdkAPICallError extends SerializedAiSdkError {
} }
export const isSerializedAiSdkAPICallError = (error: SerializedError): error is SerializedAiSdkAPICallError => { 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)
)
} }

View File

@ -1,17 +1,18 @@
import { loggerService } from '@logger'
import { import {
AiSdkErrorUnion,
isSerializedAiSdkAPICallError, isSerializedAiSdkAPICallError,
SerializedAiSdkAPICallError,
SerializedAiSdkError, SerializedAiSdkError,
SerializedAiSdkInvalidToolInputError,
SerializedAiSdkNoSuchToolError,
SerializedError SerializedError
} from '@renderer/types/error' } from '@renderer/types/error'
import { AISDKError, APICallError } from 'ai' import { InvalidToolInputError, NoSuchToolError } from 'ai'
import { t } from 'i18next' import { t } from 'i18next'
import z from 'zod' import z from 'zod'
import { safeSerialize } from './serialize' 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 { export function getErrorDetails(err: any, seen = new WeakSet()): any {
// Handle circular references // Handle circular references
@ -95,33 +96,77 @@ export const formatMcpError = (error: any) => {
return error.message return error.message
} }
export const serializeError = (error: AISDKError): SerializedError => { const getBaseError = (error: Error) => {
const baseError = { return {
name: error.name, name: error.name ?? null,
message: error.message, message: error.message ?? null,
stack: error.stack ?? null, stack: error.stack ?? null,
cause: error.cause ? String(error.cause) : 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 if ('url' in error) serializedError.url = error.url
try { if ('requestBodyValues' in error) serializedError.requestBodyValues = safeSerialize(error.requestBodyValues)
const obj = JSON.parse(content) if ('statusCode' in error) serializedError.statusCode = error.statusCode ?? null
content = obj.error.message if ('responseBody' in error) serializedError.responseBody = error.responseBody ?? null
} catch (e: any) { if ('isRetryable' in error) serializedError.isRetryable = error.isRetryable
logger.warn('Error parsing error response body:', e) if ('data' in error) serializedError.data = safeSerialize(error.data)
} if ('responseHeaders' in error) serializedError.responseHeaders = error.responseHeaders ?? null
return { if ('statusText' in error) serializedError.statusText = error.statusText ?? null
...baseError, if ('parameter' in error) serializedError.parameter = error.parameter
url: error.url, if ('value' in error) serializedError.value = safeSerialize(error.value)
requestBodyValues: safeSerialize(error.requestBodyValues), if ('content' in error) serializedError.content = safeSerialize(error.content)
statusCode: error.statusCode ?? null, if ('role' in error) serializedError.role = error.role
responseBody: content, if ('prompt' in error) serializedError.prompt = safeSerialize(error.prompt)
isRetryable: error.isRetryable, if ('toolName' in error) serializedError.toolName = error.toolName
data: safeSerialize(error.data), if ('toolInput' in error) serializedError.toolInput = error.toolInput
responseHeaders: error.responseHeaders ?? null if ('text' in error) serializedError.text = error.text ?? null
} satisfies SerializedAiSdkAPICallError if ('originalMessage' in error) serializedError.originalMessage = safeSerialize(error.originalMessage)
} if ('response' in error) serializedError.response = error.response ?? null
return baseError 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 * Zod