godcrm/context/AIChatContext/helpers.ts
GOD CRM Release f89e074dd1
Some checks failed
CI / Lint / Typecheck / Test / Build (push) Has been cancelled
CI / PostgreSQL Integration Tests (push) Has been cancelled
GOD CRM — public scrubbed snapshot
Governed substrate for autonomous agents: scoped identity (passports),
audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
2026-08-10 04:01:45 +03:00

67 lines
2 KiB
TypeScript

import { logger } from '@/shared/utils/logger';
/**
* Retry wrapper for API calls that fail with rate limit (429) or gateway errors (502/503).
* Automatically retries with increasing delays.
*/
export async function withRetry<T>(
fn: () => Promise<T>,
delays: number[] = [3000, 8000, 20000]
): Promise<T> {
for (let attempt = 0; attempt <= delays.length; attempt++) {
try {
return await fn();
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
const isRetryable = /429|502|503|rate.?limit/i.test(msg);
if (!isRetryable || attempt >= delays.length) {
throw err;
}
const delay = delays[attempt];
logger.warn(`[AI Chat] Retryable error, retry ${attempt + 1}/${delays.length} in ${delay / 1000}s...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error('Max retries exceeded');
}
/**
* Generate a smart conversation title from the first user message.
* - Strips markdown formatting, code blocks, URLs
* - Truncates at word boundary (max 60 chars)
* - Falls back to "New chat" if content is empty
*/
export function generateConversationTitle(content: string): string {
if (!content || !content.trim()) return 'New chat';
let title = content
// Remove code blocks
.replace(/```[\s\S]*?```/g, '')
// Remove inline code
.replace(/`[^`]+`/g, '')
// Remove markdown links [text](url) -> text
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
// Remove URLs
.replace(/https?:\/\/\S+/g, '')
// Remove markdown formatting (bold, italic, headers)
.replace(/[#*_~>]+/g, '')
// Collapse whitespace
.replace(/\s+/g, ' ')
.trim();
if (!title) return 'New chat';
// Truncate at word boundary, max 60 chars
if (title.length > 60) {
title = title.substring(0, 60);
const lastSpace = title.lastIndexOf(' ');
if (lastSpace > 30) {
title = title.substring(0, lastSpace);
}
title += '...';
}
return title;
}