Complete M16 action select circle parity
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-08-20 22:57:59 -04:00
parent fb5abd8e37
commit 6a0b980d75
368 changed files with 17417 additions and 117 deletions

View File

@@ -0,0 +1,71 @@
import { parseProviderUsage } from "./provider-usage";
export type TokenLimitCategory = "NONE" | "CONTEXT_LIMIT" | "OUTPUT_LIMIT" | "MAX_OUTPUT_TOKENS" | "UNKNOWN";
export interface TokenLimitClassification {
category: TokenLimitCategory;
detected: boolean;
retryable: boolean;
reason: string | null;
actual: number | null;
limit: number | null;
}
export interface TokenLimitOptions {
contextTokens?: number;
outputTokens?: number;
maxOutputTokens?: number;
}
function textOf(input: unknown): string {
try {
const serialized = JSON.stringify(input);
return (serialized ?? String(input)).toLowerCase();
} catch { return String(input).toLowerCase(); }
}
export const classifyLimit = classifyTokenLimit;
function numberAt(input: unknown, names: Set<string>, seen = new Set<object>()): number | null {
if (typeof input !== "object" || input === null) return null;
if (seen.has(input)) return null;
seen.add(input);
if (Array.isArray(input)) {
for (const value of input) { const result = numberAt(value, names, seen); if (result !== null) return result; }
return null;
}
for (const [key, value] of Object.entries(input)) {
const normalized = key.replace(/[A-Z]/gu, (letter) => `_${letter.toLowerCase()}`).toLowerCase();
if (names.has(normalized) && typeof value === "number" && Number.isFinite(value)) return value;
const result = numberAt(value, names, seen);
if (result !== null) return result;
}
return null;
}
function result(category: TokenLimitCategory, reason: string | null, actual: number | null, limit: number | null): TokenLimitClassification {
return { category, detected: category !== "NONE", retryable: category === "CONTEXT_LIMIT" || category === "OUTPUT_LIMIT", reason, actual, limit };
}
/** Recognize provider errors, finish reasons and measured usage consistently. */
export function classifyTokenLimit(input: unknown, options: TokenLimitOptions = {}): TokenLimitClassification {
const text = textOf(input);
const usage = parseProviderUsage(input);
const contextActual = numberAt(input, new Set(["context_tokens", "contexttokens", "prompt_tokens", "prompttokens", "input_tokens", "inputtokens"]));
const outputActual = usage.outputTokens ?? numberAt(input, new Set(["output_tokens", "outputtokens", "completion_tokens", "completiontokens"]));
const contextMarker = /(context[_ -]?length|context[_ -]?window|maximum[_ -]?context|prompt[_ -]?too[_ -]?long|input[_ -]?too[_ -]?long|context[_ -]?limit|context[_ -]?exceed)/u.test(text);
const outputMarker = /(output[_ -]?limit|completion[_ -]?limit|output[_ -]?too[_ -]?long|output[_ -]?exceed|completion[_ -]?tokens?.{0,20}(limit|exceed|too))/u.test(text);
const maxMarker = /(max(?:imum)?[_ -]?output[_ -]?tokens|max[_ -]?completion[_ -]?tokens|max[_ -]?tokens|finish[_ -]?reason.{0,12}(length|max_tokens)|stop[_ -]?reason.{0,12}max_tokens|incomplete.{0,30}max_output_tokens)/u.test(text);
if (contextMarker || (options.contextTokens !== undefined && contextActual !== null && contextActual > options.contextTokens)) {
return result("CONTEXT_LIMIT", "context token limit exceeded", contextActual, options.contextTokens ?? null);
}
if (outputMarker || (options.outputTokens !== undefined && outputActual !== null && outputActual > options.outputTokens)) {
return result("OUTPUT_LIMIT", "output token limit exceeded", outputActual, options.outputTokens ?? null);
}
if (maxMarker || (options.maxOutputTokens !== undefined && outputActual !== null && outputActual >= options.maxOutputTokens && /(?:length|max[_ -]?tokens)/u.test(text))) {
return result("MAX_OUTPUT_TOKENS", "generation stopped at max_output_tokens", outputActual, options.maxOutputTokens ?? null);
}
if (text.includes("token") && /(limit|exceed|truncat|too long)/u.test(text)) return result("UNKNOWN", "provider reported an unclassified token limit", null, null);
return result("NONE", null, null, null);
}