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/cli/index.js +164 -39
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +32 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -548,8 +548,8 @@ var defaultSelector = (samples) => {
|
|
|
548
548
|
})[0];
|
|
549
549
|
};
|
|
550
550
|
async function runBranches(client, request, opts = {}) {
|
|
551
|
-
const
|
|
552
|
-
const temperatures = resolveTemperatures(
|
|
551
|
+
const budget2 = Math.max(1, opts.budget ?? 1);
|
|
552
|
+
const temperatures = resolveTemperatures(budget2, opts.temperatures);
|
|
553
553
|
const selector = opts.selector ?? defaultSelector;
|
|
554
554
|
const samples = await Promise.all(
|
|
555
555
|
temperatures.map(async (temperature, index) => {
|
|
@@ -586,12 +586,12 @@ function aggregateBranchUsage(samples) {
|
|
|
586
586
|
promptCacheMissTokens
|
|
587
587
|
};
|
|
588
588
|
}
|
|
589
|
-
function resolveTemperatures(
|
|
590
|
-
if (custom && custom.length >=
|
|
591
|
-
if (
|
|
589
|
+
function resolveTemperatures(budget2, custom) {
|
|
590
|
+
if (custom && custom.length >= budget2) return [...custom.slice(0, budget2)];
|
|
591
|
+
if (budget2 === 1) return [0];
|
|
592
592
|
const out = [];
|
|
593
|
-
for (let i = 0; i <
|
|
594
|
-
out.push(Number((i / (
|
|
593
|
+
for (let i = 0; i < budget2; i++) {
|
|
594
|
+
out.push(Number((i / (budget2 - 1)).toFixed(2)));
|
|
595
595
|
}
|
|
596
596
|
return out;
|
|
597
597
|
}
|
|
@@ -1276,29 +1276,29 @@ function truncateForModelByTokens(s, maxTokens) {
|
|
|
1276
1276
|
|
|
1277
1277
|
${tail}`;
|
|
1278
1278
|
}
|
|
1279
|
-
function sizePrefixToTokens(s,
|
|
1280
|
-
if (
|
|
1281
|
-
let size = Math.min(s.length,
|
|
1279
|
+
function sizePrefixToTokens(s, budget2) {
|
|
1280
|
+
if (budget2 <= 0 || s.length === 0) return "";
|
|
1281
|
+
let size = Math.min(s.length, budget2 * 4);
|
|
1282
1282
|
for (let iter = 0; iter < 6; iter++) {
|
|
1283
1283
|
if (size <= 0) return "";
|
|
1284
1284
|
const slice = s.slice(0, size);
|
|
1285
1285
|
const count = countTokens(slice);
|
|
1286
|
-
if (count <=
|
|
1287
|
-
const next = Math.floor(size * (
|
|
1286
|
+
if (count <= budget2) return slice;
|
|
1287
|
+
const next = Math.floor(size * (budget2 / count) * 0.95);
|
|
1288
1288
|
if (next >= size) return s.slice(0, Math.max(0, size - 1));
|
|
1289
1289
|
size = next;
|
|
1290
1290
|
}
|
|
1291
1291
|
return s.slice(0, Math.max(0, size));
|
|
1292
1292
|
}
|
|
1293
|
-
function sizeSuffixToTokens(s,
|
|
1294
|
-
if (
|
|
1295
|
-
let size = Math.min(s.length,
|
|
1293
|
+
function sizeSuffixToTokens(s, budget2) {
|
|
1294
|
+
if (budget2 <= 0 || s.length === 0) return "";
|
|
1295
|
+
let size = Math.min(s.length, budget2 * 4);
|
|
1296
1296
|
for (let iter = 0; iter < 6; iter++) {
|
|
1297
1297
|
if (size <= 0) return "";
|
|
1298
1298
|
const slice = s.slice(-size);
|
|
1299
1299
|
const count = countTokens(slice);
|
|
1300
|
-
if (count <=
|
|
1301
|
-
const next = Math.floor(size * (
|
|
1300
|
+
if (count <= budget2) return slice;
|
|
1301
|
+
const next = Math.floor(size * (budget2 / count) * 0.95);
|
|
1302
1302
|
if (next >= size) return s.slice(-Math.max(0, size - 1));
|
|
1303
1303
|
size = next;
|
|
1304
1304
|
}
|
|
@@ -1999,6 +1999,19 @@ var CacheFirstLoop = class {
|
|
|
1999
1999
|
* flip it live alongside `model`.
|
|
2000
2000
|
*/
|
|
2001
2001
|
autoEscalate = true;
|
|
2002
|
+
/**
|
|
2003
|
+
* Soft USD budget — see {@link CacheFirstLoopOptions.budgetUsd}.
|
|
2004
|
+
* Mutable so `/budget` slash can set / change / clear it mid-session.
|
|
2005
|
+
* `null` (the default) disables all budget checks.
|
|
2006
|
+
*/
|
|
2007
|
+
budgetUsd;
|
|
2008
|
+
/**
|
|
2009
|
+
* Set the first time a turn crosses 80% of the budget so the warning
|
|
2010
|
+
* doesn't repeat every turn afterwards. Cleared by `setBudget` (any
|
|
2011
|
+
* change re-arms the warning, including raising the cap above the
|
|
2012
|
+
* current spend).
|
|
2013
|
+
*/
|
|
2014
|
+
_budgetWarned = false;
|
|
2002
2015
|
sessionName;
|
|
2003
2016
|
/**
|
|
2004
2017
|
* Hook list, mutable so `/hooks reload` can swap it without
|
|
@@ -2064,6 +2077,7 @@ var CacheFirstLoop = class {
|
|
|
2064
2077
|
this.model = opts.model ?? "deepseek-v4-flash";
|
|
2065
2078
|
this.reasoningEffort = opts.reasoningEffort ?? "max";
|
|
2066
2079
|
if (opts.autoEscalate !== void 0) this.autoEscalate = opts.autoEscalate;
|
|
2080
|
+
this.budgetUsd = typeof opts.budgetUsd === "number" && opts.budgetUsd > 0 ? opts.budgetUsd : null;
|
|
2067
2081
|
this.maxToolIters = opts.maxToolIters ?? 64;
|
|
2068
2082
|
this.hooks = opts.hooks ?? [];
|
|
2069
2083
|
this.hookCwd = opts.hookCwd ?? process.cwd();
|
|
@@ -2303,6 +2317,16 @@ var CacheFirstLoop = class {
|
|
|
2303
2317
|
}
|
|
2304
2318
|
this.stream = this.branchEnabled ? false : this._streamPreference;
|
|
2305
2319
|
}
|
|
2320
|
+
/**
|
|
2321
|
+
* Set / change / clear the soft USD budget. `null` (or any non-
|
|
2322
|
+
* positive number) disables the cap entirely. Re-arms the 80%
|
|
2323
|
+
* warning so a user who bumps the cap mid-session sees a fresh
|
|
2324
|
+
* threshold message at the new boundary.
|
|
2325
|
+
*/
|
|
2326
|
+
setBudget(usd) {
|
|
2327
|
+
this.budgetUsd = typeof usd === "number" && usd > 0 ? usd : null;
|
|
2328
|
+
this._budgetWarned = false;
|
|
2329
|
+
}
|
|
2306
2330
|
/**
|
|
2307
2331
|
* Arm pro for the next turn (consumed at turn start). Called by
|
|
2308
2332
|
* `/pro`. Idempotent — repeated calls stay armed, `disarmPro()`
|
|
@@ -2464,6 +2488,26 @@ var CacheFirstLoop = class {
|
|
|
2464
2488
|
return userText;
|
|
2465
2489
|
}
|
|
2466
2490
|
async *step(userInput) {
|
|
2491
|
+
if (this.budgetUsd !== null) {
|
|
2492
|
+
const spent = this.stats.totalCost;
|
|
2493
|
+
if (spent >= this.budgetUsd) {
|
|
2494
|
+
yield {
|
|
2495
|
+
turn: this._turn,
|
|
2496
|
+
role: "error",
|
|
2497
|
+
content: "",
|
|
2498
|
+
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.`
|
|
2499
|
+
};
|
|
2500
|
+
return;
|
|
2501
|
+
}
|
|
2502
|
+
if (!this._budgetWarned && spent >= this.budgetUsd * 0.8) {
|
|
2503
|
+
this._budgetWarned = true;
|
|
2504
|
+
yield {
|
|
2505
|
+
turn: this._turn,
|
|
2506
|
+
role: "warning",
|
|
2507
|
+
content: `\u25B2 budget 80% used \u2014 $${spent.toFixed(4)} of $${this.budgetUsd.toFixed(2)}. Next turn or two likely trips the cap.`
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2467
2511
|
this._turn++;
|
|
2468
2512
|
this.scratch.reset();
|
|
2469
2513
|
this.repair.resetStorm();
|
|
@@ -2560,14 +2604,14 @@ var CacheFirstLoop = class {
|
|
|
2560
2604
|
let preHarvestedPlanState;
|
|
2561
2605
|
try {
|
|
2562
2606
|
if (this.branchEnabled) {
|
|
2563
|
-
const
|
|
2607
|
+
const budget2 = this.branchOptions.budget ?? 1;
|
|
2564
2608
|
yield {
|
|
2565
2609
|
turn: this._turn,
|
|
2566
2610
|
role: "branch_start",
|
|
2567
2611
|
content: "",
|
|
2568
2612
|
branchProgress: {
|
|
2569
2613
|
completed: 0,
|
|
2570
|
-
total:
|
|
2614
|
+
total: budget2,
|
|
2571
2615
|
latestIndex: -1,
|
|
2572
2616
|
latestTemperature: -1,
|
|
2573
2617
|
latestUncertainties: -1
|
|
@@ -2601,7 +2645,7 @@ var CacheFirstLoop = class {
|
|
|
2601
2645
|
onSampleDone
|
|
2602
2646
|
}
|
|
2603
2647
|
);
|
|
2604
|
-
for (let k = 0; k <
|
|
2648
|
+
for (let k = 0; k < budget2; k++) {
|
|
2605
2649
|
const sample = queue.shift() ?? await new Promise((resolve13) => {
|
|
2606
2650
|
waiter = resolve13;
|
|
2607
2651
|
});
|
|
@@ -2611,7 +2655,7 @@ var CacheFirstLoop = class {
|
|
|
2611
2655
|
content: "",
|
|
2612
2656
|
branchProgress: {
|
|
2613
2657
|
completed: k + 1,
|
|
2614
|
-
total:
|
|
2658
|
+
total: budget2,
|
|
2615
2659
|
latestIndex: sample.index,
|
|
2616
2660
|
latestTemperature: sample.temperature,
|
|
2617
2661
|
latestUncertainties: sample.planState.uncertainties.length
|
|
@@ -11401,13 +11445,13 @@ var MIN_DIFF_ROWS = 8;
|
|
|
11401
11445
|
function EditConfirm({ block, onChoose }) {
|
|
11402
11446
|
const { stdout: stdout3 } = useStdout2();
|
|
11403
11447
|
const rows = stdout3?.rows ?? 40;
|
|
11404
|
-
const
|
|
11448
|
+
const budget2 = Math.max(MIN_DIFF_ROWS, rows - MODAL_OVERHEAD_ROWS);
|
|
11405
11449
|
const allLines = useMemo(
|
|
11406
11450
|
() => formatEditBlockDiff(block, { contextLines: 2, maxLines: 1e5, indent: " " }),
|
|
11407
11451
|
[block]
|
|
11408
11452
|
);
|
|
11409
11453
|
const [scroll, setScroll] = useState2(0);
|
|
11410
|
-
const maxScroll = Math.max(0, allLines.length -
|
|
11454
|
+
const maxScroll = Math.max(0, allLines.length - budget2);
|
|
11411
11455
|
const effectiveScroll = Math.min(scroll, maxScroll);
|
|
11412
11456
|
useKeystroke((ev) => {
|
|
11413
11457
|
if (ev.paste) return;
|
|
@@ -11438,11 +11482,11 @@ function EditConfirm({ block, onChoose }) {
|
|
|
11438
11482
|
return;
|
|
11439
11483
|
}
|
|
11440
11484
|
if (key.pageDown || input === " " || input === "f") {
|
|
11441
|
-
setScroll((s) => Math.min(maxScroll, s + Math.max(1,
|
|
11485
|
+
setScroll((s) => Math.min(maxScroll, s + Math.max(1, budget2 - 2)));
|
|
11442
11486
|
return;
|
|
11443
11487
|
}
|
|
11444
11488
|
if (key.pageUp || input === "b") {
|
|
11445
|
-
setScroll((s) => Math.max(0, s - Math.max(1,
|
|
11489
|
+
setScroll((s) => Math.max(0, s - Math.max(1, budget2 - 2)));
|
|
11446
11490
|
return;
|
|
11447
11491
|
}
|
|
11448
11492
|
if (input === "g") {
|
|
@@ -11458,9 +11502,9 @@ function EditConfirm({ block, onChoose }) {
|
|
|
11458
11502
|
const removed = isNew ? 0 : (block.search.match(/\n/g)?.length ?? 0) + 1;
|
|
11459
11503
|
const added = block.replace === "" ? 0 : (block.replace.match(/\n/g)?.length ?? 0) + 1;
|
|
11460
11504
|
const tag = isNew ? "NEW" : "EDIT";
|
|
11461
|
-
const visibleLines = allLines.slice(effectiveScroll, effectiveScroll +
|
|
11505
|
+
const visibleLines = allLines.slice(effectiveScroll, effectiveScroll + budget2);
|
|
11462
11506
|
const hiddenAbove = effectiveScroll;
|
|
11463
|
-
const hiddenBelow = Math.max(0, allLines.length - effectiveScroll -
|
|
11507
|
+
const hiddenBelow = Math.max(0, allLines.length - effectiveScroll - budget2);
|
|
11464
11508
|
const totalLines = allLines.length;
|
|
11465
11509
|
const showScrollHud = hiddenAbove + hiddenBelow > 0;
|
|
11466
11510
|
const subtitleParts = [`-${removed} +${added} lines`];
|
|
@@ -13547,13 +13591,13 @@ function buildViewport(line, cursorCol, visibleCells, pastes) {
|
|
|
13547
13591
|
return clipAroundCursor(line, cursorCol, visibleCells, pastes);
|
|
13548
13592
|
}
|
|
13549
13593
|
function clipFromLeft(line, visibleCells, pastes) {
|
|
13550
|
-
const
|
|
13594
|
+
const budget2 = Math.max(1, visibleCells - 1);
|
|
13551
13595
|
let used = 0;
|
|
13552
13596
|
let end = 0;
|
|
13553
13597
|
while (end < line.length) {
|
|
13554
13598
|
const ch = line[end];
|
|
13555
13599
|
const cw = charCellsAt(line, end, pastes);
|
|
13556
|
-
if (used + cw >
|
|
13600
|
+
if (used + cw > budget2) break;
|
|
13557
13601
|
used += cw;
|
|
13558
13602
|
end++;
|
|
13559
13603
|
}
|
|
@@ -13561,10 +13605,10 @@ function clipFromLeft(line, visibleCells, pastes) {
|
|
|
13561
13605
|
return { segments, cursorCell: null, hiddenLeft: false, hiddenRight: end < line.length };
|
|
13562
13606
|
}
|
|
13563
13607
|
function clipAroundCursor(line, cursorCol, visibleCells, pastes) {
|
|
13564
|
-
let
|
|
13608
|
+
let budget2 = visibleCells;
|
|
13565
13609
|
const reservedForMarkers = 2;
|
|
13566
|
-
|
|
13567
|
-
const halfBudget = Math.floor(
|
|
13610
|
+
budget2 = Math.max(1, budget2 - reservedForMarkers);
|
|
13611
|
+
const halfBudget = Math.floor(budget2 / 2);
|
|
13568
13612
|
let start = cursorCol;
|
|
13569
13613
|
let leftCells = 0;
|
|
13570
13614
|
while (start > 0 && leftCells < halfBudget) {
|
|
@@ -13573,7 +13617,7 @@ function clipAroundCursor(line, cursorCol, visibleCells, pastes) {
|
|
|
13573
13617
|
start--;
|
|
13574
13618
|
leftCells += cw;
|
|
13575
13619
|
}
|
|
13576
|
-
const rightBudget =
|
|
13620
|
+
const rightBudget = budget2 - leftCells;
|
|
13577
13621
|
let end = cursorCol;
|
|
13578
13622
|
let rightCells = 0;
|
|
13579
13623
|
const cursorChar = cursorCol < line.length ? charCellsAt(line, cursorCol, pastes) : 1;
|
|
@@ -14080,7 +14124,8 @@ function StatsPanel({
|
|
|
14080
14124
|
busy,
|
|
14081
14125
|
proArmed,
|
|
14082
14126
|
escalated,
|
|
14083
|
-
dashboardUrl
|
|
14127
|
+
dashboardUrl,
|
|
14128
|
+
budgetUsd
|
|
14084
14129
|
}) {
|
|
14085
14130
|
const branchOn = (branchBudget ?? 1) > 1;
|
|
14086
14131
|
const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model2] ?? DEFAULT_CONTEXT_TOKENS;
|
|
@@ -14126,7 +14171,12 @@ function StatsPanel({
|
|
|
14126
14171
|
balance,
|
|
14127
14172
|
coldStart
|
|
14128
14173
|
}
|
|
14129
|
-
));
|
|
14174
|
+
), budgetUsd !== null && budgetUsd !== void 0 ? /* @__PURE__ */ React21.createElement(BudgetRow, { spent: summary.totalCostUsd, cap: budgetUsd }) : null);
|
|
14175
|
+
}
|
|
14176
|
+
function BudgetRow({ spent, cap }) {
|
|
14177
|
+
const pct2 = Math.max(0, spent / cap * 100);
|
|
14178
|
+
const color = pct2 >= 100 ? "#f87171" : pct2 >= 80 ? "#fbbf24" : "#94a3b8";
|
|
14179
|
+
return /* @__PURE__ */ React21.createElement(Box19, null, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, " budget "), /* @__PURE__ */ React21.createElement(Text17, { color }, `$${spent.toFixed(4)} / $${cap.toFixed(2)}`, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, ` (${pct2.toFixed(0)}%)`)));
|
|
14130
14180
|
}
|
|
14131
14181
|
function Header({
|
|
14132
14182
|
model: model2,
|
|
@@ -14828,6 +14878,12 @@ var SLASH_COMMANDS = [
|
|
|
14828
14878
|
summary: "arm v4-pro for the NEXT turn only (one-shot \xB7 auto-disarms after turn)",
|
|
14829
14879
|
argCompleter: ["off"]
|
|
14830
14880
|
},
|
|
14881
|
+
{
|
|
14882
|
+
cmd: "budget",
|
|
14883
|
+
argsHint: "[usd|off]",
|
|
14884
|
+
summary: "session USD cap \u2014 warns at 80%, refuses next turn at 100%. Off by default. /budget alone shows status",
|
|
14885
|
+
argCompleter: ["off", "1", "5", "10", "20", "50"]
|
|
14886
|
+
},
|
|
14831
14887
|
{ cmd: "mcp", summary: "list MCP servers + tools attached to this session" },
|
|
14832
14888
|
{
|
|
14833
14889
|
cmd: "resource",
|
|
@@ -16317,6 +16373,42 @@ var pro = (args, loop2, ctx) => {
|
|
|
16317
16373
|
};
|
|
16318
16374
|
};
|
|
16319
16375
|
var ESCALATION_MODEL_ID = "deepseek-v4-pro";
|
|
16376
|
+
var budget = (args, loop2) => {
|
|
16377
|
+
const arg = args[0]?.trim() ?? "";
|
|
16378
|
+
if (arg === "") {
|
|
16379
|
+
if (loop2.budgetUsd === null) {
|
|
16380
|
+
return {
|
|
16381
|
+
info: "no session budget set \u2014 Reasonix will keep going until you stop it. Set one with: /budget <usd> (e.g. /budget 5)"
|
|
16382
|
+
};
|
|
16383
|
+
}
|
|
16384
|
+
const spent2 = loop2.stats.totalCost;
|
|
16385
|
+
const pct2 = spent2 / loop2.budgetUsd * 100;
|
|
16386
|
+
return {
|
|
16387
|
+
info: `budget: $${spent2.toFixed(4)} of $${loop2.budgetUsd.toFixed(2)} (${pct2.toFixed(1)}%) \xB7 /budget off to clear, /budget <usd> to change`
|
|
16388
|
+
};
|
|
16389
|
+
}
|
|
16390
|
+
if (arg === "off" || arg === "none" || arg === "0") {
|
|
16391
|
+
loop2.setBudget(null);
|
|
16392
|
+
return { info: "budget \u2192 off (no cap)" };
|
|
16393
|
+
}
|
|
16394
|
+
const cleaned = arg.replace(/^\$/, "");
|
|
16395
|
+
const usd = Number(cleaned);
|
|
16396
|
+
if (!Number.isFinite(usd) || usd <= 0) {
|
|
16397
|
+
return {
|
|
16398
|
+
info: `usage: /budget <usd> (got "${arg}" \u2014 must be a positive number, e.g. /budget 5 or /budget 12.50)`
|
|
16399
|
+
};
|
|
16400
|
+
}
|
|
16401
|
+
loop2.setBudget(usd);
|
|
16402
|
+
const spent = loop2.stats.totalCost;
|
|
16403
|
+
if (spent >= usd) {
|
|
16404
|
+
return {
|
|
16405
|
+
info: `\u25B2 budget \u2192 $${usd.toFixed(2)} but already spent $${spent.toFixed(4)}. Next turn will be refused \u2014 bump the cap higher to keep going, or end the session.`
|
|
16406
|
+
};
|
|
16407
|
+
}
|
|
16408
|
+
return {
|
|
16409
|
+
info: `budget \u2192 $${usd.toFixed(2)} (so far: $${spent.toFixed(4)} \xB7 warns at 80%, refuses next turn at 100% \xB7 /budget off to clear)`
|
|
16410
|
+
};
|
|
16411
|
+
};
|
|
16320
16412
|
var handlers9 = {
|
|
16321
16413
|
model,
|
|
16322
16414
|
models,
|
|
@@ -16324,7 +16416,8 @@ var handlers9 = {
|
|
|
16324
16416
|
preset,
|
|
16325
16417
|
branch,
|
|
16326
16418
|
effort,
|
|
16327
|
-
pro
|
|
16419
|
+
pro,
|
|
16420
|
+
budget
|
|
16328
16421
|
};
|
|
16329
16422
|
|
|
16330
16423
|
// src/cli/ui/slash/handlers/observability.ts
|
|
@@ -17577,6 +17670,7 @@ function App({
|
|
|
17577
17670
|
transcript,
|
|
17578
17671
|
harvest: harvest3,
|
|
17579
17672
|
branch: branch2,
|
|
17673
|
+
budgetUsd,
|
|
17580
17674
|
session,
|
|
17581
17675
|
tools,
|
|
17582
17676
|
mcpSpecs,
|
|
@@ -17790,6 +17884,7 @@ function App({
|
|
|
17790
17884
|
model: model2,
|
|
17791
17885
|
harvest: harvest3,
|
|
17792
17886
|
branch: branch2,
|
|
17887
|
+
budgetUsd,
|
|
17793
17888
|
session,
|
|
17794
17889
|
hooks: hookList,
|
|
17795
17890
|
hookCwd: currentRootDir,
|
|
@@ -17800,7 +17895,7 @@ function App({
|
|
|
17800
17895
|
});
|
|
17801
17896
|
loopRef.current = l;
|
|
17802
17897
|
return l;
|
|
17803
|
-
}, [model2, system, harvest3, branch2, session, tools, codeMode]);
|
|
17898
|
+
}, [model2, system, harvest3, branch2, budgetUsd, session, tools, codeMode]);
|
|
17804
17899
|
useEffect6(() => {
|
|
17805
17900
|
loop2.hooks = hookList;
|
|
17806
17901
|
}, [loop2, hookList]);
|
|
@@ -20045,7 +20140,8 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
20045
20140
|
updateAvailable,
|
|
20046
20141
|
proArmed,
|
|
20047
20142
|
escalated: turnOnPro,
|
|
20048
|
-
dashboardUrl
|
|
20143
|
+
dashboardUrl,
|
|
20144
|
+
budgetUsd: loop2.budgetUsd
|
|
20049
20145
|
}
|
|
20050
20146
|
), /* @__PURE__ */ React24.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React24.createElement(EventRow, { key: item.id, event: item, projectRoot: currentRootDir })), !historical.some((e) => e.role === "user" || e.role === "assistant") && !busy && !streaming ? /* @__PURE__ */ React24.createElement(WelcomeBanner, { inCodeMode: !!codeMode }) : null, !PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && streaming ? /* @__PURE__ */ React24.createElement(Box22, { marginY: 1 }, /* @__PURE__ */ React24.createElement(EventRow, { event: streaming, projectRoot: currentRootDir })) : null, !PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && ongoingTool ? /* @__PURE__ */ React24.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && subagentActivity ? /* @__PURE__ */ React24.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !ongoingTool && statusLine ? /* @__PURE__ */ React24.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && undoBanner && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !pendingChoice && !stagedChoiceCustom && !pendingRevision ? /* @__PURE__ */ React24.createElement(UndoBanner, { banner: undoBanner }) : null, !PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React24.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React24.createElement(
|
|
20051
20147
|
PlanRefineInput,
|
|
@@ -20316,6 +20412,7 @@ function Root({
|
|
|
20316
20412
|
transcript: appProps.transcript,
|
|
20317
20413
|
harvest: appProps.harvest,
|
|
20318
20414
|
branch: appProps.branch,
|
|
20415
|
+
budgetUsd: appProps.budgetUsd,
|
|
20319
20416
|
session: appProps.session,
|
|
20320
20417
|
tools,
|
|
20321
20418
|
mcpSpecs,
|
|
@@ -20477,6 +20574,7 @@ async function codeCommand(opts = {}) {
|
|
|
20477
20574
|
await chatCommand({
|
|
20478
20575
|
model: opts.model ?? "deepseek-v4-flash",
|
|
20479
20576
|
harvest: opts.harvest ?? false,
|
|
20577
|
+
budgetUsd: opts.budgetUsd,
|
|
20480
20578
|
system: codeSystemPrompt2(rootDir, { hasSemanticSearch: semantic2.enabled }),
|
|
20481
20579
|
transcript: opts.transcript,
|
|
20482
20580
|
session,
|
|
@@ -21213,7 +21311,8 @@ async function runCommand2(opts) {
|
|
|
21213
21311
|
tools,
|
|
21214
21312
|
model: opts.model,
|
|
21215
21313
|
harvest: opts.harvest,
|
|
21216
|
-
branch: opts.branch
|
|
21314
|
+
branch: opts.branch,
|
|
21315
|
+
budgetUsd: opts.budgetUsd
|
|
21217
21316
|
});
|
|
21218
21317
|
const prefixHash = prefix.fingerprint;
|
|
21219
21318
|
let transcriptStream = null;
|
|
@@ -21769,6 +21868,17 @@ Your training data has a cutoff. When an answer's correctness depends on somethi
|
|
|
21769
21868
|
The signal isn't a topic list \u2014 it's: "if I'm wrong about this, is it because reality moved on?". If yes, ground the answer in fresh evidence; if no (definitions, mechanisms, well-established APIs), answer from memory.
|
|
21770
21869
|
|
|
21771
21870
|
${ESCALATION_CONTRACT}`;
|
|
21871
|
+
function parseBudgetFlag(raw) {
|
|
21872
|
+
if (raw === void 0) return void 0;
|
|
21873
|
+
if (!Number.isFinite(raw) || raw <= 0) {
|
|
21874
|
+
process.stderr.write(
|
|
21875
|
+
`\u25B2 ignoring --budget=${raw} (must be a positive number) \u2014 running with no cap
|
|
21876
|
+
`
|
|
21877
|
+
);
|
|
21878
|
+
return void 0;
|
|
21879
|
+
}
|
|
21880
|
+
return raw;
|
|
21881
|
+
}
|
|
21772
21882
|
var program = new Command();
|
|
21773
21883
|
program.name("reasonix").description("DeepSeek-native agent framework \u2014 built for cache hits and cheap tokens.").version(VERSION).option(
|
|
21774
21884
|
"-c, --continue",
|
|
@@ -21806,6 +21916,10 @@ program.command("code [dir]").description(
|
|
|
21806
21916
|
).option("-m, --model <id>", "Override default model (v4-flash)").option("--no-session", "Disable session persistence for this run").option("-r, --resume", "Skip the session picker \u2014 always continue prior messages").option("-n, --new", "Skip the session picker \u2014 always wipe prior messages and start fresh").option("--transcript <path>", "Write a JSONL transcript to this path").option(
|
|
21807
21917
|
"--harvest",
|
|
21808
21918
|
"Opt-in Pillar-2 plan-state extraction. Adds one flash call per turn; off by default (no preset enables it)."
|
|
21919
|
+
).option(
|
|
21920
|
+
"--budget <usd>",
|
|
21921
|
+
"Soft USD cap on session spend. Off by default. Warns at 80%, refuses next turn at 100%. Mid-session: /budget <usd> or /budget off.",
|
|
21922
|
+
(v) => Number.parseFloat(v)
|
|
21809
21923
|
).option(
|
|
21810
21924
|
"--no-dashboard",
|
|
21811
21925
|
"Suppress the auto-launched embedded web dashboard. Default behavior boots it on TUI mount and shows the URL in the status bar (clickable in OSC-8-aware terminals)."
|
|
@@ -21818,6 +21932,7 @@ program.command("code [dir]").description(
|
|
|
21818
21932
|
forceResume: !!opts.resume,
|
|
21819
21933
|
forceNew: !!opts.new,
|
|
21820
21934
|
harvest: !!opts.harvest,
|
|
21935
|
+
budgetUsd: parseBudgetFlag(opts.budget),
|
|
21821
21936
|
noDashboard: opts.dashboard === false
|
|
21822
21937
|
});
|
|
21823
21938
|
});
|
|
@@ -21831,6 +21946,10 @@ program.command("chat").description("Interactive Ink TUI with live cache/cost pa
|
|
|
21831
21946
|
"--branch <n>",
|
|
21832
21947
|
"Self-consistency: run N parallel samples per turn (N\xD7 cost). Manual only \u2014 never auto-enabled.",
|
|
21833
21948
|
(v) => Number.parseInt(v, 10)
|
|
21949
|
+
).option(
|
|
21950
|
+
"--budget <usd>",
|
|
21951
|
+
"Soft USD cap on session spend. Off by default. Warns at 80%, refuses next turn at 100%. Mid-session: /budget <usd> or /budget off.",
|
|
21952
|
+
(v) => Number.parseFloat(v)
|
|
21834
21953
|
).option("--session <name>", "Use a named session (default: from config, usually 'default').").option("--no-session", "Disable session persistence for this run (ephemeral chat)").option("-r, --resume", "Skip the session picker \u2014 always continue prior messages").option(
|
|
21835
21954
|
"-c, --continue",
|
|
21836
21955
|
"Resume the most-recently-used session (any name) without showing the picker."
|
|
@@ -21868,6 +21987,7 @@ program.command("chat").description("Interactive Ink TUI with live cache/cost pa
|
|
|
21868
21987
|
transcript: opts.transcript,
|
|
21869
21988
|
harvest: defaults.harvest,
|
|
21870
21989
|
branch: defaults.branch,
|
|
21990
|
+
budgetUsd: parseBudgetFlag(opts.budget),
|
|
21871
21991
|
session: continueOpts.session,
|
|
21872
21992
|
mcp: defaults.mcp,
|
|
21873
21993
|
mcpPrefix: opts.mcpPrefix,
|
|
@@ -21880,6 +22000,10 @@ program.command("run <task>").description("Run a single task non-interactively,
|
|
|
21880
22000
|
"--branch <n>",
|
|
21881
22001
|
"Self-consistency: run N parallel samples per turn and pick the most confident",
|
|
21882
22002
|
(v) => Number.parseInt(v, 10)
|
|
22003
|
+
).option(
|
|
22004
|
+
"--budget <usd>",
|
|
22005
|
+
"Soft USD cap on session spend. Off by default. Refuses to start a new turn once cumulative cost \u2265 cap.",
|
|
22006
|
+
(v) => Number.parseFloat(v)
|
|
21883
22007
|
).option("--transcript <path>", "Write a JSONL transcript to this path for replay/diff").option(
|
|
21884
22008
|
"--mcp <spec>",
|
|
21885
22009
|
'MCP server spec; repeatable. "name=cmd args...", "cmd args...", or a URL (http/https \u2192 SSE).',
|
|
@@ -21903,6 +22027,7 @@ program.command("run <task>").description("Run a single task non-interactively,
|
|
|
21903
22027
|
system: applyMemoryStack(opts.system, process.cwd()),
|
|
21904
22028
|
harvest: defaults.harvest,
|
|
21905
22029
|
branch: defaults.branch,
|
|
22030
|
+
budgetUsd: parseBudgetFlag(opts.budget),
|
|
21906
22031
|
transcript: opts.transcript,
|
|
21907
22032
|
mcp: defaults.mcp,
|
|
21908
22033
|
mcpPrefix: opts.mcpPrefix
|