diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index bc05799a29..3c233b0578 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -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}} 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", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 5ba0a6a672..a630bda814 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -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}} 获取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": "助手", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 66cebe35f5..98bb66b04c 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -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}} 获取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": "助手", diff --git a/src/renderer/src/i18n/translate/el-gr.json b/src/renderer/src/i18n/translate/el-gr.json index f60bb252d4..2ca2574bf0 100644 --- a/src/renderer/src/i18n/translate/el-gr.json +++ b/src/renderer/src/i18n/translate/el-gr.json @@ -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}} για να λάβετε ένα κλειδί 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": "βοηθός", diff --git a/src/renderer/src/i18n/translate/es-es.json b/src/renderer/src/i18n/translate/es-es.json index fad12693bc..94a6a0d0cd 100644 --- a/src/renderer/src/i18n/translate/es-es.json +++ b/src/renderer/src/i18n/translate/es-es.json @@ -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}} 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", diff --git a/src/renderer/src/i18n/translate/fr-fr.json b/src/renderer/src/i18n/translate/fr-fr.json index 7c9df58208..0c929c697d 100644 --- a/src/renderer/src/i18n/translate/fr-fr.json +++ b/src/renderer/src/i18n/translate/fr-fr.json @@ -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}} 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", diff --git a/src/renderer/src/i18n/translate/ja-jp.json b/src/renderer/src/i18n/translate/ja-jp.json index 97d2d4365f..10cd57db6a 100644 --- a/src/renderer/src/i18n/translate/ja-jp.json +++ b/src/renderer/src/i18n/translate/ja-jp.json @@ -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}}で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": "\nツール入力\n", + "toolName": "ツール名", "unknown": "不明なエラー", - "user_message_not_found": "元のユーザーメッセージを見つけることができませんでした" + "usage": "用量", + "user_message_not_found": "元のユーザーメッセージを見つけることができませんでした", + "value": "値", + "values": "値" }, "export": { "assistant": "アシスタント", diff --git a/src/renderer/src/i18n/translate/pt-pt.json b/src/renderer/src/i18n/translate/pt-pt.json index d3c1d61cfb..4127b25391 100644 --- a/src/renderer/src/i18n/translate/pt-pt.json +++ b/src/renderer/src/i18n/translate/pt-pt.json @@ -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}} 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", diff --git a/src/renderer/src/i18n/translate/ru-ru.json b/src/renderer/src/i18n/translate/ru-ru.json index 6bbc1136da..bae0264e88 100644 --- a/src/renderer/src/i18n/translate/ru-ru.json +++ b/src/renderer/src/i18n/translate/ru-ru.json @@ -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}} для получения ключа 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": "Ассистент", diff --git a/src/renderer/src/pages/home/Messages/Blocks/ErrorBlock.tsx b/src/renderer/src/pages/home/Messages/Blocks/ErrorBlock.tsx index f4eb8d1dd6..9fa6359472 100644 --- a/src/renderer/src/pages/home/Messages/Blocks/ErrorBlock.tsx +++ b/src/renderer/src/pages/home/Messages/Blocks/ErrorBlock.tsx @@ -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 = ({ open, onClose, erro const renderErrorDetails = (error?: SerializedError) => { if (!error) return
{t('error.unknown')}
- if (isSerializedAiSdkAPICallError(error)) { - return - } - if (isSerializedAiSdkError(error)) { + if (isSerializedAiSdkErrorUnion(error)) { return } 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 ( - + - {error.url && ( + {(isSerializedAiSdkAPICallError(error) || isSerializedAiSdkDownloadError(error)) && ( + <> + {error.statusCode && ( + + {t('error.statusCode')}: + {error.statusCode} + + )} + {error.url && ( + + {t('error.requestUrl')}: + {error.url} + + )} + + )} + + {isSerializedAiSdkAPICallError(error) && ( + <> + {error.requestBodyValues && ( + + {t('error.requestBodyValues')}: + + + )} + + {error.responseHeaders && ( + + {t('error.responseHeaders')}: + + + )} + + {error.responseBody && ( + + {t('error.responseBody')}: + + + )} + + {error.data && ( + + {t('error.data')}: + + + )} + + )} + + {isSerializedAiSdkDownloadError(error) && ( + <> + {error.statusText && ( + + {t('error.statusText')}: + {error.statusText} + + )} + + )} + + {isSerializedAiSdkInvalidArgumentError(error) && ( + <> + {error.parameter && ( + + {t('error.parameter')}: + {error.parameter} + + )} + + )} + + {(isSerializedAiSdkInvalidArgumentError(error) || isSerializedAiSdkTypeValidationError(error)) && ( + <> + {error.value && ( + + {t('error.value')}: + {safeToString(error.value)} + + )} + + )} + + {isSerializedAiSdkInvalidDataContentError(error) && ( - {t('error.requestUrl')}: - {error.url} + {t('error.content')}: + {safeToString(error.content)} )} - {requestBodyValues && ( + {isSerializedAiSdkInvalidMessageRoleError(error) && ( - {t('error.requestBodyValues')}: - + {t('error.role')}: + {error.role} )} - {error.statusCode && ( + {isSerializedAiSdkInvalidPromptError(error) && ( - {t('error.statusCode')}: - {error.statusCode} - - )} - {error.responseHeaders && ( - - {t('error.responseHeaders')}: - + {t('error.prompt')}: + {safeToString(error.prompt)} )} - {error.responseBody && ( + {isSerializedAiSdkInvalidToolInputError(error) && ( + <> + {error.toolName && ( + + {t('error.toolName')}: + {error.toolName} + + )} + {error.toolInput && ( + + {t('error.toolInput')}: + {error.toolInput} + + )} + + )} + + {(isSerializedAiSdkJSONParseError(error) || isSerializedAiSdkNoObjectGeneratedError(error)) && ( - {t('error.responseBody')}: - + {t('error.text')}: + {error.text} )} - {data && ( + {isSerializedAiSdkMessageConversionError(error) && ( - {t('error.data')}: - + {t('error.originalMessage')}: + {safeToString(error.originalMessage)} + + )} + + {isSerializedAiSdkNoSpeechGeneratedError(error) && ( + + {t('error.responses')}: + {error.responses.join(', ')} + + )} + + {isSerializedAiSdkNoObjectGeneratedError(error) && ( + <> + {error.response && ( + + {t('error.response')}: + {safeToString(error.response)} + + )} + {error.usage && ( + + {t('error.usage')}: + {safeToString(error.usage)} + + )} + {error.finishReason && ( + + {t('error.finishReason')}: + {error.finishReason} + + )} + + )} + + {(isSerializedAiSdkNoSuchModelError(error) || + isSerializedAiSdkNoSuchProviderError(error) || + isSerializedAiSdkTooManyEmbeddingValuesForCallError(error)) && ( + + {t('error.modelId')}: + {error.modelId} + + )} + + {(isSerializedAiSdkNoSuchModelError(error) || isSerializedAiSdkNoSuchProviderError(error)) && ( + + {t('error.modelType')}: + {error.modelType} + + )} + + {isSerializedAiSdkNoSuchProviderError(error) && ( + <> + + {t('error.providerId')}: + {error.providerId} + + + + {t('error.availableProviders')}: + {error.availableProviders.join(', ')} + + + )} + + {isSerializedAiSdkNoSuchToolError(error) && ( + <> + + {t('error.toolName')}: + {error.toolName} + + {error.availableTools && ( + + {t('error.availableTools')}: + {error.availableTools?.join(', ') || t('common.none')} + + )} + + )} + + {isSerializedAiSdkRetryError(error) && ( + <> + {error.reason && ( + + {t('error.reason')}: + {error.reason} + + )} + {error.lastError && ( + + {t('error.lastError')}: + {safeToString(error.lastError)} + + )} + {error.errors && error.errors.length > 0 && ( + + {t('error.errors')}: + {error.errors.map((e) => safeToString(e)).join('\n\n')} + + )} + + )} + + {isSerializedAiSdkTooManyEmbeddingValuesForCallError(error) && ( + <> + {error.provider && ( + + {t('error.provider')}: + {error.provider} + + )} + {error.maxEmbeddingsPerCall && ( + + {t('error.maxEmbeddingsPerCall')}: + {error.maxEmbeddingsPerCall} + + )} + {error.values && ( + + {t('error.values')}: + {safeToString(error.values)} + + )} + + )} + + {isSerializedAiSdkToolCallRepairError(error) && ( + + {t('error.originalError')}: + {safeToString(error.originalError)} + + )} + + {isSerializedAiSdkUnsupportedFunctionalityError(error) && ( + + {t('error.functionality')}: + {error.functionality} )} diff --git a/src/renderer/src/types/aiCoreTypes.ts b/src/renderer/src/types/aiCoreTypes.ts index 614211a5c7..e93218ab9e 100644 --- a/src/renderer/src/types/aiCoreTypes.ts +++ b/src/renderer/src/types/aiCoreTypes.ts @@ -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[0], 'model' | 'messages'> & @@ -27,6 +27,3 @@ export type StreamObjectParams = Omit[0], 'model export type GenerateObjectParams = Omit[0], 'model'> export type AiSdkModel = LanguageModel | ImageModel - -// 该类型用于格式化错误信息,目前只处理 APICallError,待扩展 -export type AiSdkErrorUnion = AISDKError | APICallError diff --git a/src/renderer/src/types/error.ts b/src/renderer/src/types/error.ts index 2439eaa123..c260c9c09f 100644 --- a/src/renderer/src/types/error.ts +++ b/src/renderer/src/types/error.ts @@ -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): error is SerializedAiSdkError => { +export const isSerializedError = (error: Record): 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) + ) } diff --git a/src/renderer/src/utils/error.ts b/src/renderer/src/utils/error.ts index 759c1cf512..a1640fd99d 100644 --- a/src/renderer/src/utils/error.ts +++ b/src/renderer/src/utils/error.ts @@ -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 验证错误信息为可读的字符串