| import { Request, Response, NextFunction } from 'express'; |
| import { MissingMaterialItem } from './models'; |
|
|
| export class AppError extends Error { |
| public statusCode: number; |
| public errorCode: number; |
|
|
| constructor(message: string, statusCode: number, errorCode: number) { |
| super(message); |
| this.statusCode = statusCode; |
| this.errorCode = errorCode; |
| Object.setPrototypeOf(this, AppError.prototype); |
| } |
| } |
|
|
| export class MissingMaterialError extends AppError { |
| public missingItems: MissingMaterialItem[]; |
|
|
| constructor(missingItems: MissingMaterialItem[]) { |
| super('need_more_material', 400, 4001); |
| this.missingItems = missingItems; |
| Object.setPrototypeOf(this, MissingMaterialError.prototype); |
| } |
| } |
|
|
| |
| export const requestLogger = (req: Request, res: Response, next: NextFunction) => { |
| const started_at = new Date(); |
| |
| |
| const originalSend = res.send; |
| res.send = function (body: any) { |
| const ended_at = new Date(); |
| |
| |
| const case_context = req.body?.case_context || req.body; |
| const case_id = case_context?.case_id || 'unknown'; |
| |
| |
| const metadata = case_context?.metadata || {}; |
| const retry_count = metadata.retry_count || req.headers['x-retry-count'] || req.body?.retry_count || 0; |
|
|
| |
| let agent_name = 'unknown'; |
| if (req.path.includes('peer-reg-summary')) agent_name = 'AGENT-01'; |
| else if (req.path.includes('policy-rewrite')) agent_name = 'AGENT-02'; |
| else if (req.path.includes('compliance-check')) agent_name = 'AGENT-03'; |
| else if (req.path.includes('legal-pack')) agent_name = 'AGENT-04'; |
| else if (req.path.includes('log-analysis')) agent_name = 'LOG_ANALYSIS'; |
| else if (req.path.includes('code-security')) agent_name = 'CODE_SECURITY'; |
| else if (req.path.includes('regulatory-penalty-summary')) agent_name = 'REG_PENALTY_SUMMARY'; |
|
|
| const status = res.statusCode >= 400 ? 'failed' : 'success'; |
| const error_code = res.locals.errorCode || 0; |
| |
| const api_latency_ms = ended_at.getTime() - started_at.getTime(); |
| const llm_latency_ms = res.locals.llm_latency_ms || 0; |
|
|
| |
| console.log(JSON.stringify({ |
| case_id, |
| retry_count, |
| agent_name, |
| metadata, |
| started_at: started_at.toISOString(), |
| ended_at: ended_at.toISOString(), |
| api_latency_ms, |
| llm_latency_ms, |
| status, |
| error_code |
| })); |
|
|
| return originalSend.call(this, body); |
| }; |
|
|
| next(); |
| }; |
|
|
| |
| export const errorHandler = (err: any, req: Request, res: Response, next: NextFunction) => { |
| let statusCode = 500; |
| let errorCode = 5000; |
| let message = 'Internal Server Error'; |
| let extraData: any = null; |
|
|
| if (err instanceof MissingMaterialError) { |
| statusCode = err.statusCode; |
| errorCode = err.errorCode; |
| message = err.message; |
| extraData = { missing_materials: err.missingItems }; |
| } else if (err instanceof AppError) { |
| statusCode = err.statusCode; |
| errorCode = err.errorCode; |
| message = err.message; |
| } else if (err.message === 'LLM_INFERENCE_FAILED') { |
| statusCode = 500; |
| errorCode = 5001; |
| message = '智能体推理失败'; |
| } else if (err.message === 'MISSING_MATERIALS') { |
| statusCode = 400; |
| errorCode = 4001; |
| message = 'need_more_material'; |
| } else if (err.message === 'INVALID_FORMAT') { |
| statusCode = 400; |
| errorCode = 4002; |
| message = '输入格式错误'; |
| } else if (err.message === 'MISSING_CONTEXT') { |
| statusCode = 500; |
| errorCode = 5002; |
| message = '外部上下文缺失'; |
| } else if (err.message === 'MISSING_LLM_API_KEY') { |
| statusCode = 500; |
| errorCode = 5003; |
| message = 'LLM密钥未配置'; |
| } |
|
|
| |
| res.locals.errorCode = errorCode; |
|
|
| if (err instanceof MissingMaterialError) { |
| res.status(statusCode).json({ |
| schema_version: 'v1.0', |
| error_code: 'need_more_material', |
| message: message, |
| ...(extraData || {}) |
| }); |
| } else { |
| res.status(statusCode).json({ |
| error: { |
| code: errorCode, |
| message: message, |
| ...(extraData || {}) |
| } |
| }); |
| } |
| }; |
|
|