返回 DeepSeek-Reasonix
inboxError.ts
根目录 / desktop / frontend / src / lib / inboxError.ts
1 import type { Locale } from "./i18n";
2
3 const CODE_PREFIX = "reasonix_error:";
4
5 // Message arrays share one stable code-to-index table so the three localized
6 // copies do not repeat object keys in the initial desktop bundle.
7 const CODE_INDEX = {
8 inbox_paused: 0,
9 inbox_capacity_items: 1,
10 inbox_capacity_bytes: 2,
11 inbox_item_too_large: 3,
12 inbox_item_not_found: 4,
13 inbox_invalid_state: 5,
14 inbox_schema_readonly: 6,
15 inbox_closed: 7,
16 inbox_empty: 8,
17 inbox_idempotency_conflict: 9,
18 channel_read_only: 10,
19 workspace_starting: 11,
20 workspace_start_failed: 12,
21 inbox_not_submitted: 16,
22 image_attachment_unreadable: 17,
23 inbox_target_transient: 18,
24 } as const;
25
26 type InboxErrorCode = keyof typeof CODE_INDEX;
27 const UNKNOWN_INDEX = 13;
28 const STEER_QUEUED_INDEX = 14;
29 const CANCEL_FAILED_INDEX = 15;
30
31 const ERROR_COPY: Record<Locale, readonly string[]> = {
32 en: [
33 "Inbox is paused",
34 "The inbox has reached its item limit",
35 "The inbox has reached its storage limit",
36 "This instruction is too large to add to the inbox",
37 "This inbox instruction no longer exists",
38 "This inbox instruction cannot be changed in its current state",
39 "This inbox was created by a newer version and is read-only",
40 "The inbox is closed",
41 "A blank instruction cannot be added",
42 "This instruction conflicts with an earlier submission",
43 "This session is read-only, so its inbox cannot be changed",
44 "The workspace is still starting. Try again shortly",
45 "The workspace failed to start",
46 "The inbox operation could not be completed",
47 "The turn ended before guidance could be applied. It will remain queued for the next turn",
48 "Cancel failed: {error}",
49 "The message was not sent. Refresh the session and try again",
50 "The image could not be read. Re-add it or try again",
51 "The session is switching. The message will be sent automatically.",
52 ],
53 zh: [
54 "收件箱已暂停",
55 "收件箱已达到条目上限",
56 "收件箱已达到容量上限",
57 "这条指令太大,无法加入收件箱",
58 "这条收件箱指令已不存在",
59 "当前状态下无法操作这条收件箱指令",
60 "收件箱由较新版本创建,当前只能读取",
61 "收件箱已关闭",
62 "不能加入空白指令",
63 "这条指令与已提交的请求冲突",
64 "当前会话为只读,无法修改收件箱",
65 "工作区还在启动,请稍后重试",
66 "工作区启动失败",
67 "无法完成收件箱操作",
68 "引导尚未应用时当前回合已结束;它会保留在队列中,供下一回合处理",
69 "取消失败:{error}",
70 "消息未发送,请刷新会话后重试",
71 "图片读取失败,请重新添加或重试",
72 "会话正在切换,消息会自动发出。",
73 ],
74 "zh-TW": [
75 "收件匣已暫停",
76 "收件匣已達到項目上限",
77 "收件匣已達到容量上限",
78 "這條指令太大,無法加入收件匣",
79 "這條收件匣指令已不存在",
80 "目前狀態下無法操作這條收件匣指令",
81 "收件匣由較新版本建立,目前只能讀取",
82 "收件匣已關閉",
83 "不能加入空白指令",
84 "這條指令與已提交的請求衝突",
85 "目前會話為唯讀,無法修改收件匣",
86 "工作區還在啟動,請稍後重試",
87 "工作區啟動失敗",
88 "無法完成收件匣操作",
89 "引導尚未套用時目前回合已結束;它會保留在佇列中,供下一回合處理",
90 "取消失敗:{error}",
91 "訊息未傳送,請重新整理會話後重試",
92 "圖片讀取失敗,請重新加入或重試",
93 "工作階段正在切換,訊息會自動送出。",
94 ],
95 };
96
97 const LEGACY_CODES: Record<string, InboxErrorCode> = {
98 "inbox is paused": "inbox_paused",
99 "session inbox item limit reached": "inbox_capacity_items",
100 "session inbox byte limit reached": "inbox_capacity_bytes",
101 "inbox item exceeds single-item size limit": "inbox_item_too_large",
102 "inbox item not found": "inbox_item_not_found",
103 "inbox item state does not allow this operation": "inbox_invalid_state",
104 "inbox schema is newer and is read-only": "inbox_schema_readonly",
105 "inbox is closed": "inbox_closed",
106 "inbox item body is empty": "inbox_empty",
107 "idempotency key was already used for different input": "inbox_idempotency_conflict",
108 "channel session is read-only": "channel_read_only",
109 "workspace is still starting": "workspace_starting",
110 };
111
112 function errorText(error: unknown): string {
113 return error instanceof Error ? error.message : String(error);
114 }
115
116 export function formatInboxError(error: unknown, locale: Locale): string {
117 const raw = errorText(error);
118 const encodedCode = raw.startsWith(CODE_PREFIX) ? raw.slice(CODE_PREFIX.length) : "";
119 const legacyCode = LEGACY_CODES[raw]
120 ?? (raw.startsWith("workspace failed to start:") ? "workspace_start_failed" : undefined);
121 const code = encodedCode || legacyCode;
122 if (!code) return raw;
123 const index = CODE_INDEX[code as InboxErrorCode];
124 return ERROR_COPY[locale][index ?? UNKNOWN_INDEX];
125 }
126
127 export function inboxSteerQueuedMessage(locale: Locale): string {
128 return ERROR_COPY[locale][STEER_QUEUED_INDEX];
129 }
130
131 export function isInboxItemMissing(error: unknown): boolean {
132 const raw = errorText(error);
133 return raw === `${CODE_PREFIX}inbox_item_not_found` || raw === "inbox item not found";
134 }
135
136 // The idle-tab code is consumed by the Stop path, never displayed.
137 export function isTurnNotRunning(error: unknown): boolean {
138 return errorText(error) === `${CODE_PREFIX}turn_not_running`;
139 }
140
141 // The tab moved to another session between reading the permission snapshot and
142 // applying the choice; the choice belongs to the session that was read.
143 export function isPermissionSessionChanged(error: unknown): boolean {
144 return errorText(error) === `${CODE_PREFIX}permission_session_changed`;
145 }
146
147 export function formatInboxCancelError(error: unknown, locale: Locale): string {
148 return ERROR_COPY[locale][CANCEL_FAILED_INDEX].replace("{error}", formatInboxError(error, locale));
149 }
150
150 lines TYPESCRIPT