Files
2026-07-13 13:39:12 +08:00

88 lines
2.6 KiB
TypeScript

import { MAX_TOOLS_LIMIT } from "../config/constants.ts";
const DETECTED_LIMITS = new Map<string, { limit: number; timestamp: number }>();
const TTL_MS = 24 * 60 * 60 * 1000;
const DEFAULT_LIMIT = MAX_TOOLS_LIMIT;
const PROVIDER_TOOL_LIMITS: Record<string, number> = {
"grok-cli": 200,
"nvidia": 1536,
};
const _detectedLimitsSweep = setInterval(() => {
const now = Date.now();
for (const [key, entry] of DETECTED_LIMITS) {
if (now - entry.timestamp > TTL_MS) DETECTED_LIMITS.delete(key);
}
}, 60_000);
if (typeof _detectedLimitsSweep === "object" && "unref" in _detectedLimitsSweep) {
(_detectedLimitsSweep as { unref?: () => void }).unref?.();
}
export function getKnownToolLimit(provider: string | null | undefined): number | null {
const proactiveLimit = PROVIDER_TOOL_LIMITS[provider];
if (proactiveLimit !== undefined) {
return proactiveLimit;
}
const cached = DETECTED_LIMITS.get(provider);
if (cached && Date.now() - cached.timestamp < TTL_MS) {
return cached.limit;
}
return null;
}
export function getEffectiveToolLimit(provider: string | null | undefined): number {
return getKnownToolLimit(provider) ?? DEFAULT_LIMIT;
}
export function setDetectedToolLimit(provider: string, limit: number): void {
const current = getEffectiveToolLimit(provider);
if (limit < current) {
DETECTED_LIMITS.set(provider, { limit, timestamp: Date.now() });
}
}
const TOOL_LIMIT_PATTERNS = [
/'tools':\s*maximum\s+number\s+of\s+items\s+is\s+(\d+)/i,
/Maximum\s+number\s+of\s+tools\s+(?:allowed\s+)?(?:is\s+)?(\d+)/i,
/Too\s+many\s+tools\.?\s*(?:Maximum\s+)?(\d+)/i,
/\d+\s+tools\s+have\s+been\s+provided\s+but\s+(?:the\s+)?maximum\s+is\s+(\d+)/i,
/tool.*limit.*(\d+)/i,
/tools.*exceeded.*(\d+)/i,
];
export function parseToolLimitFromError(errorMessage: string): number | null {
for (const pattern of TOOL_LIMIT_PATTERNS) {
const match = errorMessage.match(pattern);
if (match && match[1]) {
const limit = parseInt(match[1], 10);
if (limit > 0 && limit <= 10000) {
return limit;
}
}
}
return null;
}
const TOOL_LIMIT_ERROR_INDICATORS = [
"maximum number of tools",
"too many tools",
"tools limit",
"'tools'",
"maximum number of items",
];
export function shouldDetectLimit(errorMessage: string, statusCode: number): boolean {
if (statusCode !== 400) return false;
const lower = errorMessage.toLowerCase();
return TOOL_LIMIT_ERROR_INDICATORS.some((indicator) => lower.includes(indicator));
}
export function getDetectedToolLimit(provider: string): number {
return getEffectiveToolLimit(provider);
}
export function clearDetectedLimits(): void {
DETECTED_LIMITS.clear();
}