@sema-agent/core
Version:
Stateless, task-oriented AI agent core
59 lines (58 loc) • 2.51 kB
JavaScript
export const FLOOR_OUTPUT_TOKENS = 3000;
const CONTEXT_HEADROOM_TOKENS = 1000;
const CONTEXT_OVERFLOW_RE = /^input length and `max_tokens` exceed context limit: (\d+) \+ (\d+) > (\d+)(?!\w|[.,]\d|\s\d|[+\-*/])/;
const CONTEXT_OVERFLOW_PREFIX = "input length and `max_tokens` exceed context limit:";
function providerDiagnostic(body) {
const trimmed = body.trim();
if (!trimmed.startsWith("{"))
return undefined;
let parsed;
try {
parsed = JSON.parse(trimmed);
}
catch {
return undefined;
}
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
return undefined;
const err = parsed.error;
if (typeof err !== "object" || err === null || Array.isArray(err))
return undefined;
const message = err.message;
return typeof message === "string" ? message : undefined;
}
function reportFrom(diagnostic) {
const message = diagnostic.trimStart();
const m = CONTEXT_OVERFLOW_RE.exec(message);
if (m === null)
return undefined;
if (message.slice(m[0].length).includes(CONTEXT_OVERFLOW_PREFIX))
return undefined;
const [, rawInput, rawMax, rawLimit] = m;
if (rawInput === undefined || rawMax === undefined || rawLimit === undefined)
return undefined;
const inputTokens = Number.parseInt(rawInput, 10);
const maxTokens = Number.parseInt(rawMax, 10);
const contextLimit = Number.parseInt(rawLimit, 10);
if (!Number.isSafeInteger(inputTokens) || !Number.isSafeInteger(maxTokens) || !Number.isSafeInteger(contextLimit)) {
return undefined;
}
if (inputTokens <= contextLimit - maxTokens)
return undefined;
return { inputTokens, maxTokens, contextLimit };
}
export function parseContextOverflow(status, body) {
if (status !== 400)
return undefined;
const diagnostic = providerDiagnostic(body);
return diagnostic === undefined ? undefined : reportFrom(diagnostic);
}
export function planOutputCapAdjustment(report, otherCapsInEffect = []) {
const available = Math.max(0, report.contextLimit - report.inputTokens - CONTEXT_HEADROOM_TOKENS);
if (available < FLOOR_OUTPUT_TOKENS)
return { outcome: "below_floor", available };
const current = Math.min(report.maxTokens, ...otherCapsInEffect.filter((c) => c !== undefined));
if (available >= current)
return { outcome: "no_progress", available, current };
return { outcome: "adjust", maxOutputTokens: available, current };
}