Skip to content

feat(cloud): Enforce per-plan AI token allowance #9

Description

@nfebe

The cloud plugin should enforce a per-plan AI token allowance by implementing the usage half of the Entitlements seam. Core already gives the plugin what it needs: it gates each turn with remaining($owner, 'ai_tokens') and meters with consume($owner, 'ai_tokens', $n), both keyed on the polymorphic owner. The plugin supplies the counter storage, resolves the owner's allowance, and binds its implementation over the default AllowAllEntitlements.

Two things aren't in place yet: the owner's active plan is never persisted (plans exist only as marketing config), and core meters the agent route only, so a user can spend tokens on other routes without touching their allowance.

Checklist

  • Persist the owner's active plan in the plugin so remaining() can resolve an allowance (link an existing plan/subscription issue if one already covers this).
  • Add a token_allowance and a monthly reset period to each plan.
  • Create ai_usage_counters in the plugin, keyed polymorphically: morphs('owner'), period_start, tokens_used, unique(owner_type, owner_id, period_start).
  • Implement remaining('ai_tokens') as allowance minus current-period usage and consume('ai_tokens', n) as an increment. Bind over the default.
  • (core) Meter every token-spending path. The general and SmartQL replies and the per-turn classify and title calls currently call neither consume() nor record usage; only the agent route does.
  • (core) Fire consume() at most once per assistant message, keyed on the message id core already owns, so a job retry doesn't double-count.

Acceptance

  • A user over their allowance gets a quota-exceeded response from POST /api/v1/ai/chat.
  • Usage rolls over monthly.
  • A deployment with the cloud plugin disabled stays unlimited.
  • A core test confirms the counter matches the tokens core recorded for a turn.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions