[AAASM-4034] ✅ (sdk): Add langchain-installed __getattr__ contract test#205
Conversation
Adds a `langchain-test` dependency group carrying `langchain-core`, deliberately excluded from `default-groups` so the default suite stays langchain-free and the existing callback-delegation tests keep exercising the empty `_FallbackBaseCallbackHandler` fallback. Installing the group swaps the real `BaseCallbackHandler` in as the base of `AssemblyCallbackHandler` for the AAASM-4034 contract test. Refs AAASM-4034
Exercises the AAASM-4014 delegating `__getattr__` against the real
`langchain_core.callbacks.BaseCallbackHandler`. Guarded by
`pytest.importorskip("langchain_core")` so it skips cleanly in the default
langchain-free suite. Asserts every LangChain callback-contract member
(`on_*` events, `ignore_*` flags, `raise_error`/`run_inline`) resolves via
normal class lookup and is never synthesized by `__getattr__`, while a
non-contract governance member still delegates and denies a policy-denied
tool through the crewai adapter path under enforce.
Refs AAASM-4034
Adds a focused ci.yaml job that installs the `langchain-test` group and runs only the contract test, wired into the `ci-success` aggregate gate so the `__getattr__` contract is exercised against the real LangChain base without swapping the base class under the main langchain-free test matrix. Refs AAASM-4034
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
|
🤖 Claude Code review — approve AAASM-4034 (follow-up to 4014). Test-only. New non-default Proves the AAASM-4014 |



What
Adds a CI-gated test that exercises the AAASM-4014 delegating
__getattr__onAssemblyCallbackHandleragainst the reallangchain_core.callbacks.BaseCallbackHandler, instead of the empty_FallbackBaseCallbackHandlerevery other delegation test runs against today.langchain-testdependency group (langchain-core) inpyproject.toml, deliberately excluded fromdefault-groupsso the default suite stays fast and langchain-free.test/unit/adapters/langchain/test_getattr_contract_with_langchain.py, guarded bypytest.importorskip("langchain_core")(4 tests).langchain-contract-testjob inci.yamlthat installs the group and runs only this file, wired into theci-successaggregate gate.Why
AAASM-4014 added
__getattr__forwarding of missing attributes to_interceptorso co-installed adapters (e.g. crewai) that look upcheck_tool_starton the LangChain handler reach real governance. Its safety — that delegation never shadows or synthesizes a genuine LangChain callback-contract member — was argued but never CI-tested, becauselangchain_corewas not a test dependency. This PR makes that guarantee executable.The test asserts:
on_*event methods,ignore_*flags,raise_error/run_inline) resolves through normal class lookup — viainspect.getattr_static, which never triggers__getattr__— to the base class (or to the four methods the handler overrides), and a spy interceptor records zero delegated accesses for the whole contract surface;check_tool_start) still delegates through__getattr__, and the crewai adapter path denies a policy-denied tool underenforce.No behavior change to
callback_handler.py— this is a test-only ticket. No genuine bug found; the__getattr__behaves exactly as its safety argument claims.How verified
uv sync --frozen && .venv/bin/python -m pytest test/→ 737 passed, 17 skipped (new file skips cleanly).uv sync --frozen --group langchain-test && .venv/bin/python -m pytest test/unit/adapters/langchain/test_getattr_contract_with_langchain.py→ 4 passed..venv/bin/mypy agent_assembly(with--ignore-missing-imports, as CI) clean;ruff checkclean; full pre-commit (isort/autoflake/black/mypy/uv-lock) green.How the langchain leg is gated/run
It is not in
default-groups, souv sync(and the main CI matrix, which installs thedevgroup) never installs langchain and the test skips. It runs only via the dedicatedlangchain-contract-testCI job (uv sync --frozen --group langchain-test), or locally with the same command.Refs AAASM-4034