Class CostBudgetEnforcer

java.lang.Object
com.tnsai.quality.cost.CostBudgetEnforcer
All Implemented Interfaces:
com.tnsai.hooks.spi.Hook<com.tnsai.hooks.events.PreAction>

public final class CostBudgetEnforcer extends Object implements com.tnsai.hooks.spi.Hook<com.tnsai.hooks.events.PreAction>
Hook that enforces a CostBudget on every pre-LLM action (issue #82). Sits in the PreAction chain, matches only on ActionType.LLM, and either:
  • allows the call when the budget is not exceeded;
  • blocks it on BudgetPolicy.HARD_STOP when the spend so far + the pre-call estimate would exceed the cap;
  • logs a warning and allows on BudgetPolicy.SOFT_WARN;
  • blocks (the only sensible action — the framework owns no queue to defer into) on BudgetPolicy.DEFER, with a clear message so the consumer can implement the deferral externally.

Pluggable concerns

  • Budget resolution: the Function budgetResolver maps a PreAction to the most-specific CostBudget that applies. Returning Optional.empty() means "no budget configured for this scope, allow without enforcement". Implementations typically read a config map or a database.
  • Pre-call cost estimate: the Function estimator returns the predicted USD spend for a single call. The framework doesn't ship per-provider pricing today (see LLMPricingRegistry follow-up); a sensible default returns BigDecimal.ZERO, in which case the enforcer only blocks after the cap is already hit, never before a borderline call.

Why a hook

Same SPI surface as every other intercept point; consumers wire it via the standard HookDispatcher alongside security and audit hooks. No new framework primitive needed.
Since:
0.10.0 (issue #82 closeout)
  • Constructor Details

    • CostBudgetEnforcer

      public CostBudgetEnforcer(CostBudgetStore store, Function<com.tnsai.hooks.events.PreAction,Optional<CostBudget>> budgetResolver, Function<com.tnsai.hooks.events.PreAction,BigDecimal> estimator)
    • CostBudgetEnforcer

      public CostBudgetEnforcer(CostBudgetStore store, Function<com.tnsai.hooks.events.PreAction,Optional<CostBudget>> budgetResolver)
      Convenience for the common "don't pre-estimate" case — every call's cost is treated as 0, so the enforcer only fires after the cap is already crossed by recorded spend. Operators who want pre-estimate-driven blocking pass a real estimator.
  • Method Details

    • eventType

      public Class<com.tnsai.hooks.events.PreAction> eventType()
      Specified by:
      eventType in interface com.tnsai.hooks.spi.Hook<com.tnsai.hooks.events.PreAction>
    • matcher

      public com.tnsai.hooks.HookMatcher<com.tnsai.hooks.events.PreAction> matcher()
      Specified by:
      matcher in interface com.tnsai.hooks.spi.Hook<com.tnsai.hooks.events.PreAction>
    • priority

      public int priority()
      Specified by:
      priority in interface com.tnsai.hooks.spi.Hook<com.tnsai.hooks.events.PreAction>
    • apply

      public com.tnsai.hooks.HookResult<com.tnsai.hooks.events.PreAction> apply(com.tnsai.hooks.events.PreAction event)
      Specified by:
      apply in interface com.tnsai.hooks.spi.Hook<com.tnsai.hooks.events.PreAction>