Skip to content

[DX] BudgetExceededError surfaces raw traceback in CLI #1627

@Dhivya-Bharathy

Description

@Dhivya-Bharathy

Severity

Severity Category Issue Type
Medium DX / UX API design gap + unhandled exception propagation

Summary

Two related gaps affect the budget configuration experience:

  1. API discoverability: Agent() does not accept max_budget as a direct parameter. Passing it produces a raw TypeError with no guidance toward the correct API (ExecutionConfig).
  2. Unhandled propagation: BudgetExceededError raised inside chat_mixin.py propagates to the CLI as a full Python traceback. There is no handler in cli/main.py to format it as a user-facing message.

In both cases, the user receives an unformatted Python traceback instead of a clear, actionable error.

Note: These two gaps are linked by the same symptom (raw traceback) and the same fix location (cli/main.py). They can be resolved together or separately.


Affected Components

Component Location Issue
Agent.__init__() src/praisonaiagents/agent/agent.py max_budget not accepted as a direct parameter
BudgetExceededError src/praisonaiagents/agent/chat_mixin.py lines 630–635 Raised and re-raised, never formatted
CLI entry point src/praisonai/praisonai/cli/main.py No except BudgetExceededError handler

Issue Type: API design gap (parameter discoverability) + unhandled exception propagation (UX).


Expected vs Actual Behavior

Behavior
Expected ERROR: Budget limit exceeded. Spent $X.XX (limit: $Y.YY). To configure a budget, use ExecutionConfig(max_budget=...). — clean, single line
Actual Full Python traceback ending with TypeError or BudgetExceededError printed to stderr

Reproduction Steps

from praisonaiagents import Agent

# Gap 1: passing max_budget directly → raw TypeError
agent = Agent(
    name="TestAgent",
    instructions="You are a helpful assistant.",
    max_budget=0.000001,
)

Output:

TypeError: Agent.__init__() got an unexpected keyword argument 'max_budget'

No hint that ExecutionConfig(max_budget=...) is the correct path. No documentation reference.


Root Cause Analysis

Gap 1: Agent.__init__() uses **kwargs but does not include max_budget in its signature or produce a helpful redirect message when an unknown budget-related key is passed.

Gap 2: The execution flow for budget enforcement:

Agent.start()
    ↓
_arun_execution_loop()
    ↓
_aget_llm_response()   [chat_mixin.py]
    ↓
BudgetExceededError raised
    ↓
except BudgetExceededError: raise   ← intentionally re-raised
    ↓
cli/main.py                         ← no handler here
    ↓
Python default traceback printed to stderr

BudgetExceededError is defined in errors.py and raised correctly — the gap is the absence of a top-level CLI handler.


Impact Analysis

Dimension Detail
Affected users Any user who sets a cost budget or follows examples using max_budget
Discoverability High — max_budget is a natural parameter name; users try it first
Support overhead Users open issues or ask in forums rather than resolving independently
Pipeline impact Automated runs receive non-zero exit with no parseable error output

Why This Matters

Budget configuration is a first-class feature for production deployments. When the failure mode is a raw traceback, users cannot distinguish between a bug in their code and a framework-level issue. A clean, single-line error message reduces time-to-resolution from minutes to seconds.


Possible Fixes

Option A — Add BudgetExceededError handler to CLI entry point:

from praisonaiagents.errors import BudgetExceededError

try:
    result = run_agent(...)
except BudgetExceededError as e:
    click.echo(f"Error: {e}", err=True)
    click.echo("To adjust the budget, set max_budget in ExecutionConfig.", err=True)
    sys.exit(1)

Option B — Accept max_budget directly in Agent() as a convenience alias:

def __init__(self, ..., max_budget: float | None = None, ...):
    if max_budget is not None:
        execution = execution or ExecutionConfig()
        execution.max_budget = max_budget

This is fully backward compatible and additive — no existing calls are broken.

Option C — Improve the TypeError message for unknown budget parameters:

# In Agent.__init__, before raising TypeError for unknown kwargs:
if "max_budget" in kwargs:
    raise TypeError(
        "'max_budget' is not a direct Agent() parameter. "
        "Use: Agent(execution=ExecutionConfig(max_budget=...))"
    )

Backward Compatibility

  • Option A: Fully backward compatible — adds a handler, changes no existing behaviour.
  • Option B: Fully backward compatible — adds an alias parameter with default None.
  • Option C: Fully backward compatible — improves error message quality only.

Suggested Regression Test

def test_budget_exceeded_produces_clean_cli_output(capsys):
    """BudgetExceededError must not surface as a raw traceback."""
    # Run CLI with a budget that will be exceeded
    result = runner.invoke(cli, ["run", "--budget", "0.000001", "Say hello"])
    assert result.exit_code == 1
    assert "Traceback" not in result.output
    assert "budget" in result.output.lower()

Acceptance Criteria

  • BudgetExceededError is caught at the CLI level and produces a single-line error message
  • CLI exits with code 1 — not an unhandled exception exit
  • Either max_budget is accepted directly by Agent(), or the TypeError message explicitly redirects to ExecutionConfig
  • No raw Traceback block is shown to the end user for budget-related errors

Environment

OS      : Windows 10 (19045)
Python  : 3.13
Package : praisonaiagents 1.5.117 / praisonai 4.5.117
Install : pip

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdocumentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions