reasonix 0.12.19 → 0.12.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -993,6 +993,18 @@ interface CacheFirstLoopOptions {
993
993
  * presets pass `false` to lock the running session to one model.
994
994
  */
995
995
  autoEscalate?: boolean;
996
+ /**
997
+ * Soft USD budget for the entire session. When set, the loop:
998
+ * - Emits a one-shot warning event when cumulative cost crosses 80%
999
+ * - Refuses to run the next turn once cumulative cost ≥ budget,
1000
+ * yielding an error that explains how to bump or clear the cap
1001
+ *
1002
+ * Default `undefined` — no cap, no warnings. Reasonix is the cost-
1003
+ * focused agent; the budget is opt-in so users new to the tool
1004
+ * don't get blocked at $0.50 wondering what happened, but heavy /
1005
+ * headless / CI users have a clean circuit breaker available.
1006
+ */
1007
+ budgetUsd?: number;
996
1008
  /**
997
1009
  * Session name. When set, the loop pre-loads the session's prior messages
998
1010
  * into its log on construction, and appends every new log entry to
@@ -1071,6 +1083,19 @@ declare class CacheFirstLoop {
1071
1083
  * flip it live alongside `model`.
1072
1084
  */
1073
1085
  autoEscalate: boolean;
1086
+ /**
1087
+ * Soft USD budget — see {@link CacheFirstLoopOptions.budgetUsd}.
1088
+ * Mutable so `/budget` slash can set / change / clear it mid-session.
1089
+ * `null` (the default) disables all budget checks.
1090
+ */
1091
+ budgetUsd: number | null;
1092
+ /**
1093
+ * Set the first time a turn crosses 80% of the budget so the warning
1094
+ * doesn't repeat every turn afterwards. Cleared by `setBudget` (any
1095
+ * change re-arms the warning, including raising the cap above the
1096
+ * current spend).
1097
+ */
1098
+ private _budgetWarned;
1074
1099
  sessionName: string | null;
1075
1100
  /**
1076
1101
  * Hook list, mutable so `/hooks reload` can swap it without
@@ -1227,6 +1252,13 @@ declare class CacheFirstLoop {
1227
1252
  * flip a knob between turns.
1228
1253
  */
1229
1254
  configure(opts: ReconfigurableOptions): void;
1255
+ /**
1256
+ * Set / change / clear the soft USD budget. `null` (or any non-
1257
+ * positive number) disables the cap entirely. Re-arms the 80%
1258
+ * warning so a user who bumps the cap mid-session sees a fresh
1259
+ * threshold message at the new boundary.
1260
+ */
1261
+ setBudget(usd: number | null): void;
1230
1262
  /**
1231
1263
  * Arm pro for the next turn (consumed at turn start). Called by
1232
1264
  * `/pro`. Idempotent — repeated calls stay armed, `disarmPro()`
package/dist/index.js CHANGED
@@ -1855,6 +1855,19 @@ var CacheFirstLoop = class {
1855
1855
  * flip it live alongside `model`.
1856
1856
  */
1857
1857
  autoEscalate = true;
1858
+ /**
1859
+ * Soft USD budget — see {@link CacheFirstLoopOptions.budgetUsd}.
1860
+ * Mutable so `/budget` slash can set / change / clear it mid-session.
1861
+ * `null` (the default) disables all budget checks.
1862
+ */
1863
+ budgetUsd;
1864
+ /**
1865
+ * Set the first time a turn crosses 80% of the budget so the warning
1866
+ * doesn't repeat every turn afterwards. Cleared by `setBudget` (any
1867
+ * change re-arms the warning, including raising the cap above the
1868
+ * current spend).
1869
+ */
1870
+ _budgetWarned = false;
1858
1871
  sessionName;
1859
1872
  /**
1860
1873
  * Hook list, mutable so `/hooks reload` can swap it without
@@ -1920,6 +1933,7 @@ var CacheFirstLoop = class {
1920
1933
  this.model = opts.model ?? "deepseek-v4-flash";
1921
1934
  this.reasoningEffort = opts.reasoningEffort ?? "max";
1922
1935
  if (opts.autoEscalate !== void 0) this.autoEscalate = opts.autoEscalate;
1936
+ this.budgetUsd = typeof opts.budgetUsd === "number" && opts.budgetUsd > 0 ? opts.budgetUsd : null;
1923
1937
  this.maxToolIters = opts.maxToolIters ?? 64;
1924
1938
  this.hooks = opts.hooks ?? [];
1925
1939
  this.hookCwd = opts.hookCwd ?? process.cwd();
@@ -2159,6 +2173,16 @@ var CacheFirstLoop = class {
2159
2173
  }
2160
2174
  this.stream = this.branchEnabled ? false : this._streamPreference;
2161
2175
  }
2176
+ /**
2177
+ * Set / change / clear the soft USD budget. `null` (or any non-
2178
+ * positive number) disables the cap entirely. Re-arms the 80%
2179
+ * warning so a user who bumps the cap mid-session sees a fresh
2180
+ * threshold message at the new boundary.
2181
+ */
2182
+ setBudget(usd) {
2183
+ this.budgetUsd = typeof usd === "number" && usd > 0 ? usd : null;
2184
+ this._budgetWarned = false;
2185
+ }
2162
2186
  /**
2163
2187
  * Arm pro for the next turn (consumed at turn start). Called by
2164
2188
  * `/pro`. Idempotent — repeated calls stay armed, `disarmPro()`
@@ -2320,6 +2344,26 @@ var CacheFirstLoop = class {
2320
2344
  return userText;
2321
2345
  }
2322
2346
  async *step(userInput) {
2347
+ if (this.budgetUsd !== null) {
2348
+ const spent = this.stats.totalCost;
2349
+ if (spent >= this.budgetUsd) {
2350
+ yield {
2351
+ turn: this._turn,
2352
+ role: "error",
2353
+ content: "",
2354
+ error: `session budget exhausted \u2014 spent $${spent.toFixed(4)} \u2265 cap $${this.budgetUsd.toFixed(2)}. Bump the cap with /budget <usd>, clear it with /budget off, or end the session.`
2355
+ };
2356
+ return;
2357
+ }
2358
+ if (!this._budgetWarned && spent >= this.budgetUsd * 0.8) {
2359
+ this._budgetWarned = true;
2360
+ yield {
2361
+ turn: this._turn,
2362
+ role: "warning",
2363
+ content: `\u25B2 budget 80% used \u2014 $${spent.toFixed(4)} of $${this.budgetUsd.toFixed(2)}. Next turn or two likely trips the cap.`
2364
+ };
2365
+ }
2366
+ }
2323
2367
  this._turn++;
2324
2368
  this.scratch.reset();
2325
2369
  this.repair.resetStorm();