Skip to content

Support per-run cost limits in common.ai LLM and Agent operators - #71403

Open
Lee-W wants to merge 2 commits into
apache:mainfrom
astronomer:common-ai-cost-limit
Open

Support per-run cost limits in common.ai LLM and Agent operators#71403
Lee-W wants to merge 2 commits into
apache:mainfrom
astronomer:common-ai-cost-limit

Conversation

@Lee-W

@Lee-W Lee-W commented Aug 11, 2026

Copy link
Copy Markdown
Member

Why

Dag authors had no way to cap what a single LLM or Agent task is allowed to spend, and no way to see what one cost after the fact. pydantic-ai made both first-class in 2.23.0 via RunUsage.cost and UsageLimits.cost_limit.

What

Raising the floor is what unlocks the enforcement path — the operators already forward usage_limits untouched to run_sync, so cost_limit takes effect with no interception logic of our own. The max_cost parameter exists for the one thing usage_limits structurally cannot do: a UsageLimits object cannot be templated, so a budget that follows the environment had to be expressible as a scalar.

The docs deliberately spell out where the cap stops being a guarantee, since each of these reads as a broken promise to anyone who assumed otherwise: the request that crosses the limit still completes and still bills, self-hosted or unpriced models report no cost at all and the limit silently does nothing, and a durable replay re-counts the cached spend against a fresh attempt's budget.


Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Generated-by: [Claude] following the guidelines


  • Read the Pull Request Guidelines for more information. Note: commit author/co-author name and email in commits become permanently public when merged.
  • For fundamental code changes, an Airflow Improvement Proposal (AIP) is needed.
  • When adding dependency, check compliance with the ASF 3rd Party License Policy.
  • For significant user-facing changes create newsfragment: {pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.

@Lee-W
Lee-W force-pushed the common-ai-cost-limit branch 5 times, most recently from eb460d9 to acb43e9 Compare August 12, 2026 13:47
@Lee-W
Lee-W marked this pull request as ready for review August 13, 2026 02:17
``apache-airflow-providers-common-compat`` ``>=1.15.0``
``apache-airflow-providers-standard`` ``>=1.12.1``
``pydantic-ai-slim`` ``>=2.0.0``
``pydantic-ai-slim`` ``>=2.23.0``

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we could just upgrade this version since we're still in 0.x.x and the cost feature is something that would be widely used

Lee-W added 2 commits August 13, 2026 16:44
Dag authors had no way to cap what a single LLM or Agent task is allowed to
spend, and no way to see what one cost after the fact. pydantic-ai made both
first-class in 2.23.0 via RunUsage.cost and UsageLimits.cost_limit, but this
provider's floor was >=2.0.0, so neither existed for users here.

Raising the floor is what unlocks the enforcement path — the operators already
forward usage_limits untouched to run_sync, so cost_limit takes effect with no
interception logic of our own. The max_cost parameter exists for the one thing
usage_limits structurally cannot do: a UsageLimits object cannot be templated,
so a budget that follows the environment had to be expressible as a scalar.

The docs deliberately spell out where the cap stops being a guarantee, since
each of these reads as a broken promise to anyone who assumed otherwise: the
request that crosses the limit still completes and still bills, self-hosted or
unpriced models report no cost at all and the limit silently does nothing, and
a durable replay re-counts the cached spend against a fresh attempt's budget.
Because max_cost is templated, its value is often not in the Dag author's
control -- an unset Variable or a typo renders to a string the operator then
has to make sense of. An "inf" that passed validation left a cap that could
never be exceeded, which is worse than no cap at all: it reads as protection
that isn't there. "nan" escaped as a bare decimal.InvalidOperation from the
negativity comparison, contradicting the documented ValueError contract.

The classification call LLMRetryPolicy makes on every task failure is not an
operator run, so no cost cap has ever applied to it. That is pre-existing and
deliberate, but someone who sets max_cost reasonably expects it to bound
everything the task spends, so the exemption is now stated in the docs.

The provider requires pydantic-ai-slim 2.23.0 for the cost API, so the extras
now say so too rather than leaving a floor the resolver silently overrides.
@Lee-W
Lee-W force-pushed the common-ai-cost-limit branch from acb43e9 to 04872a2 Compare August 13, 2026 08:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant