82 lines
3.8 KiB
JavaScript
82 lines
3.8 KiB
JavaScript
// src/ai/ai-status.js —— AI 链路状态类型 / 错误码常量
|
||
//
|
||
// 把散落在 ai-controller / ai-chat-panel / ai-diff-panel 里的字面量集中
|
||
// 单一事实源;状态类型与 chat panel 的 notify / data-ai-state / dataset.status
|
||
// 三处渲染点保持一致。
|
||
//
|
||
// 错误码统一走 shared/ai-errors.js(CJS,main / preload / renderer 三处共用)。
|
||
// renderer 是 ESM 不能直接 require CJS,所以 preload 经 contextBridge 暴露
|
||
// window.api.aiErrors.AI_ERROR;本文件在模块顶层取这个值。单测(jsdom 无 preload)
|
||
// 走下方本地副本 —— 副本与 shared/ai-errors.js 同字面量,新增错误码时两边一起改,
|
||
// 由 tests/unit/ai-errors.test.js 校验两边一致。
|
||
|
||
/**
|
||
* AI 状态类型 —— renderer 端所有状态渲染都引用这里。
|
||
* 命名与 [data-ai-state] dataset 属性一一对应(见 ai-diff-panel / ai-chat-panel)。
|
||
*/
|
||
export const AI_STATUS = Object.freeze({
|
||
IDLE: 'idle',
|
||
RUNNING: 'running',
|
||
CANCELLED: 'cancelled',
|
||
ERROR: 'error',
|
||
SUCCESS: 'success',
|
||
DIFF: 'diff',
|
||
});
|
||
|
||
/**
|
||
* AI 错误码 —— 来自 shared/ai-errors.js#AI_ERROR。renderer 在模块顶层直接
|
||
* window.api?.aiErrors?.AI_ERROR 取值;取不到时(jsdom 单测 / preload 注入失败)
|
||
* 退化到下方本地副本。
|
||
*
|
||
* audit fix (CQ-MED-7):之前 renderer 各自维护一份字面量注释提醒"必须与 main/ai.js
|
||
* 同名常量一致"——实际曾漂移(renderer 旧版 ERR_TIMEOUT='ERR_TIMEOUT' 与 main 的
|
||
* 'AI_TIMEOUT' 对不上,aiErrorMessage switch 永不命中、永远走 fallback 'AI 修改失败')。
|
||
* 现在共享同一文件,注释提醒的"靠人同步"变成"靠文件同步"。
|
||
*/
|
||
const SHARED_AI_ERROR = (typeof window !== 'undefined'
|
||
&& window.api?.aiErrors?.AI_ERROR) || null;
|
||
|
||
const LOCAL_AI_ERROR_FALLBACK = Object.freeze({
|
||
NOT_CONFIGURED: 'AI_NOT_CONFIGURED',
|
||
NO_FILE: 'NO_FILE',
|
||
EDITOR_UNAVAILABLE: 'EDITOR_UNAVAILABLE',
|
||
IPC_FAILED: 'IPC_FAILED',
|
||
GENERATION_STALE: 'GENERATION_STALE',
|
||
FILE_CHANGED: 'FILE_CHANGED',
|
||
ERR_TIMEOUT: 'AI_TIMEOUT',
|
||
ERR_PROVIDER: 'AI_PROVIDER_ERROR',
|
||
ERR_FORMAT: 'AI_BAD_RESPONSE',
|
||
ERR_CANCELLED: 'AI_CANCELLED',
|
||
// Round 13 fix (H3):与 shared/ai-errors.js 对齐的本地副本,单测 / preload
|
||
// 注入失败时使用。tests/unit/ai-errors.test.js 会校验两边字面量一致。
|
||
INVALID_PROMPT: 'AI_INVALID_PROMPT',
|
||
INVALID_CONTENT: 'AI_INVALID_CONTENT',
|
||
CONTENT_TOO_LARGE: 'AI_CONTENT_TOO_LARGE',
|
||
PROMPT_TOO_LARGE: 'AI_PROMPT_TOO_LARGE',
|
||
});
|
||
|
||
export const AI_ERROR = SHARED_AI_ERROR || LOCAL_AI_ERROR_FALLBACK;
|
||
|
||
/**
|
||
* 把 AI 错误码映射成中文消息(用于 status bar chip / toast)。
|
||
* 单一映射点,避免各组件各自拼字符串。
|
||
*/
|
||
export function aiErrorMessage(code, fallback) {
|
||
switch (code) {
|
||
case AI_ERROR.NOT_CONFIGURED: return 'AI 未配置,已打开设置';
|
||
case AI_ERROR.NO_FILE: return '请先打开 Markdown 文件';
|
||
case AI_ERROR.EDITOR_UNAVAILABLE: return '无法读取编辑器内容,已取消本次 AI 请求';
|
||
case AI_ERROR.IPC_FAILED: return 'AI 通信异常';
|
||
case AI_ERROR.GENERATION_STALE: return '文件已切换,旧 AI 响应已丢弃';
|
||
case AI_ERROR.FILE_CHANGED: return '文件已被外部修改';
|
||
case AI_ERROR.ERR_TIMEOUT: return 'AI 请求超时';
|
||
case AI_ERROR.ERR_PROVIDER: return 'AI 服务返回异常';
|
||
case AI_ERROR.ERR_FORMAT: return 'AI 响应格式无法解析';
|
||
case AI_ERROR.ERR_CANCELLED: return '已取消 AI 请求';
|
||
case AI_ERROR.INVALID_PROMPT: return '修改要求不能为空';
|
||
case AI_ERROR.INVALID_CONTENT: return '当前文件内容无效';
|
||
case AI_ERROR.CONTENT_TOO_LARGE: return '文档过大,请拆分后再让 AI 修改';
|
||
case AI_ERROR.PROMPT_TOO_LARGE: return '提示词过长,请简化要求';
|
||
default: return fallback || 'AI 修改失败';
|
||
}
|
||
} |