floe-guard 0.13.0 → 0.13.1

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.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BudgetGuard, b as BudgetAdvisory } from './guard-BXtXoark.cjs';
2
- export { a as BudgetExceeded, c as BudgetGuardOptions, d as BudgetReservation, D as DeadlineExceeded, F as FloeGuardError, L as LedgerSyncError, M as ManualPrice, P as PricedModel, R as ReservationHandle, S as SpendEvent, T as TokenBudgetExceeded, U as UnpriceableModelError, e as UnpriceableVoiceError, p as priceTokens, f as pricing, r as resolvePrice } from './guard-BXtXoark.cjs';
1
+ import { B as BudgetGuard, b as BudgetAdvisory } from './guard-Ct38zQZS.cjs';
2
+ export { a as BudgetExceeded, c as BudgetGuardOptions, d as BudgetReservation, D as DeadlineExceeded, F as FloeGuardError, L as LedgerSyncError, M as ManualPrice, P as PricedModel, R as ReservationHandle, S as SpendEvent, T as TokenBudgetExceeded, U as UnpriceableModelError, e as UnpriceableVoiceError, p as priceTokens, f as pricing, r as resolvePrice } from './guard-Ct38zQZS.cjs';
3
3
 
4
4
  /**
5
5
  * LatencyBudget — a cumulative tool-chain deadline, sibling to BudgetGuard.
@@ -205,7 +205,14 @@ interface BudgetRetryOptions<T> {
205
205
  maxAttempts?: number;
206
206
  /** Choose a cheaper retry plan when `guard.advisory().nearLimit` is true. */
207
207
  onDegrade?: (error: unknown, advisory: BudgetAdvisory) => RetryPlan<T> | Promise<RetryPlan<T> | undefined> | undefined;
208
- /** Decide whether an error is retryable. Defaults to all non-budget errors. */
208
+ /**
209
+ * Decide whether an error is retryable.
210
+ *
211
+ * Defaults to all non-{@link FloeGuardError} errors — every
212
+ * {@link FloeGuardError} (including {@link BudgetExceeded} and
213
+ * {@link UnpriceableModelError}) is treated as terminal because retrying a
214
+ * deterministic guard error cannot fix it and would only multiply LLM spend.
215
+ */
209
216
  retryIf?: (error: unknown) => boolean;
210
217
  }
211
218
  /**
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BudgetGuard, b as BudgetAdvisory } from './guard-BXtXoark.js';
2
- export { a as BudgetExceeded, c as BudgetGuardOptions, d as BudgetReservation, D as DeadlineExceeded, F as FloeGuardError, L as LedgerSyncError, M as ManualPrice, P as PricedModel, R as ReservationHandle, S as SpendEvent, T as TokenBudgetExceeded, U as UnpriceableModelError, e as UnpriceableVoiceError, p as priceTokens, f as pricing, r as resolvePrice } from './guard-BXtXoark.js';
1
+ import { B as BudgetGuard, b as BudgetAdvisory } from './guard-Ct38zQZS.js';
2
+ export { a as BudgetExceeded, c as BudgetGuardOptions, d as BudgetReservation, D as DeadlineExceeded, F as FloeGuardError, L as LedgerSyncError, M as ManualPrice, P as PricedModel, R as ReservationHandle, S as SpendEvent, T as TokenBudgetExceeded, U as UnpriceableModelError, e as UnpriceableVoiceError, p as priceTokens, f as pricing, r as resolvePrice } from './guard-Ct38zQZS.js';
3
3
 
4
4
  /**
5
5
  * LatencyBudget — a cumulative tool-chain deadline, sibling to BudgetGuard.
@@ -205,7 +205,14 @@ interface BudgetRetryOptions<T> {
205
205
  maxAttempts?: number;
206
206
  /** Choose a cheaper retry plan when `guard.advisory().nearLimit` is true. */
207
207
  onDegrade?: (error: unknown, advisory: BudgetAdvisory) => RetryPlan<T> | Promise<RetryPlan<T> | undefined> | undefined;
208
- /** Decide whether an error is retryable. Defaults to all non-budget errors. */
208
+ /**
209
+ * Decide whether an error is retryable.
210
+ *
211
+ * Defaults to all non-{@link FloeGuardError} errors — every
212
+ * {@link FloeGuardError} (including {@link BudgetExceeded} and
213
+ * {@link UnpriceableModelError}) is treated as terminal because retrying a
214
+ * deterministic guard error cannot fix it and would only multiply LLM spend.
215
+ */
209
216
  retryIf?: (error: unknown) => boolean;
210
217
  }
