@animalabs/connectome-host 0.5.1 → 0.5.2
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/CHANGELOG.md +15 -0
- package/package.json +1 -1
- package/src/modules/web-ui-module.ts +37 -1
- package/web/src/Settings.tsx +64 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.5.2 — 2026-07-26
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Settings preview reported unreachable budgets as fitting.** context-manager's
|
|
10
|
+
`PreviewResult.budgetTokens` is the *rejection* budget —
|
|
11
|
+
`(requested - reserve) * (1 + overBudgetGraceRatio)` — and its `fits` means
|
|
12
|
+
"would not throw `OverBudgetError`", not "fits the budget you asked for". On
|
|
13
|
+
Mythos (`overBudgetGraceRatio: 0.35`) those differ by a third: previewing
|
|
14
|
+
250k reported `fits: true` at 273,828 tokens, a budget the picker had in fact
|
|
15
|
+
exhausted trying to reach. The endpoint now returns an `accounting` block
|
|
16
|
+
separating `fitsRequested` / `withinGrace` / `unreachable`, and the panel
|
|
17
|
+
renders three distinct verdicts (fits / over-requested-but-graced /
|
|
18
|
+
would-hard-fail) plus the full budget derivation.
|
|
19
|
+
|
|
5
20
|
## 0.5.1
|
|
6
21
|
|
|
7
22
|
### Added
|
package/package.json
CHANGED
|
@@ -1249,7 +1249,43 @@ export class WebUiModule implements Module {
|
|
|
1249
1249
|
{ status: 501 },
|
|
1250
1250
|
);
|
|
1251
1251
|
}
|
|
1252
|
-
|
|
1252
|
+
// Honest budget accounting. context-manager's `budgetTokens` is the
|
|
1253
|
+
// REJECTION budget: (requested - reserve) * (1 + overBudgetGraceRatio),
|
|
1254
|
+
// i.e. the threshold above which a compile throws. Its `fits` therefore
|
|
1255
|
+
// means "would not hard-fail", NOT "fits the budget you asked for".
|
|
1256
|
+
//
|
|
1257
|
+
// On a recipe with overBudgetGraceRatio 0.35 those differ by a third, so
|
|
1258
|
+
// reporting cm's `fits` verbatim told operators that a budget they
|
|
1259
|
+
// cannot actually reach was fine. Split the two questions apart and let
|
|
1260
|
+
// the panel say which one it means.
|
|
1261
|
+
const r = result as { finalTokens?: number; budgetTokens?: number; exhausted?: boolean };
|
|
1262
|
+
const reserve = app.recipe.agent.maxTokens ?? 16_384;
|
|
1263
|
+
const effectiveBudget = Math.max(0, budget - reserve);
|
|
1264
|
+
const finalTokens = typeof r.finalTokens === 'number' ? r.finalTokens : NaN;
|
|
1265
|
+
const fitsRequested = Number.isFinite(finalTokens) && finalTokens <= effectiveBudget;
|
|
1266
|
+
const withinGrace = Number.isFinite(finalTokens) && typeof r.budgetTokens === 'number'
|
|
1267
|
+
? finalTokens <= r.budgetTokens
|
|
1268
|
+
: undefined;
|
|
1269
|
+
return Response.json({
|
|
1270
|
+
agent: agentName,
|
|
1271
|
+
budget,
|
|
1272
|
+
...(overrides as object),
|
|
1273
|
+
accounting: {
|
|
1274
|
+
requestedBudgetTokens: budget,
|
|
1275
|
+
reserveForResponseTokens: reserve,
|
|
1276
|
+
/** What the picker actually targets. */
|
|
1277
|
+
effectiveBudgetTokens: effectiveBudget,
|
|
1278
|
+
/** Hard-fail ceiling — requested minus reserve, plus grace. */
|
|
1279
|
+
rejectionBudgetTokens: r.budgetTokens,
|
|
1280
|
+
/** Fits the budget the operator asked for. */
|
|
1281
|
+
fitsRequested,
|
|
1282
|
+
/** Merely tolerated by the grace margin — over budget, but no throw. */
|
|
1283
|
+
withinGrace,
|
|
1284
|
+
/** Exhausted AND over the request => this budget is UNREACHABLE. */
|
|
1285
|
+
unreachable: r.exhausted === true && !fitsRequested,
|
|
1286
|
+
},
|
|
1287
|
+
preview: result,
|
|
1288
|
+
});
|
|
1253
1289
|
} catch (err) {
|
|
1254
1290
|
return Response.json(
|
|
1255
1291
|
{ error: err instanceof Error ? err.message : String(err) },
|
package/web/src/Settings.tsx
CHANGED
|
@@ -36,6 +36,24 @@ export interface SettingsState {
|
|
|
36
36
|
previewAvailable: boolean;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Honest budget accounting from the server.
|
|
41
|
+
*
|
|
42
|
+
* `preview.fits` from context-manager means "would not throw OverBudgetError",
|
|
43
|
+
* which on a recipe with a grace ratio is NOT the same as "fits the budget you
|
|
44
|
+
* typed". These three flags keep the questions separate.
|
|
45
|
+
*/
|
|
46
|
+
interface PreviewAccounting {
|
|
47
|
+
requestedBudgetTokens: number;
|
|
48
|
+
reserveForResponseTokens: number;
|
|
49
|
+
effectiveBudgetTokens: number;
|
|
50
|
+
rejectionBudgetTokens?: number;
|
|
51
|
+
fitsRequested: boolean;
|
|
52
|
+
withinGrace?: boolean;
|
|
53
|
+
/** Picker exhausted AND still over the request — this budget cannot be reached. */
|
|
54
|
+
unreachable: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
39
57
|
interface PreviewResult {
|
|
40
58
|
finalTokens: number;
|
|
41
59
|
budgetTokens: number;
|
|
@@ -91,6 +109,7 @@ export function SettingsPanel(props: {
|
|
|
91
109
|
const [notify, setNotify] = createSignal(false);
|
|
92
110
|
|
|
93
111
|
const [preview, setPreview] = createSignal<PreviewResult | null>(null);
|
|
112
|
+
const [acct, setAcct] = createSignal<PreviewAccounting | null>(null);
|
|
94
113
|
const [previewErr, setPreviewErr] = createSignal<string | null>(null);
|
|
95
114
|
const [previewing, setPreviewing] = createSignal(false);
|
|
96
115
|
|
|
@@ -133,12 +152,15 @@ export function SettingsPanel(props: {
|
|
|
133
152
|
const body = await res.json();
|
|
134
153
|
if (!res.ok) {
|
|
135
154
|
setPreview(null);
|
|
155
|
+
setAcct(null);
|
|
136
156
|
setPreviewErr(body?.error ?? `HTTP ${res.status}`);
|
|
137
157
|
return;
|
|
138
158
|
}
|
|
139
159
|
setPreview(body.preview as PreviewResult);
|
|
160
|
+
setAcct((body.accounting ?? null) as PreviewAccounting | null);
|
|
140
161
|
} catch (e) {
|
|
141
162
|
setPreview(null);
|
|
163
|
+
setAcct(null);
|
|
142
164
|
setPreviewErr(e instanceof Error ? e.message : String(e));
|
|
143
165
|
} finally {
|
|
144
166
|
setPreviewing(false);
|
|
@@ -357,20 +379,45 @@ export function SettingsPanel(props: {
|
|
|
357
379
|
<Show when={preview()}>
|
|
358
380
|
{(p) => (
|
|
359
381
|
<div>
|
|
382
|
+
{/* Three distinct verdicts. Collapsing "fits your budget" into
|
|
383
|
+
"wouldn't throw" is how a 35%-grace recipe reports an
|
|
384
|
+
unreachable budget as fine — so they are kept apart. */}
|
|
360
385
|
<div
|
|
361
386
|
class={`px-2 py-1 rounded mb-1.5 text-[11px] border ${
|
|
362
|
-
|
|
387
|
+
acct()?.fitsRequested
|
|
363
388
|
? 'bg-emerald-950/40 border-emerald-800 text-emerald-300'
|
|
364
|
-
:
|
|
389
|
+
: acct()?.withinGrace
|
|
390
|
+
? 'bg-amber-950/40 border-amber-800 text-amber-200'
|
|
391
|
+
: 'bg-red-950/40 border-red-800 text-red-300'
|
|
365
392
|
}`}
|
|
366
393
|
>
|
|
367
|
-
{
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
394
|
+
<Show when={acct()?.fitsRequested}>
|
|
395
|
+
<div>
|
|
396
|
+
fits — {p().finalTokens.toLocaleString()} of{' '}
|
|
397
|
+
{acct()!.effectiveBudgetTokens.toLocaleString()} usable tok
|
|
398
|
+
</div>
|
|
399
|
+
</Show>
|
|
400
|
+
<Show when={!acct()?.fitsRequested && acct()?.withinGrace}>
|
|
401
|
+
<div>
|
|
402
|
+
OVER REQUESTED BUDGET — {p().finalTokens.toLocaleString()} tok vs{' '}
|
|
403
|
+
{acct()!.effectiveBudgetTokens.toLocaleString()} usable
|
|
404
|
+
</div>
|
|
405
|
+
<div class="text-[10px] opacity-90 mt-0.5">
|
|
406
|
+
it would not hard-fail, but only because the grace margin absorbs the
|
|
407
|
+
overshoot (ceiling {acct()!.rejectionBudgetTokens?.toLocaleString()}).
|
|
408
|
+
The context would run above your target indefinitely.
|
|
409
|
+
</div>
|
|
410
|
+
</Show>
|
|
411
|
+
<Show when={acct() && !acct()!.fitsRequested && acct()!.withinGrace === false}>
|
|
412
|
+
<div>
|
|
413
|
+
WOULD HARD-FAIL — {p().finalTokens.toLocaleString()} tok exceeds even the
|
|
414
|
+
grace ceiling {acct()!.rejectionBudgetTokens?.toLocaleString()}
|
|
415
|
+
</div>
|
|
416
|
+
</Show>
|
|
417
|
+
<Show when={acct()?.unreachable}>
|
|
371
418
|
<div class="text-[10px] opacity-90 mt-0.5">
|
|
372
|
-
picker exhausted
|
|
373
|
-
|
|
419
|
+
<b>unreachable:</b> the picker exhausted — nothing further can be folded,
|
|
420
|
+
so this budget cannot be reached no matter how long you wait.
|
|
374
421
|
</div>
|
|
375
422
|
</Show>
|
|
376
423
|
</div>
|
|
@@ -378,6 +425,10 @@ export function SettingsPanel(props: {
|
|
|
378
425
|
<table class="w-full font-mono text-[10px]">
|
|
379
426
|
<tbody>
|
|
380
427
|
<For each={[
|
|
428
|
+
['requested budget', acct()?.requestedBudgetTokens],
|
|
429
|
+
['− reserve for response', acct()?.reserveForResponseTokens],
|
|
430
|
+
['= usable for context', acct()?.effectiveBudgetTokens],
|
|
431
|
+
['grace ceiling (hard fail above)', acct()?.rejectionBudgetTokens],
|
|
381
432
|
['head (verbatim)', p().headTokens],
|
|
382
433
|
['tail (verbatim)', p().tailTokens],
|
|
383
434
|
['middle (foldable)', p().middleTokens],
|
|
@@ -389,7 +440,11 @@ export function SettingsPanel(props: {
|
|
|
389
440
|
<tr>
|
|
390
441
|
<td class="text-neutral-500 pr-2">{k}</td>
|
|
391
442
|
<td class="text-neutral-300 text-right tabular-nums">
|
|
392
|
-
{typeof v === 'number'
|
|
443
|
+
{typeof v === 'number'
|
|
444
|
+
? v.toLocaleString()
|
|
445
|
+
: v === undefined || v === null
|
|
446
|
+
? '–'
|
|
447
|
+
: String(v)}
|
|
393
448
|
</td>
|
|
394
449
|
</tr>
|
|
395
450
|
)}
|