Skip to content

[AAASM-4034] ✅ (sdk): Add langchain-installed __getattr__ contract test#205

Merged
Chisanan232 merged 3 commits into
masterfrom
v0.0.1/AAASM-4034/test/langchain_getattr_contract
Jul 3, 2026
Merged

[AAASM-4034] ✅ (sdk): Add langchain-installed __getattr__ contract test#205
Chisanan232 merged 3 commits into
masterfrom
v0.0.1/AAASM-4034/test/langchain_getattr_contract

Conversation

@Chisanan232

Copy link
Copy Markdown
Contributor

What

Adds a CI-gated test that exercises the AAASM-4014 delegating __getattr__ on AssemblyCallbackHandler against the real langchain_core.callbacks.BaseCallbackHandler, instead of the empty _FallbackBaseCallbackHandler every other delegation test runs against today.

  • New non-default langchain-test dependency group (langchain-core) in pyproject.toml, deliberately excluded from default-groups so the default suite stays fast and langchain-free.
  • New test/unit/adapters/langchain/test_getattr_contract_with_langchain.py, guarded by pytest.importorskip("langchain_core") (4 tests).
  • New focused langchain-contract-test job in ci.yaml that installs the group and runs only this file, wired into the ci-success aggregate gate.

Why

AAASM-4014 added __getattr__ forwarding of missing attributes to _interceptor so co-installed adapters (e.g. crewai) that look up check_tool_start on 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, because langchain_core was not a test dependency. This PR makes that guarantee executable.

The test asserts:

  • (a) every contract member (on_* event methods, ignore_* flags, raise_error/run_inline) resolves through normal class lookup — via inspect.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;
  • (b) with langchain co-installed, a non-contract governance member (check_tool_start) still delegates through __getattr__, and the crewai adapter path denies a policy-denied tool under enforce.

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

  • Default suite langchain-free: uv sync --frozen && .venv/bin/python -m pytest test/ → 737 passed, 17 skipped (new file skips cleanly).
  • Langchain leg: 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 check clean; full pre-commit (isort/autoflake/black/mypy/uv-lock) green.

How the langchain leg is gated/run

It is not in default-groups, so uv sync (and the main CI matrix, which installs the dev group) never installs langchain and the test skips. It runs only via the dedicated langchain-contract-test CI job (uv sync --frozen --group langchain-test), or locally with the same command.

Refs AAASM-4034

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

codecov Bot commented Jul 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@sonarqubecloud

sonarqubecloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

@Chisanan232

Copy link
Copy Markdown
Contributor Author

🤖 Claude Code review — approve

AAASM-4034 (follow-up to 4014). Test-only. New non-default langchain-test group (langchain-core>=0.3,<0.4, excluded from default-groups) + a focused CI leg wired into ci-success; the test is pytest.importorskip("langchain_core")-guarded so the default matrix stays langchain-free and skips cleanly.

Proves the AAASM-4014 __getattr__ contract-safety against the REAL LangChain base: inspect.getattr_static confirms every contract member (on_*, ignore_*, raise_error) resolves via normal class lookup — __getattr__ never fires for them (spy records zero delegated contract accesses) — while a non-contract governance member still delegates and denies a policy-denied tool under enforce. No behavior change; default suite 737 pass + 4 langchain-leg pass. CI green.

@Chisanan232 Chisanan232 merged commit 16aa6e7 into master Jul 3, 2026
29 checks passed
@Chisanan232 Chisanan232 deleted the v0.0.1/AAASM-4034/test/langchain_getattr_contract branch July 3, 2026 03:41
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