49 lines
1.5 KiB
TypeScript
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');
|
|
}
|
|
}
|