lib/agent-models.ts
Rama main · réplica de lectura del repositorio original.
/**
* Shared registry (client + server) of models and settings of the agent of
* cloud code (MIN-46). NO server-only import: the model picker (UI) and the
* server-side resolution (`lib/server/agent/model.ts`) both import it.
*/
export interface AgentModelOption {
/** id OpenRouter au format `provider/model`. */
id: string;
/** label displayed in the picker. */
label: string;
/** short note (cost / usage). */
hint?: string;
}
/**
* Curated labels from a handful of top models. The picker (launch +
* personal default) is NO LONGER limited to this list: it searches the entire index
* OpenRouter (`/api/agent/models`) and formats the names via `formatModelName`.
* This list is only used to provide nice known labels (cf. `model-display`)
* for these specific ids. Ids to be confirmed against OpenRouter index `/models`.
*/
export const AGENT_ALLOWED_MODELS: AgentModelOption[] = [
{ id: "deepseek/deepseek-v4-flash", label: "DeepSeek V4 Flash", hint: "Économique · défaut" },
{ id: "anthropic/claude-sonnet-5", label: "Claude Sonnet 5", hint: "Équilibré, fort en code" },
{ id: "anthropic/claude-opus-4.8", label: "Claude Opus 4.8", hint: "Qualité maximale" },
];
// ── Context compaction (hardening, very long runs) ────────────────────
/** Beyond this estimation of tokens, we summarize the middle of the history.
Conservative (proxy characters/4 which underestimates the code): safe on models
with a wide window (DeepSeek, Claude…). */
export const AGENT_COMPACT_TOKEN_THRESHOLD = 70_000;
/**
* CALIBRATED VALUE of the compaction threshold: what it is worth at the reference price, and
* the FLOOR under which it never falls (see `agentCompactThreshold`, which
* transposes it to the price of the run model — it was a fixed ceiling until MIN-248).
*
* Window ≠ budget. The threshold was 75% of the window, and the models we
* use have windows from 1M to 1.05M → effective threshold ~787,000 tokens, i.e.
* 5× our largest checkpoint. Result: compaction never ran a single time in production (MIN-113). What caps a long session is not
* the window, it is the COST PER ROUND: we return the entire history with each call
* and — measured, not assumed — prompt caching does not amortize it (the breakpoints of
* `caching.ts` are at the top of the history, so the block hidden remains frozen while
* the history increases; the observed cost sticks to the full input rate to within 2%).
*
* 120,000 comes from the MIN-101 measurement of 814 agent `ai_usage` calls:
* • p90 of real context = 86,815 tokens → a normal session never sees it;
* • max observed = 158,301 → a cap at 180k would NEVER trigger, this which
* would reproduce the bug that we are correcting here;
* • summarizing is amortized in ~1.2 rounds from 60 k, so it is the quality (do not
* harass the short sessions) which sets the floor, not the profitability.
* To be reviewed if the distribution of contexts changes — not to the blind man.
*/
export const AGENT_COMPACT_BASELINE_TOKENS = 120_000;
/**
* Entry price AT WHICH the 120,000 above were calibrated: that of model
* minddy's default at the time of measurement (`deepseek/deepseek-v4-flash`,
* $0.14/Mtok). This is what makes the cap TRANSPOSABLE: at this price, the prompt
* of a round costs $0.0168, and it is this COST PER ROUND — not the number of
* tokens — that the cap actually limits.
*/
export const AGENT_COMPACT_REFERENCE_INPUT_USD_PER_MTOK = 0.14;
/**
* How high the cap can GO for a cheap model. Twice the value
* calibrated, and the reason is that of MIN-113: the largest context ever
* observed on the agent is 158,301 tokens. A threshold beyond 240,000 would therefore never trigger — that is, it would not exist.
*/
export const AGENT_COMPACT_MAX_TOKENS_CEILING = 240_000;
/**
* COMPACTION THRESHOLD of the run, derived from the model rather than written in hard copy.
*
* The 120,000 cap said a real thing — "a round should not cost
* more than that to return" — but it said it in TOKENS, which does not mean la
* same as for a model at the same price. Between `deepseek-v4-flash`
* ($0.14/Mtok) and `claude-opus-4.8` ($5/Mtok), the same history of 120,000
* tokens costs $0.017 or $0.60 per round: thirty-six times the difference, for a
* safeguard supposed to limit an expense.
*
* The threshold is therefore read in dollars and is converted into tokens at the price of the model.
* Three terminals, and each repairs a known fault:
*
* - **floor to `AGENT_COMPACT_BASELINE_TOKENS`** — we never GO
* below the calibrated value, even for a very expensive model. Compacting earlier
* saves nothing: the model buys back in rereads what is taken from it, and
* is exactly MIN-248. An expensive model therefore keeps the behavior
* of today, down to the byte.
* - **ceiling at `AGENT_COMPACT_MAX_TOKENS_CEILING`** — a threshold that runs
* never reach has never been triggered (MIN-113).
* - **and always ≤ 75% of the window**: the budget cannot exceed what
* the model can read.
*
* `inputUsdPerMTok` unknown (BYOK provider outside the OpenRouter catalog) or null
* (free model) → we fall back on the calibrated value. Ignoring the price is not
* a license to move up: it is a reason not to move.
*/
export function agentCompactThreshold(opts: {
contextWindow?: number | null;
inputUsdPerMTok?: number | null;
}): number {
const fromWindow = opts.contextWindow
? Math.floor(opts.contextWindow * 0.75)
: AGENT_COMPACT_TOKEN_THRESHOLD;
const price = opts.inputUsdPerMTok;
const affordable =
typeof price === "number" && Number.isFinite(price) && price > 0
? Math.floor(
(AGENT_COMPACT_BASELINE_TOKENS * AGENT_COMPACT_REFERENCE_INPUT_USD_PER_MTOK) / price,
)
: AGENT_COMPACT_BASELINE_TOKENS;
const budget = Math.min(
Math.max(affordable, AGENT_COMPACT_BASELINE_TOKENS),
AGENT_COMPACT_MAX_TOKENS_CEILING,
);
return Math.min(fromWindow, budget);
}