Skip to content

Apply review feedback: per-mode breaker split, adapter runner classes, docs fixes (#9, #10, #11)#12

Open
kamil-duszynski-dna wants to merge 3 commits into
mainfrom
review-fixes-9-10-11
Open

Apply review feedback: per-mode breaker split, adapter runner classes, docs fixes (#9, #10, #11)#12
kamil-duszynski-dna wants to merge 3 commits into
mainfrom
review-fixes-9-10-11

Conversation

@kamil-duszynski-dna

Copy link
Copy Markdown
Collaborator

Summary

Addresses three rounds of reviewer feedback. The branch bundles issues
#9, #10 and #11 as three focused commits.

The package stays mypy --strict clean and the full suite is green
(98 passed).


#9 — Split CircuitBreaker by mode + review cleanups

  • Split into a base + per-mode strategies. CircuitBreaker(mode=...) is now
    a constructor that dispatches to internal _BudgetGuardBreaker /
    _LoopKillerBreaker. Each strategy is free of mode branching, so the
    per-method is None limit checks are gone.
  • Mode is now an Enum (Mode.BUDGET_GUARD / Mode.LOOP_KILLER). The
    hand-rolled mode assertion is replaced by coerce_mode, which still accepts
    the string values ("budget-guard" / "loop-killer") for ergonomics.
  • Numeric guards moved to core/_numbers.py: is_positive_integer
    (three-state) and is_non_negative_finite; the _describe helper is removed.
  • Removed the dead return after _trip (which is NoReturn).
  • Renames: set_token_snapshotset_tokens; TokenMetrics /
    ExtractedTokens fields input/outputinput_tokens/output_tokens.

Note: per the reviewer's choice, Mode is a plain Enum, so equality with raw
strings (mode == "budget-guard") no longer holds — assertions were updated to
compare against Mode members. String values are still accepted at all public
boundaries via coerce_mode.

#10 — Documentation fixes

  • Corrected the type-check claim. "mypy --strict clean" was misleading:
    python -m mypy / mypy --strict src are clean, but mypy --strict . reports
    errors because the test suite isn't held to strict typing. The wording now says
    the package is strict-clean.
  • Sorted the repository-layout tree (directories before files, core first)
    and added the previously-missing core/_numbers.py entry.

The reviewer's suggestion to change python -m mypy && python -m pytest to a
single & was not applied&& is correct (gate + shared exit code);
& would background mypy and run pytest in parallel, losing both.

#11 — Adapter runner classes (drop with_circuit_breaker)

  • Removed the four identically-named with_circuit_breaker functions (the
    with prefix collided with the keyword and the duplicated names were a smell).

  • New base CircuitBreakerRunner (_runner.py): captures the breaker
    config, mints a fresh breaker per run, gates the preflight estimator,
    resolves on_trip, and implements the context-manager protocol.

  • One distinct subclass per adapter with a unified run() method:
    OpenAIAgentsCircuitBreakerRunner, LangChainCircuitBreakerRunner,
    ClaudeAgentCircuitBreakerRunner, LangGraphCircuitBreakerRunner.

  • Canonical usage is a context manager:

    with OpenAIAgentsCircuitBreakerRunner(agent, max_input_token=50_000) as safe:
        result = await safe.run("Analyze this dataset")

Two design notes surfaced during review: the context manager is intentionally
minimal (the breaker is per-run, not per-block — documented in the base
class), and LangChain's run() is now async (awaits ainvoke, falls back to


Breaking changes

Pre-1.0; per AGENTS.md we prefer cleaner APIs over compat shims.

  • with_circuit_breaker(...)<Framework>CircuitBreakerRunner(...) used as a
    context manager, with a unified .run() method.
  • Mode is an Enum (string values still accepted on input).
  • CircuitBreaker.set_token_snapshotset_tokens.
  • TokenMetrics.input / .output.input_tokens / .output_tokens.

Testing

  • python -m mypy — clean (20 source files).
  • python -m pytest98 passed (includes new context-manager coverage per
    adapter).

Address reviewer comments on the core breaker:

- Split CircuitBreaker into a base + per-mode strategies
  (_BudgetGuardBreaker / _LoopKillerBreaker); the public constructor
  dispatches on `mode`, so each strategy is free of mode branching and
  the `is None` limit checks disappear.
- Make Mode an Enum; replace the hand-rolled mode assertion with
  coerce_mode (accepts a Mode member or its string value).
- Move numeric guards to core/_numbers.py: is_positive_integer
  (tri-state) and is_non_negative_finite; drop the _describe helper.
- Remove the dead `return` after _trip (which is NoReturn).
- Rename set_token_snapshot -> set_tokens and TokenMetrics/ExtractedTokens
  fields input/output -> input_tokens/output_tokens.

Tests, README and AGENTS.md updated. mypy --strict clean.
- Clarify the type-check statement: the package (src/) is mypy --strict
  clean via `python -m mypy`; the test suite isn't held to strict typing,
  so bare `mypy --strict .` reports errors.
- Sort the repository-layout tree (dirs before files, core first) and add
  the previously-missing core/_numbers.py entry.
Drop the four identically-named with_circuit_breaker functions in favour of
per-adapter OOP runners (the word "with" collided with the keyword and the
duplicated names were a code smell):

- Add CircuitBreakerRunner base (_runner.py): captures the breaker config,
  mints a fresh breaker per run, gates the preflight estimator, resolves
  on_trip, and implements the context-manager protocol.
- Each adapter exposes a distinct subclass with a unified run() method:
  OpenAIAgentsCircuitBreakerRunner, LangChainCircuitBreakerRunner,
  ClaudeAgentCircuitBreakerRunner, LangGraphCircuitBreakerRunner.
- Canonical usage is a context manager:
      with OpenAIAgentsCircuitBreakerRunner(agent) as safe:
          await safe.run(...)

Update adapter exports, tests (incl. context-manager coverage), README and
AGENTS.md. mypy --strict clean.
@kamil-duszynski-dna kamil-duszynski-dna self-assigned this Jun 16, 2026
@kamil-duszynski-dna kamil-duszynski-dna added the enhancement New feature or request label Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant