Files
gongxue-base/apps/server/src/ai-chat/ai-chat.helpers.ts

49 lines
1.5 KiB
TypeScript

export function redactText(value: string): string {
return value
.replace(/1[3-9]\d{9}/g, '[PHONE]')
.replace(/\b\d{17}[\dXx]\b/g, '[ID_CARD]')
.replace(/Bearer\s+[A-Za-z0-9._~+/-]+=*/gi, 'Bearer [REDACTED]')
.replace(/(sk-|api[_-]?key["'=:\s]+)[A-Za-z0-9._-]{8,}/gi, '$1[REDACTED]');
}
export function makeRedactingReplacer(redact: (value: string) => string) {
return (key: string, value: unknown): unknown => {
if (/password|token|secret|api.?key|authorization|phone|mobile|id.?card|身份证/i.test(key)) {
return '[REDACTED]';
}
if (typeof value === 'string') return redact(value);
return value;
};
}
export function parseToolArguments(value: string): unknown {
try {
return JSON.parse(value || '{}') as unknown;
} catch {
return null;
}
}
export function safeToolName(name: string): string {
return name.replace(/[^a-zA-Z0-9_]/g, '_').slice(0, 64) || '_invalid';
}
export function throwIfAborted(signal: AbortSignal): void {
if (signal.aborted) throw signal.reason ?? new Error('aborted');
}
export function errorCode(error: unknown): string {
if (error && typeof error === 'object' && 'status' in error) {
const status = Number(error.status);
if (status === 408) return 'UPSTREAM_TIMEOUT';
if (status >= 400 && status < 500) return 'UPSTREAM_REQUEST_ERROR';
}
return 'UPSTREAM_ERROR';
}
export function assertGeneratedLength(reasoning: string, content: string): void {
if (reasoning.length + content.length > 256 * 1024) {
throw new Error('AI response exceeded limit');
}
}