kaxil commented on code in PR #71462:
URL: https://github.com/apache/airflow/pull/71462#discussion_r3765825944
##########
providers/anthropic/src/airflow/providers/anthropic/hooks/anthropic.py:
##########
@@ -123,6 +126,49 @@ def is_terminal(cls, status: str) -> bool:
#: ``session.status_idle`` stop reason emitted when a session stops against
its budget.
BUDGET_REACHED = "budget_reached"
+#: What a caller may pass as a session budget: an amount in USD, or the raw
API payload.
+BudgetSpec = str | int | float | Decimal | Mapping[str, Any]
+
+
+def build_budget(budget: BudgetSpec) -> dict[str, Any]:
+ """
+ Normalize a session budget into the API's ``max_list_cost`` payload.
+
+ A scalar is read as **US dollars** (``25``, ``25.0`` and ``"25.00"`` all
mean $25.00).
+ The API wants minor units as an integer decimal string, so the conversion
runs through
+ :class:`~decimal.Decimal` (never binary float) and rejects an amount finer
than a cent
+ rather than silently rounding money. A mapping is deep-copied and
otherwise returned
+ unchanged, so a raw payload the provider has not caught up with stays
usable without a
+ provider release.
+
+ .. warning::
+ The ceiling is a stop trigger, not a cap: it is checked between model
requests, so
+ a request already in flight can carry the session well past it.
+ """
+ if isinstance(budget, Mapping):
+ # Deep, not ``dict()``: a shallow copy leaves the nested
``max_list_cost`` aliased
+ # to the caller's object, so a later edit of the returned payload
would reach back
+ # into a templated operator field.
+ return deepcopy(dict(budget))
+ if isinstance(budget, bool):
+ raise ValueError(f"Invalid budget {budget!r}: expected an amount in
USD or a mapping.")
+ try:
+ dollars = Decimal(str(budget))
+ except (InvalidOperation, ValueError) as e:
+ raise ValueError(f"Invalid budget {budget!r}: not a decimal amount in
USD.") from e
Review Comment:
Applied -- you are right that it was dead code. `Decimal(str(True))` raises
`InvalidOperation` (`str(True)` is `'True'`), so bools were already rejected by
the parse below; the guard only changed which message they got.
One knock-on: `test_rejects_bad_amounts` had a case pinning the old
`expected an amount` message for `True`, so that param now matches `not a
decimal` instead. Without that the suite fails.
##########
providers/anthropic/docs/operators/anthropic.rst:
##########
@@ -147,9 +147,12 @@ Parameters
* ``poll_interval`` — seconds between session status checks.
* ``timeout`` — seconds to wait for a terminal status; defaults to 24 hours.
* ``vault_ids`` — vault IDs providing MCP/credential access to the session.
+* ``budget`` -- spend ceiling for the session, in US dollars (``25.00``) or as
the raw API
+ payload (a mapping). Templated. See `Session budgets`_ below.
Review Comment:
Expanded -- it now reads "Templated, so it can come from a Variable, a
params entry, or an upstream XCom." Agreed that the bare word assumes the
reader already knows what it buys them.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]