211
218
  /**
package/dist/index.js CHANGED
@@ -772,19 +772,21 @@ var BudgetGuard = class {
772
772
  }
773
773
  /**
774
774
  * The ONE choke point, across two dimensions and two scopes. Returns the first
775
- * ceiling that blocks as `[dimension, scope]` — dimension `"usd" | "tokens"`,
776
- * scope `"aggregate" | "step"` — or `null` if the call fits everywhere.
777
- * Aggregate is checked before step (the guard-wide ceiling is the hard limit).
775
+ * ceiling that blocks as `[dimension, scope, spent, limit]` — dimension
776
+ * `"usd" | "tokens"`, scope `"aggregate" | "step"` — or `null` if the call
777
+ * fits everywhere. Aggregate is checked before step (the guard-wide ceiling
778
+ * is the hard limit). `spent` / `limit` are captured here so `raiseBlock`
779
+ * (called outside the lock) reads no shared state and stays race-free.
778
780
  */
779
781
  blockingCross(estimateUsd, estimateTokens) {
780
782
  const committed = this.spentUsd + this.reserved;
781
783
  if (committed > this.limitUsd - EPS || committed + estimateUsd > this.limitUsd + EPS) {
782
- return ["usd", "aggregate"];
784
+ return ["usd", "aggregate", this.spentUsd, this.limitUsd];
783
785
  }
784
786
  if (this.tokenLimit !== null) {
785
787
  const committedT = this.spentTokens + this.reservedTokens;
786
788
  if (committedT >= this.tokenLimit || committedT + estimateTokens > this.tokenLimit) {
787
- return ["tokens", "aggregate"];
789
+ return ["tokens", "aggregate", committedT, this.tokenLimit];
788
790
  }
789
791
  }
790
792
  const step = this.steps.length ? this.steps[this.steps.length - 1] : null;
@@ -792,36 +794,26 @@ var BudgetGuard = class {
792
794
  if (step.maxUsd !== null) {
793
795
  const sCommitted = step.spentUsd + step.reservedUsd;
794
796
  if (sCommitted > step.maxUsd - EPS || sCommitted + estimateUsd > step.maxUsd + EPS) {
795
- return ["usd", "step"];
797
+ return ["usd", "step", sCommitted, step.maxUsd];
796
798
  }
797
799
  }
798
800
  if (step.maxTokens !== null) {
799
801
  const sCommittedT = step.spentTokens + step.reservedTokens;
800
802
  if (sCommittedT >= step.maxTokens || sCommittedT + estimateTokens > step.maxTokens) {
801
- return ["tokens", "step"];
803
+ return ["tokens", "step", sCommittedT, step.maxTokens];
802
804
  }
803
805
  }
804
806
  }
805
807
  return null;
806
808
  }
807
- /** Notify + throw the right error for a [dimension, scope] block. */
809
+ /** Notify + throw the right error for a [dimension, scope, spent, limit] block. */
808
810
  raiseBlock(blocked) {
809
- const [dimension, scope] = blocked;
811
+ const [dimension, scope, spent, limit] = blocked;
810
812
  if (dimension === "usd") {
811
- this.onBlock(this.spentUsd, this.limitUsd);
812
- throw new BudgetExceeded(this.spentUsd, this.limitUsd);
813
+ this.onBlock(spent, limit);
814
+ throw new BudgetExceeded(spent, limit);
813
815
  }
814
- let spentT;
815
- let limitT;
816
- if (scope === "step") {
817
- const step = this.steps[this.steps.length - 1];
818
- spentT = step.spentTokens + step.reservedTokens;
819
- limitT = step.maxTokens ?? 0;
820
- } else {
821
- spentT = this.spentTokens + this.reservedTokens;
822
- limitT = this.tokenLimit ?? 0;
823
- }
824
- throw new TokenBudgetExceeded(spentT, limitT, scope);
816
+ throw new TokenBudgetExceeded(Math.trunc(spent), Math.trunc(limit), scope);
825
817
  }
826
818
  /**
827
819
  * Scope a per-step USD and/or token cap for a **sequential agent loop**.
@@ -1109,7 +1101,7 @@ function budgetGuardMiddleware(guard) {
1109
1101
 
1110
1102
  // src/retry.ts
1111
1103
  function defaultRetryIf(error) {
1112
- return !(error instanceof BudgetExceeded);
1104
+ return !(error instanceof FloeGuardError);
1113
1105
  }
1114
1106
  async function withBudgetRetry(guard, call, options = {}) {
1115
1107
  const maxAttempts = options.maxAttempts ?? 2;