Skip to content
65 linesCodeBlameRaw
1/**
2 * Effort and suggestions, as the pages say them (components/effort.tsx).
3 * Pure, so it is tested on its own. Every cost
4 * shown comes from the agents service's measured sessions; a level an
5 * agent has not run at says so instead of a number.
6 */
7import type { AgentEffort, AgentEffortCosts, AgentRecommendation, AgentRecommendations, EffortCost, EffortLevel } from "@g1t/contracts";
8
9/** Dollars as lib/usage.ts `money` writes them; here so this file imports nothing at run time. */
10function money(micros: number): string {
11 const d = Math.abs(micros) / 1_000_000;
12 const digits = d < 0.0001 || d >= 0.01 ? 2 : d >= 0.001 ? 3 : 4;
13 return `${micros < 0 ? "−" : ""}$${d.toLocaleString("en-US", { minimumFractionDigits: digits, maximumFractionDigits: digits })}`;
14}
15
16export const EFFORT_OPTIONS: { key: AgentEffort; label: string; about: string }[] = [
17 { key: "auto", label: "Auto", about: "Picks per piece of work: medium, and high on a session someone has had to steer." },
18 { key: "low", label: "Low", about: "The fast tier, light reasoning, up to 5 steps a session. For routine work." },
19 { key: "medium", label: "Medium", about: "Starts where the work would, moderate reasoning, up to 8 steps a session." },
20 { key: "high", label: "High", about: "The standard tier or above, deep reasoning, up to 10 steps a session." },
21 { key: "max", label: "Max", about: "The most capable tier, the most reasoning, up to 12 steps a session." },
22];
23
24export function effortLabel(effort: AgentEffort | null | undefined): string {
25 return EFFORT_OPTIONS.find((o) => o.key === effort)?.label ?? "Auto";
26}
27
28/** An agent's setting from its routing; none is Auto. */
29export function effortSetting(routing: { effort?: AgentEffort } | null | undefined): AgentEffort {
30 const value = routing?.effort;
31 return EFFORT_OPTIONS.some((o) => o.key === value) ? (value as AgentEffort) : "auto";
32}
33
34/** One level's measured cost, or null when the agent has not run at it. */
35export function costAt(costs: AgentEffortCosts | null, level: EffortLevel): EffortCost | null {
36 const found = costs?.levels.find((l) => l.effort === level);
37 return found && found.sessions > 0 && found.typical_micros != null ? found : null;
38}
39
40/** What a setting has cost per typical task: "$0.42 a typical task, from 14 sessions", or why there is no figure. */
41export function costLine(costs: AgentEffortCosts | null, effort: AgentEffort): string {
42 if (!costs) return "Costs couldn't be read right now.";
43 // Auto runs as medium, and high once steered: its figure is medium's.
44 const level: EffortLevel = effort === "auto" ? "medium" : effort;
45 const at = costAt(costs, level);
46 const days = `in the last ${costs.window_days} days`;
47 if (!at) return effort === "auto" ? `No sessions at Medium ${days}, so no figure yet.` : `No sessions at ${effortLabel(effort)} ${days}, so no figure yet.`;
48 const sessions = `${at.sessions.toLocaleString("en-US")} session${at.sessions === 1 ? "" : "s"}`;
49 return `${money(at.typical_micros!)} a typical task${effort === "auto" ? " at Medium" : ""}, from ${sessions} ${days}`;
50}
51
52/** "92%" of sessions finished with nobody stepping in, or empty. */
53export function acceptedLabel(cost: EffortCost | null): string {
54 return cost?.accepted_share != null ? `${Math.round(cost.accepted_share * 100)}%` : "";
55}
56
57/** What the open suggestions together would save a month. */
58export function totalSaving(recs: AgentRecommendations | null): number {
59 return (recs?.open ?? []).reduce((n, r) => n + (r.saving_month_micros ?? 0), 0);
60}
61
62/** "About $31 a month" from a suggestion's measured saving. */
63export function savingLabel(rec: Pick<AgentRecommendation, "saving_month_micros">): string {
64 return rec.saving_month_micros != null && rec.saving_month_micros > 0 ? `About ${money(rec.saving_month_micros)} a month` : "";
65}