import { useAtomValue } from "@effect/atom-react"; import type { EnvironmentId } from "@t3tools/contracts"; import { ChevronDownIcon, PlusIcon, RotateCcwIcon, XIcon } from "lucide-react"; import * as Option from "effect/Option"; import { AsyncResult, Atom } from "effect/unstable/reactivity"; import { useRef, useState } from "react"; import { isElectron } from "../../env"; import { cn } from "../../lib/utils"; import { environmentPresentations } from "../../state/presentation"; import { serverEnvironment } from "../../state/server"; import { environmentSession } from "../../state/session"; import { useAtomCommand } from "../../state/use-atom-command"; import type { EnvironmentUsageStatus } from "../../state/usage"; import { resolvePrimaryOperateAccess, resolveRemoteOperateAccess, } from "../settings/ProviderSettingsPanel.logic"; import { Button } from "../ui/button"; import { Dialog, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPopup, DialogTitle, } from "../ui/dialog"; import { Input } from "../ui/input"; import { Label } from "../ui/label"; import { Menu, MenuCheckboxItem, MenuPopup, MenuSeparator, MenuTrigger } from "../ui/menu"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../ui/table"; import { Tooltip, TooltipTrigger, TooltipPopup } from "../ui/tooltip"; import { USAGE_PRICE_FIELDS } from "./usagePriceForm"; import { isEmptyUsagePriceDraft, usagePriceCell, usagePriceTableChanges, usagePriceTableErrors, type UsagePriceDraft, type UsagePriceField, } from "./usagePriceTable"; import { writeUsagePrices, type UsagePriceTarget, type UsagePriceWriteResult, } from "./usagePriceTargets"; const priceTargetsAtom = Atom.make((get): readonly UsagePriceTarget[] => [...get(environmentPresentations.presentationsAtom)].map(([environmentId, environment]) => { const settings = get(serverEnvironment.settingsValueAtom(environmentId)); const session = get(environmentSession.sessionStateAtom(environmentId)); const sessionAccess = { session: Option.getOrNull(AsyncResult.value(session)), isPending: session.waiting, hasError: session._tag === "Failure", }; const isPrimary = environment.entry.target._tag === "PrimaryConnectionTarget"; const access = isPrimary ? resolvePrimaryOperateAccess({ ...sessionAccess, isPrimary, hasDesktopBridge: isElectron }) : resolveRemoteOperateAccess(sessionAccess); return { environmentId, label: environment.entry.target.label, prices: settings?.usagePriceOverrides ?? null, unavailable: environment.connection.phase !== "connected" ? "Offline" : settings === null ? "Prices not loaded" : environment.serverConfig?.environment.capabilities.usagePriceOverrides !== true ? "Update server to edit prices" : access === "pending" ? "Checking permissions…" : access === "denied" ? "Read-only access" : null, }; }), ); type SaveAttempt = { readonly drafts: readonly UsagePriceDraft[]; readonly destinations: readonly { readonly environmentId: EnvironmentId; readonly label: string; }[]; readonly results: ReadonlyMap< EnvironmentId, UsagePriceWriteResult | { readonly status: "saving" } >; }; export function UsagePriceOverrides({ usage, initialSelectedEnvironmentIds, onOpenChange, }: { readonly usage: readonly EnvironmentUsageStatus[]; readonly initialSelectedEnvironmentIds: ReadonlySet | null; readonly onOpenChange: (open: boolean) => void; }) { const environments = useAtomValue(priceTargetsAtom); const [selectedIds, setSelectedIds] = useState(initialSelectedEnvironmentIds); const selected = environments.filter( (environment) => selectedIds === null || selectedIds.has(environment.environmentId), ); const [drafts, setDrafts] = useState([]); const [pending, setPending] = useState(false); const [attempt, setAttempt] = useState(null); const focusRowRef = useRef(null); const nextRowId = useRef(0); const updateSettings = useAtomCommand(serverEnvironment.updateSettings, { reportFailure: false }); const customModels = [ ...new Set(selected.flatMap((environment) => Object.keys(environment.prices ?? {}))), ].sort(); const models = [ ...new Set([ ...customModels, ...usage .filter((environment) => selected.some((target) => target.environmentId === environment.environmentId), ) .flatMap((environment) => environment.summary?.buckets.map((bucket) => bucket.model) ?? []), ]), ].sort(); // Keep new rows in place while successful environments publish their updated settings. const newModels = new Set( drafts.filter((draft) => draft.isNew).map((draft) => draft.model.trim()), ); const rows: readonly UsagePriceDraft[] = [ ...customModels .filter((model) => attempt === null || !newModels.has(model)) .map( (model) => drafts.find((draft) => draft.id === `model:${model}`) ?? { id: `model:${model}`, model, isNew: false, values: {}, }, ), ...drafts.filter((draft) => draft.isNew), ]; const stagedDrafts = drafts.filter((draft) => !isEmptyUsagePriceDraft(draft)); const errors = usagePriceTableErrors(selected, stagedDrafts); for (const draft of stagedDrafts) { if (!draft.isNew) continue; if (draft.model.trim() === "") errors.set(draft.id, "Enter a model ID."); else if ( attempt === null && (customModels.includes(draft.model.trim()) || drafts.some((other) => other.id !== draft.id && other.model.trim() === draft.model.trim())) ) errors.set(draft.id, "This model already has a row. Edit its prices there."); } const failedDestinations = attempt?.destinations.filter( (destination) => attempt.results.get(destination.environmentId)?.status === "failed", ) ?? []; const locked = pending || failedDestinations.length > 0; const hasChanges = stagedDrafts.length > 0; const destinationLabel = selected.length === 1 ? selected[0]!.label : `${selected.length} environments`; const selectionLabel = selectedIds === null ? "All environments" : destinationLabel; const discard = () => { setDrafts([]); setAttempt(null); }; const selectEnvironments = (ids: ReadonlySet | null) => { setSelectedIds(ids); setAttempt(null); }; const updateDraft = (draft: UsagePriceDraft) => { setDrafts((previous) => previous.some((entry) => entry.id === draft.id) ? previous.map((entry) => (entry.id === draft.id ? draft : entry)) : [...previous, draft], ); setAttempt(null); }; const editCell = (row: UsagePriceDraft, field: UsagePriceField, value: string) => { const values = { ...row.values, [field]: value }; const original = usagePriceCell(selected, row.model, field); if ( !row.isNew && original.placeholder !== "Mixed" && original.placeholder !== "Unavailable" && value === original.value ) delete values[field]; if (!row.isNew && Object.keys(values).length === 0) setDrafts((previous) => previous.filter((entry) => entry.id !== row.id)); else updateDraft({ ...row, values }); }; const save = async (retry = false) => { if (pending) return; const destinations = retry ? failedDestinations : selected; const edits = retry && attempt ? attempt.drafts : stagedDrafts; if (destinations.length === 0 || edits.length === 0) return; const targets = destinations.map( (destination) => environments.find( (environment) => environment.environmentId === destination.environmentId, ) ?? { ...destination, prices: null, unavailable: "Environment removed" }, ); const changes = new Map( targets.map((target) => [target.environmentId, usagePriceTableChanges(target, edits)]), ); setPending(true); setAttempt((previous) => ({ drafts: edits, destinations: retry && previous ? previous.destinations : targets, results: new Map([ ...(retry && previous ? previous.results : []), ...targets.map((target) => [target.environmentId, { status: "saving" } as const] as const), ]), })); let failed = false; await writeUsagePrices({ targets: targets.map((target) => ({ ...target, unavailable: target.unavailable ?? [...changes.get(target.environmentId)!.errors.values()][0] ?? null, })), changes: new Map([...changes].map(([id, plan]) => [id, plan.changes])), write: updateSettings, onResult: (environmentId, result) => { if (result.status === "failed") failed = true; setAttempt((previous) => previous === null ? null : { ...previous, results: new Map(previous.results).set(environmentId, result) }, ); }, }); setPending(false); if (!failed) setDrafts([]); }; return ( { if (!pending) onOpenChange(open); }} > Custom model prices Prices apply to all past and future usage on the environments you select.
} aria-labelledby="usage-prices-apply-label usage-prices-selection" disabled={pending || hasChanges} > {selectionLabel} selectEnvironments(checked ? null : new Set())} > All environments {environments.map((environment) => ( { const next = new Set(selected.map((target) => target.environmentId)); if (checked) next.add(environment.environmentId); else next.delete(environment.environmentId); selectEnvironments(next.size === environments.length ? null : next); }} > {environment.label} {environment.unavailable ? ( {environment.unavailable} ) : null} ))}
USD / million tokens
{selected.length === 0 ? (

{environments.length === 0 ? "Connect an environment to set model prices." : "Select an environment to see and change its model prices."}

) : ( <>
{USAGE_PRICE_FIELDS.map((field) => ( ))} Model ID {USAGE_PRICE_FIELDS.map((field) => ( {field.label} ))} {rows.length === 0 ? ( {selected.some((environment) => environment.prices === null) ? "Some environment prices are unavailable." : "No custom prices. Add a row to override automatic pricing."} ) : ( rows.map((row) => ( {row.isNew ? ( { if (node && focusRowRef.current === row.id) { node.focus(); focusRowRef.current = null; } }} aria-label="New model ID" aria-invalid={ (row.model.trim() !== "" && errors.has(row.id)) || undefined } list="usage-price-models" placeholder="Model ID" autoComplete="off" spellCheck={false} disabled={locked} onChange={(event) => updateDraft({ ...row, model: event.target.value }) } /> ) : ( {row.model} )} {errors.has(row.id) && (row.model.trim() !== "" || Object.values(row.values).some((value) => value !== "")) ? (

{errors.get(row.id)}

) : null}
{row.removed ? ( Automatic pricing after saving ) : ( USAGE_PRICE_FIELDS.map((field) => { const cell = usagePriceCell(selected, row.model, field.key); return ( editCell(row, field.key, event.target.value) } /> ); }) )} } disabled={locked} aria-label={ row.removed ? `Undo reset for ${row.model}` : row.isNew ? "Remove new model" : `Reset price for ${row.model} to automatic` } onClick={() => { if (row.isNew) setDrafts((previous) => previous.filter((entry) => entry.id !== row.id), ); else if (row.removed) { if (Object.keys(row.values).length === 0) setDrafts((previous) => previous.filter((entry) => entry.id !== row.id), ); else updateDraft({ ...row, removed: false }); } else updateDraft({ ...row, removed: true }); }} > {row.isNew ? : } {row.removed ? "Undo reset" : row.isNew ? "Remove row" : "Reset to automatic"}
)) )}
{models .filter((model) => !customModels.includes(model)) .map((model) => (

Blank cache rates use the input price. Enter 0 for free tokens. {selected.length > 1 ? " Mixed cells keep each environment’s rate until you edit them." : ""}

)} {attempt ? (
{attempt.destinations.map((destination) => { const result = attempt.results.get(destination.environmentId); return (
{destination.label} {result?.status === "failed" ? `Not saved · ${result.error}` : result?.status === "saved" ? "Saved" : "Saving…"}
); })}
) : null}
{hasChanges ? `Changes apply to ${destinationLabel}` : ""}
{hasChanges ? ( ) : null}
); }