opencode prices and Go limits, settings out of .env
- Fetch prices for opencode (Zen and Go) incl. limits, image input, reasoning,
long-context tiers and peak-hour/date factors; costs apply them per request
- Record the cost opencode reports per response; track Go allowance in 5h/7d/month
windows against a provider plan limit (budget table, status overlay)
- Settings → Config file: move values of ${NAME} references into the config
- Examples, presets and forms keep keys in the config instead of .env
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
70367211c1
commit
bfa1f641d7
23 files changed
+723
-69
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import { Fragment } from "react";
|
||||
import { Icon } from "./Icon";
|
||||
import { useFetch } from "../hooks";
|
||||
import { fmtCost, fmtPercent, useT } from "../i18n";
|
||||
@@ -11,9 +12,32 @@ interface BudgetRow {
|
||||
warning: boolean;
|
||||
exceeded: boolean;
|
||||
images?: boolean;
|
||||
plan?: Plan;
|
||||
remote?: { currency?: string; remaining?: number | null; limit?: number | null; used?: number | null; spent_month?: number; scope?: string; error?: string };
|
||||
}
|
||||
|
||||
/** opencode Go: usage windows against the plan's limits (USD). */
|
||||
export interface Plan {
|
||||
limit: number;
|
||||
windows: { window: "5h" | "week" | "month"; used: number; limit: number; ratio: number }[];
|
||||
}
|
||||
|
||||
/** Three small meters (5 hours, week, month) for a subscription plan. */
|
||||
export function PlanUsage({ plan }: { plan: Plan }) {
|
||||
const t = useT();
|
||||
return (
|
||||
<div className="plan-usage">
|
||||
{plan.windows.map((w) => (
|
||||
<div key={w.window} className="plan-window" title={`${fmtCost(w.used, "USD")} / ${fmtCost(w.limit, "USD")}`}>
|
||||
<span className="plan-label">{t(`budget.window.${w.window}`)}</span>
|
||||
<Bar share={w.ratio} warning={w.ratio >= 0.8} exceeded={w.ratio >= 1} />
|
||||
<span className="plan-pct">{fmtPercent(w.ratio)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface BudgetData {
|
||||
currency: string;
|
||||
total: BudgetRow;
|
||||
@@ -62,20 +86,30 @@ export function BudgetPanel() {
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((r) => (
|
||||
<tr key={r.provider}>
|
||||
<td>
|
||||
{r.provider === "total" ? <b>{t("stats.total")}</b> : r.provider}
|
||||
{r.images && <span className="chip" style={{ marginLeft: 6 }}>{t("nav.images")}</span>}
|
||||
</td>
|
||||
<td className="num">{fmtCost(r.spent, data.currency)}</td>
|
||||
<td className="num">{r.budget ? fmtCost(r.budget, data.currency) : "–"}</td>
|
||||
<td>{r.share !== null && <Bar share={r.share} warning={r.warning} exceeded={r.exceeded} />}</td>
|
||||
<td className="num" style={{ color: r.exceeded ? "var(--red)" : r.warning ? "var(--accent2)" : undefined }}>
|
||||
{r.remaining !== null ? fmtCost(r.remaining, data.currency) : "–"}
|
||||
{r.share !== null && <span className="muted"> ({fmtPercent(r.share)})</span>}
|
||||
</td>
|
||||
<td>{r.provider === "total" ? null : <Remote r={r.remote} t={t} />}</td>
|
||||
</tr>
|
||||
<Fragment key={r.provider}>
|
||||
<tr>
|
||||
<td>
|
||||
{r.provider === "total" ? <b>{t("stats.total")}</b> : r.provider}
|
||||
{r.images && <span className="chip" style={{ marginLeft: 6 }}>{t("nav.images")}</span>}
|
||||
</td>
|
||||
<td className="num">{fmtCost(r.spent, data.currency)}</td>
|
||||
<td className="num">{r.budget ? fmtCost(r.budget, data.currency) : "–"}</td>
|
||||
<td>{r.share !== null && <Bar share={r.share} warning={r.warning} exceeded={r.exceeded} />}</td>
|
||||
<td className="num" style={{ color: r.exceeded ? "var(--red)" : r.warning ? "var(--accent2)" : undefined }}>
|
||||
{r.remaining !== null ? fmtCost(r.remaining, data.currency) : "–"}
|
||||
{r.share !== null && <span className="muted"> ({fmtPercent(r.share)})</span>}
|
||||
</td>
|
||||
<td>{r.provider === "total" ? null : <Remote r={r.remote} t={t} />}</td>
|
||||
</tr>
|
||||
{r.plan && (
|
||||
<tr className="plan-row">
|
||||
<td className="muted">{t("budget.plan", { v: fmtCost(r.plan.limit, "USD") })}</td>
|
||||
<td colSpan={5}>
|
||||
<PlanUsage plan={r.plan} />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Reference in new issue
Block a user