Goal
Deprecate every standalone max_iterations surface in the v2 SDK and make Budget the single source of truth for run governance (cost, duration, iterations). Keep old code working via mapping + a DeprecationWarning. v2 only — leave v1 untouched.
This is part of a 3-repo change. The backend (platform-backend) is the authoritative normalizer and the engine (aixplain-agents) enforces; this SDK task is deliberately thin — map deprecated inputs into budget and forward, no merge/precedence logic.
Base branch
Branch off issue-953-v2budget-sdk-send-per-run-budget-to-agen (the per-run Budget feature, off development). Do not branch off main or development directly — the Budget class only exists on that branch.
Note: file:line references below are from that branch at time of writing — verify before editing, they may have shifted.
Target model
Budget (max_cost, max_duration_seconds, max_iterations) gains a second role: in addition to run-time agent.run(budget=...), it becomes persistable at agent creation time:
# persisted default budget (lives on the saved agent)
agent = aix.Agent(..., budget=Budget(max_iterations=10, max_cost=0.50))
# run-time budget; backend merges it field-by-field over the persisted default
resp = agent.run(query="...", budget=Budget(max_cost=1.0))
The SDK does not compute the effective budget (the field-level merge of persisted vs run-time needs the saved agent, which only the backend has). The SDK only: accepts budget at create + run, maps deprecated max_iterations into the matching budget slot, warns, and serializes.
Changes
1. Persist budget on Agent
- Add a persisted
budget: Optional[Budget] field to the v2 Agent dataclass (aixplain/v2/agent.py, near the existing field block ~L488).
- Serialize it into the create/save payload (
build_save_payload, ~L1310) as camelCase budget (reuse _normalize_budget, ~L681, and _BUDGET_PARAMS_MAP, ~L674).
2. Deprecate Agent.max_iterations (persisted create field)
- Keep the kwarg accepted. On set, emit:
warnings.warn("Agent 'max_iterations' is deprecated; use budget=Budget(max_iterations=...). It will be removed in a future release.", DeprecationWarning, stacklevel=2) (match the existing subagents/deprecation pattern ~L522).
- Fold it into the agent's default
budget.max_iterations only if budget.max_iterations is not already set. If both are set, Budget wins and additionally warn about the conflict.
- After folding, the SDK must emit only
budget in the create payload — stop emitting a standalone persisted maxIterations.
3. Deprecate the run-time max_iterations exec param
- In
build_run_payload (~L1341) / the run-params path: keep accepting run-time max_iterations, warn (same message, pointing at run(budget=...)), fold into the run-time budget.max_iterations (Budget wins on conflict).
- Stop emitting standalone
executionParams.maxIterations; remove max_iterations from _EXEC_PARAMS_MAP (L658) defaults block (L1405) emission, or guarantee it's never written when budget carries it. Verify nothing else relies on the standalone exec param being emitted.
4. Session execution config
aixplain/v2/session.py ExecutionConfig mirrors run params and has max_iterations in EXECUTION_PARAMS_MAP (~L30). Apply the same deprecation/fold-to-budget so sessions are consistent. Confirm ExecutionConfig can carry a budget.
Out of scope
- Effective-budget merge / precedence across persisted vs run-time (backend owns this).
- Graceful/reduced response on budget exhaustion (PROD-2471, engine follow-up).
- v1 (
aixplain/v1/...) — leave entirely as-is.
Acceptance criteria
Agent(budget=Budget(...)) persists and serializes budget in the create payload.
Agent(max_iterations=N) still works, emits a DeprecationWarning, and results in budget.maxIterations=N in the create payload with no top-level persisted maxIterations.
agent.run(max_iterations=N) still works, warns, and results in executionParams.budget.maxIterations=N with no executionParams.maxIterations.
- When both a deprecated
max_iterations and the matching Budget.max_iterations are set, the Budget value wins and a conflict warning is emitted.
- Sessions behave consistently.
- New unit tests cover: create-payload budget persistence, both deprecation→fold paths, the conflict-precedence rule, and absence of standalone
maxIterations in emitted payloads. Existing tests updated.
Verification
Inspect emitted payloads in tests (the budget branch already has payload-shape tests for executionParams.budget); assert standalone maxIterations is gone and budget.maxIterations is present.
Goal
Deprecate every standalone
max_iterationssurface in the v2 SDK and makeBudgetthe single source of truth for run governance (cost, duration, iterations). Keep old code working via mapping + aDeprecationWarning. v2 only — leave v1 untouched.This is part of a 3-repo change. The backend (
platform-backend) is the authoritative normalizer and the engine (aixplain-agents) enforces; this SDK task is deliberately thin — map deprecated inputs intobudgetand forward, no merge/precedence logic.Base branch
Branch off
issue-953-v2budget-sdk-send-per-run-budget-to-agen(the per-run Budget feature, offdevelopment). Do not branch offmainordevelopmentdirectly — theBudgetclass only exists on that branch.Target model
Budget(max_cost,max_duration_seconds,max_iterations) gains a second role: in addition to run-timeagent.run(budget=...), it becomes persistable at agent creation time:The SDK does not compute the effective budget (the field-level merge of persisted vs run-time needs the saved agent, which only the backend has). The SDK only: accepts budget at create + run, maps deprecated
max_iterationsinto the matching budget slot, warns, and serializes.Changes
1. Persist
budgetonAgentbudget: Optional[Budget]field to the v2Agentdataclass (aixplain/v2/agent.py, near the existing field block ~L488).build_save_payload, ~L1310) as camelCasebudget(reuse_normalize_budget, ~L681, and_BUDGET_PARAMS_MAP, ~L674).2. Deprecate
Agent.max_iterations(persisted create field)warnings.warn("Agent 'max_iterations' is deprecated; use budget=Budget(max_iterations=...). It will be removed in a future release.", DeprecationWarning, stacklevel=2)(match the existingsubagents/deprecation pattern ~L522).budget.max_iterationsonly ifbudget.max_iterationsis not already set. If both are set, Budget wins and additionally warn about the conflict.budgetin the create payload — stop emitting a standalone persistedmaxIterations.3. Deprecate the run-time
max_iterationsexec parambuild_run_payload(~L1341) / the run-params path: keep accepting run-timemax_iterations, warn (same message, pointing atrun(budget=...)), fold into the run-timebudget.max_iterations(Budget wins on conflict).executionParams.maxIterations; removemax_iterationsfrom_EXEC_PARAMS_MAP(L658) defaults block (L1405) emission, or guarantee it's never written when budget carries it. Verify nothing else relies on the standalone exec param being emitted.4. Session execution config
aixplain/v2/session.pyExecutionConfigmirrors run params and hasmax_iterationsinEXECUTION_PARAMS_MAP(~L30). Apply the same deprecation/fold-to-budget so sessions are consistent. ConfirmExecutionConfigcan carry abudget.Out of scope
aixplain/v1/...) — leave entirely as-is.Acceptance criteria
Agent(budget=Budget(...))persists and serializesbudgetin the create payload.Agent(max_iterations=N)still works, emits aDeprecationWarning, and results inbudget.maxIterations=Nin the create payload with no top-level persistedmaxIterations.agent.run(max_iterations=N)still works, warns, and results inexecutionParams.budget.maxIterations=Nwith noexecutionParams.maxIterations.max_iterationsand the matchingBudget.max_iterationsare set, the Budget value wins and a conflict warning is emitted.maxIterationsin emitted payloads. Existing tests updated.Verification
Inspect emitted payloads in tests (the budget branch already has payload-shape tests for
executionParams.budget); assert standalonemaxIterationsis gone andbudget.maxIterationsis present.