Skip to content

refactor(ai): simplify Agent.fake()/record(), remove AgentBinding#188

Merged
tmgbedu merged 2 commits into
devfrom
task/agent-fake-record-1141
Jul 17, 2026
Merged

refactor(ai): simplify Agent.fake()/record(), remove AgentBinding#188
tmgbedu merged 2 commits into
devfrom
task/agent-fake-record-1141

Conversation

@tmgbedu

@tmgbedu tmgbedu commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Simplifies Agent.fake() / Agent.record() to return their fake objects directly instead of going through an AgentBinding indirection layer, then removes AgentBinding entirely.

  • Agent.fake(responses) returns AgentFake directly (unchanged behavior, was already direct).
  • Agent.record(cassette, messages) now returns AgentRecordFake directly — no more wrapping it in AgentBinding.
  • AgentRecordFake gains the container-binding (app().bind(...) / app().unbind(...)), cassette auto-resolution, and decorator (__call__) behavior that AgentBinding used to provide, so both usage forms keep working:
    • with Agent.record(cassette) as agent: ... (fluent handle)
    • with Agent.record(cassette): ... / @Agent.record(cassette) (bare context-manager/decorator binding a stand-in into the container for code under test)
  • AgentBinding is deleted, along with every reference to it (ai/agent.py import + type hint, ai/__init__.py export/__all__).
  • Fixed a pre-existing signature mismatch left over from an in-progress edit: Agent._stream() was calling _build_model(..., structured=False), but Ai.get_model_for()/Ai.build() had dropped the structured parameter — restored it so streaming still skips structured-output wrapping.
  • example/agents/tests/units/agents/record_stream.json is a legitimate new fixture: it's the cassette RouterAgent.record("record_stream.json") resolves to for example/agents/tests/units/agents/test_router_agent.py (cassette path resolves relative to the caller's file, distinct from the pre-existing example/agents/tests/features/record_stream.json).

Testing

  • uv run pytest fastapi_startkit/tests/ai -v — 273 passed
  • uv run pytest fastapi_startkit --ignore=tests/masoniteorm/postgres — 1883 passed, 7 skipped
  • uv run ruff check src/ tests/ — clean

…kes directly

Agent.fake()/record() now return AgentFake/AgentRecordFake directly instead
of wrapping the latter in an AgentBinding indirection layer. AgentRecordFake
gains the container-binding, cassette-resolution, and decorator behavior
AgentBinding used to provide, so `with Agent.record(...) as agent:` and the
`@Agent.record(...)` decorator form both keep working unchanged.

AgentBinding is removed entirely, along with every reference to it (imports,
__init__ exports, type hints, tests).
@tmgbedu
tmgbedu changed the base branch from main to dev July 17, 2026 20:05
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.23529% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...astapi_startkit/src/fastapi_startkit/ai/testing.py 81.81% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@tmgbedu tmgbedu closed this Jul 17, 2026
Two of the example/agents record() cassettes were recorded against message
text that no longer matches the tests' current wording, so their cache keys
never hit and every run fell through to a live Gemini call. The new
units/agents/record_stream.json fixture had the same problem in the other
direction: it only captured the first turn, so the second prompt() call and
the assert_response_judged() verdict both missed the cassette too.

Re-recorded all three cassettes against the real code path (mocking only the
network boundary and the judge, same seam test_agent_record_fluent.py uses)
so every prompt/stream/judge call in test_router_agent.py and
test_chat_controller.py now replays from disk with no live model calls.

uv.lock refreshes the editable fastapi-startkit metadata, which was stale
at 0.45.0 against the package's actual 0.50.0.
@tmgbedu tmgbedu reopened this Jul 17, 2026
@tmgbedu
tmgbedu merged commit c439527 into dev Jul 17, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant