errors.js
1.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* LLMError —— 全包唯一的结构化错误类型。
*
* 单列一文件(而非塞进 index.js)以避免 base.js / llm.js 与公共面 index.js 形成
* 循环 import。index.js 再 re-export 它,对外仍是契约 §3 声明的 `LLMError`。
*/
/** @typedef {import('./map-error.js').LLMErrorReason} LLMErrorReason */
const ERROR_RESPONSE = {
contentFilter: { code: 'CONTENT_FILTER', statusCode: 400 },
}
/**
* 结构化 LLM 错误。永不吞错、永不 console 兜底——失败一律抛它。
*/
export class LLMError extends Error {
/**
* @param {object} info
* @param {string} info.provider 厂商标识(api_type)。
* @param {LLMErrorReason} info.reason 归一后的失败类别。
* @param {boolean} info.retryable 是否属于可重试类。
* @param {unknown} [info.cause] 原始异常 / 响应体。
* @param {string} [info.message] 可读消息(缺省由 reason 生成)。
* @param {Record<string, any>} [info.detail] 可持久化的结构化失败详情。
* @param {string|null} [info.provider_request_id] 供应商失败响应中的请求 ID。
*/
constructor({ provider, reason, retryable, cause, message, detail, provider_request_id = null }) {
const errorMessage = message ?? `[${provider}] LLM request failed: ${reason}`
super(errorMessage)
this.name = 'LLMError'
/** @type {string} */
this.provider = provider
/** @type {LLMErrorReason} */
this.reason = reason
/** @type {boolean} */
this.retryable = retryable
/** @type {Record<string, any>} */
this.detail = detail ?? { type: 'message', message: errorMessage }
/** @type {string|null} */
this.provider_request_id = provider_request_id
const response = ERROR_RESPONSE[reason]
if (response) {
this.code = response.code
this.statusCode = response.statusCode
}
if (cause !== undefined) this.cause = cause
}
}