@cohortapp/agent-sdk 2.11.4 → 2.11.5

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.
@@ -663,7 +663,21 @@ export function dailyAllowance(deps) {
663
663
  * @param {object} [deps] { now?, ledgerDir?, agentRoot?, capUSD?, iterationCap?,
664
664
  * seatEnvelope?, mandateCachePath?, log? }
665
665
  */
666
+ /**
667
+ * Is this seat authenticated by a flat-fee Max SUBSCRIPTION (not the metered
668
+ * API)? A subscription seat has no dollar meter: the CLI's `total_cost_usd` is
669
+ * API-EQUIVALENT, not spend, and every session reports "unmeasured" by design —
670
+ * that is normal, not a telemetry outage. Banding such a seat on dollars
671
+ * suspends a seat that costs a flat fee, stops its autonomous work, and floods
672
+ * the log every tick. `deps.subscriptionAuth` overrides for tests.
673
+ */
674
+ export function isSubscriptionAuth(deps) {
675
+ if (deps && typeof deps.subscriptionAuth === "boolean") return deps.subscriptionAuth;
676
+ return process.env.MAESTRO_PREFER_SUBSCRIPTION_AUTH === "1" && !process.env.ANTHROPIC_API_KEY;
677
+ }
678
+
666
679
  export function dailyStatus(deps) {
680
+ const subscriptionAuth = isSubscriptionAuth(deps);
667
681
  const iterationCap = cfgIterationCap(deps);
668
682
  const today = sumToday(deps);
669
683
  const { spentUSD, sessions } = today;
@@ -708,15 +722,23 @@ export function dailyStatus(deps) {
708
722
  // The binding constraint is whichever is closest to (or furthest past) the cap.
709
723
  // A null day-reading contributes nothing; the exhausted-envelope case is
710
724
  // already ≥100 % on the month, so nothing is lost by skipping it.
711
- const pct = Math.max(spendPct ?? 0, monthPct, iterPct);
725
+ // A subscription-auth seat has no dollar meter (see isSubscriptionAuth): its
726
+ // dollar "spend" is API-equivalent fiction, so banding on it wrongly suspends a
727
+ // flat-fee seat and halts its autonomous work. Band it on SESSION VOLUME only
728
+ // (a real limit); concurrency (resource-governor) + the 429 rate-breaker are
729
+ // its other guards.
730
+ const pct = subscriptionAuth
731
+ ? iterPct
732
+ : Math.max(spendPct ?? 0, monthPct, iterPct);
712
733
  let band = bandForPct(pct);
713
734
 
714
735
  // ── BLIND ⇒ DEGRADE ────────────────────────────────────────────────────────
715
736
  // `blind` (sessions ran, none measured) was computed and reported and enforced
716
737
  // by nothing. It is now load-bearing: we do not invent a price, we lower the
717
738
  // rung. Only when the day is TRULY unpriceable — if a month mean was available
718
- // the spend was imputed from it and the ordinary band applies.
719
- if (today.blind && today.unpriceable && band < BLIND_MIN_BAND) {
739
+ // the spend was imputed from it and the ordinary band applies. Does NOT apply
740
+ // to subscription auth, where "unmeasured" is the normal, expected state.
741
+ if (!subscriptionAuth && today.blind && today.unpriceable && band < BLIND_MIN_BAND) {
720
742
  extraDegradations.push(
721
743
  `band raised ${band}% → ${BLIND_MIN_BAND}%: ${today.unmeasuredSessions} session(s) ran today and NONE could be ` +
722
744
  "measured or priced. An unmeasurable seat is degraded, not trusted."
@@ -725,7 +747,16 @@ export function dailyStatus(deps) {
725
747
  }
726
748
  const posture = postureForBand(band);
727
749
 
728
- const degradations = [...today.degradations, ...allowance.degradations, ...extraDegradations];
750
+ let degradations = [...today.degradations, ...allowance.degradations, ...extraDegradations];
751
+ // On a subscription seat the dollar-meter degradations (imputed / unmeasured /
752
+ // unfunded-envelope / telemetry) are irrelevant — there is no dollar meter —
753
+ // and were logged EVERY tick, burying real signal (a DM not answered) under a
754
+ // flood. Drop them; keep any non-dollar note (e.g. a malformed ledger line).
755
+ if (subscriptionAuth) {
756
+ degradations = degradations.filter(
757
+ (d) => !/imputed|unmeasured|unpriceable|UNFUNDED SEAT|envelope|per-session|telemetry|blind/i.test(String(d)),
758
+ );
759
+ }
729
760
  // Degradations ride on the returned status AND go to the log: the daemon is
730
761
  // usually the only thing awake when telemetry breaks, and a governor that
731
762
  // quietly under-counts is the failure mode this module now exists to prevent.
@@ -338,3 +338,28 @@ test("a ledger of only zero-token rows sums to $0 (proves the bug is the input,
338
338
  assert.equal(s.sessions, 2);
339
339
  } finally { await rm(dir); }
340
340
  });
341
+
342
+ test("dailyStatus: a subscription-auth seat is banded on session VOLUME, not dollars", async () => {
343
+ const dir = await makeLedgerDir();
344
+ try {
345
+ seedLedger(dir, [{ usd: 40 }]); // $40 of $10 = 400%
346
+ // A metered (API) seat: dollars bind → band 150 (refused).
347
+ assert.equal(dailyStatus({ ledgerDir: dir, now: clk, capUSD: 10, iterationCap: 100 }).band, 150);
348
+ // A flat-fee subscription seat has no dollar meter — the same API-equivalent
349
+ // "spend" is fiction. It lands at band 0 / normal so autonomous work keeps
350
+ // running; only session VOLUME can band it.
351
+ const sub = dailyStatus({ ledgerDir: dir, now: clk, capUSD: 10, iterationCap: 100, subscriptionAuth: true });
352
+ assert.equal(sub.band, 0);
353
+ assert.equal(sub.mode, "normal");
354
+ } finally { await rm(dir); }
355
+ });
356
+
357
+ test("dailyStatus: a subscription-auth seat STILL bands on session volume (a real limit)", async () => {
358
+ const dir = await makeLedgerDir();
359
+ try {
360
+ seedLedger(dir, Array.from({ length: 12 }, () => ({ usd: 0.01 }))); // 12 sessions
361
+ const sub = dailyStatus({ ledgerDir: dir, now: clk, capUSD: 1000, iterationCap: 10, subscriptionAuth: true });
362
+ assert.equal(sub.band, 100, "12 sessions / cap 10 = 120% → degrade even on subscription");
363
+ assert.equal(sub.mode, "degraded");
364
+ } finally { await rm(dir); }
365
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cohortapp/agent-sdk",
3
- "version": "2.11.4",
3
+ "version": "2.11.5",
4
4
  "description": "Cohort Agent SDK — autonomous AI colleague runtime. Deploy senior AI colleagues on dedicated Mac minis, wired to the Cohort operating surface.",
5
5
  "type": "module",
6
6
  "bin": {