📄 classifier.ts • 7363 bytes
/**
* 容错系统 - 错误分类器
* Phase 4: 智能错误分类
*/
import {
type ErrorClassification,
type ErrorCategory,
type ErrorSeverity,
type ClassifierConfig
} from './types'
/** 错误模式匹配规则 */
interface ErrorPattern {
pattern: RegExp
category: ErrorCategory
severity: ErrorSeverity
message: string
recoverable: boolean
action: string
}
/** 内置错误模式 */
const ERROR_PATTERNS: ErrorPattern[] = [
// 网络错误
{
pattern: /ECONNREFUSED|ENOTFOUND|ECONNRESET|ETIMEDOUT|ENETUNREACH|connection\s*refused/i,
category: 'network',
severity: 'medium',
message: '网络连接失败',
recoverable: true,
action: '检查网络连接后重试',
},
{
pattern: /fetch.*failed|network.*error|net::ERR/i,
category: 'network',
severity: 'medium',
message: '网络请求失败',
recoverable: true,
action: '稍后重试或检查网络',
},
// 超时错误
{
pattern: /timeout|timed?\s*out|ETIMEDOUT/i,
category: 'timeout',
severity: 'medium',
message: '操作超时',
recoverable: true,
action: '增加超时时间后重试',
},
{
pattern: /maxTurns|exceeded.*limit/i,
category: 'timeout',
severity: 'low',
message: '达到循环上限',
recoverable: false,
action: '简化任务或增加限制',
},
// 语法错误
{
pattern: /syntax.*error|unexpected.*token|parse.*error/i,
category: 'syntax',
severity: 'high',
message: '代码语法错误',
recoverable: false,
action: '修复代码语法',
},
{
pattern: /unexpected end|unterminated|string/i,
category: 'syntax',
severity: 'high',
message: '代码格式错误',
recoverable: false,
action: '检查代码完整性',
},
// 类型错误
{
pattern: /type.*error|is not a|TypeError|Cannot read property/i,
category: 'type',
severity: 'high',
message: '类型错误',
recoverable: false,
action: '检查类型定义和使用',
},
{
pattern: /undefined is not|is undefined|null.*is not|cannot.*undefined/i,
category: 'type',
severity: 'medium',
message: '变量未定义或为空',
recoverable: false,
action: '添加空值检查',
},
// 运行时错误
{
pattern: /runtime.*error|ReferenceError|EvalError|RangeError/i,
category: 'runtime',
severity: 'high',
message: '运行时错误',
recoverable: false,
action: '检查代码逻辑',
},
// 资源不足
{
pattern: /memory|heap|out of memory|OOM|allocation.*failed/i,
category: 'resource',
severity: 'critical',
message: '内存不足',
recoverable: true,
action: '释放内存或增加资源',
},
{
pattern: /disk.*full|no.*space|ENOSPC/i,
category: 'resource',
severity: 'high',
message: '磁盘空间不足',
recoverable: false,
action: '清理磁盘空间',
},
{
pattern: /max.*file.*size|file.*too.*large/i,
category: 'resource',
severity: 'medium',
message: '文件过大',
recoverable: false,
action: '拆分文件或压缩',
},
// 权限错误
{
pattern: /permission.*denied|EACCES|EPERM|unauthorized/i,
category: 'permission',
severity: 'high',
message: '权限不足',
recoverable: false,
action: '检查文件权限',
},
// 未找到
{
pattern: /not found|ENOENT|Cannot find|does not exist/i,
category: 'not_found',
severity: 'medium',
message: '资源未找到',
recoverable: false,
action: '检查路径是否正确',
},
{
pattern: /module.*not.*found|require.*failed/i,
category: 'not_found',
severity: 'high',
message: '模块未找到',
recoverable: true,
action: '安装依赖或检查路径',
},
// 验证失败
{
pattern: /validation.*failed|invalid.*input|schema.*error/i,
category: 'validation',
severity: 'medium',
message: '验证失败',
recoverable: false,
action: '检查输入数据',
},
{
pattern: /401|403|invalid.*token|authentication.*failed/i,
category: 'validation',
severity: 'high',
message: '认证失败',
recoverable: true,
action: '重新登录或刷新令牌',
},
{
pattern: /404/i,
category: 'not_found',
severity: 'medium',
message: '资源不存在',
recoverable: false,
action: '检查请求地址',
},
{
pattern: /429|rate.*limit|too.*many.*requests/i,
category: 'resource',
severity: 'medium',
message: '请求过于频繁',
recoverable: true,
action: '等待后重试',
},
{
pattern: /500|503|server.*error|internal.*error/i,
category: 'network',
severity: 'high',
message: '服务器错误',
recoverable: true,
action: '稍后重试',
},
]
/** 分类缓存 */
const classificationCache = new Map<string, ErrorClassification>()
/**
* 分类单个错误
*/
export function classifyError(error: Error | string, config?: Partial<ClassifierConfig>): ErrorClassification {
const errorMessage = typeof error === 'string' ? error : error.message
const errorCode = typeof error === 'string' ? undefined : (error as any).code
// 检查缓存
const cacheKey = errorMessage.slice(0, 100)
if (config?.cacheClassifications !== false && classificationCache.has(cacheKey)) {
return classificationCache.get(cacheKey)!
}
// 尝试匹配模式
for (const pattern of ERROR_PATTERNS) {
if (pattern.pattern.test(errorMessage) || (errorCode && pattern.pattern.test(errorCode))) {
const classification: ErrorClassification = {
category: pattern.category,
severity: pattern.severity,
message: pattern.message,
code: errorCode,
recoverable: pattern.recoverable,
suggestedAction: pattern.action,
}
// 缓存结果
if (config?.cacheClassifications !== false) {
if (classificationCache.size > (config?.maxCacheSize || 100)) {
const firstKey = classificationCache.keys().next().value
if (firstKey) classificationCache.delete(firstKey)
}
classificationCache.set(cacheKey, classification)
}
return classification
}
}
// 无法分类的错误
const unknownClassification: ErrorClassification = {
category: 'unknown',
severity: 'medium',
message: errorMessage.slice(0, 100),
code: errorCode,
recoverable: false,
suggestedAction: '检查错误信息并手动处理',
}
return unknownClassification
}
/**
* 批量分类错误
*/
export function classifyErrors(
errors: (Error | string)[]
): ErrorClassification[] {
return errors.map(e => classifyError(e))
}
/**
* 检查是否可重试
*/
export function isRetryable(error: Error | string): boolean {
const classification = classifyError(error)
return classification.recoverable
}
/**
* 获取错误严重程度
*/
export function getErrorSeverity(error: Error | string): ErrorSeverity {
return classifyError(error).severity
}
/**
* 清除分类缓存
*/
export function clearCache(): void {
classificationCache.clear()
}
/**
* 获取缓存统计
*/
export function getCacheStats(): { size: number; maxSize: number } {
return {
size: classificationCache.size,
maxSize: 100,
}
}