feat(instrument): Smolagents adapter closure — sample + doc + alias (fixes mature label honesty)#109
Closed
mmercuri wants to merge 3 commits into
Closed
feat(instrument): Smolagents adapter closure — sample + doc + alias (fixes mature label honesty)#109mmercuri wants to merge 3 commits into
mmercuri wants to merge 3 commits into
Conversation
Bootstraps the LayerLens instrument layer with the abstract base classes,
adapter registry, capture configuration, event sinks, vendored event
schemas, and pydantic v1/v2 compatibility shim that every concrete
adapter (frameworks, protocols, providers) will depend on.
Scope
-----
- src/layerlens/instrument/__init__.py: lean re-export surface
- src/layerlens/instrument/_vendored/: frozen ateam event schemas (no
runtime ateam dependency)
- src/layerlens/instrument/adapters/_base/: BaseAdapter, AdapterRegistry,
AdapterStatus, AdapterHealth, AdapterCapability, ReplayableTrace,
CaptureConfig, EventSink, TraceStoreSink, IngestionPipelineSink,
PydanticCompat
- src/layerlens/_compat/pydantic.py: model_dump/model_validate shim
spanning pydantic v1 + v2
- scripts/{port_adapter,port_protocol,emit_adapter_manifest,
regen_dep_baselines}.py: codegen helpers used to port the rest of M1
- tests/instrument/{test_base_layer,test_lazy_imports,
test_default_install,test_resolved_dep_tree}.py + _baselines/
- .github/workflows/dep-tree-guard.yaml: CI gate that locks the default
install footprint
- docs/adapters/: CONTRIBUTING, STATUS, pydantic-compatibility, testing,
PERSONA_REVIEW
Blast radius
------------
- Pure additions. No public surface changes outside the new
layerlens.instrument namespace.
- Default `pip install layerlens` install set is unchanged (verified by
test_default_install.py against the new baseline).
- Lazy adapter discovery: importing layerlens.instrument MUST NOT pull
in any optional adapter dep (verified by test_lazy_imports.py).
Test plan
---------
- uv run pytest tests/instrument/test_base_layer.py
tests/instrument/test_lazy_imports.py -x -> 45 passed
- The dep-tree-guard workflow exercises test_default_install.py and
test_resolved_dep_tree.py against the new baselines on every PR.
LAY-3400 umbrella: this PR is the prerequisite for the M1.B/M1.C/M1.D
adapter ports, M7 protocol certification, and M8 Cohere/Mistral.
Ports the twelve agent-tier framework adapters from the ateam
reference implementation onto the new layerlens.instrument base layer:
Semantic Kernel, LlamaIndex, OpenAI Agents, Pydantic-AI, Agno,
Strands, SmolAgents, MS Agent Framework, Google ADK,
Bedrock Agents, Embedding (vector store hooks), Benchmark Import
Pairs with feat/instrument-frameworks-orchestration (M1.C part 1)
which lands LangChain, LangGraph, CrewAI, AutoGen, Langfuse, and
Agentforce. Together they complete M1.C.
Scope
-----
- src/layerlens/instrument/adapters/frameworks/{semantic_kernel,
llama_index,openai_agents,pydantic_ai,agno,strands,smolagents,
ms_agent_framework,google_adk,bedrock_agents,embedding,
benchmark_import}/: per-framework packages
- tests/instrument/adapters/frameworks/test_*_adapter.py + the
test_bulk_ported_smoke.py harness (which exercises every ported
adapter against canned trace fixtures so partial framework SDKs
on a given runner don't drop coverage to zero)
- samples/instrument/<framework>/: runnable per-framework samples
- docs/adapters/frameworks-<framework>.md: per-framework integration
guide
- pyproject.toml: twelve new optional extras
(semantic-kernel, llama-index, openai-agents, pydantic-ai, agno,
strands, smolagents, ms-agent-framework, google-adk,
bedrock-agents, embedding, benchmark-import) with python_version
markers; pyright/ruff exclusions for the dynamic monkey-patching
framework code
Blast radius
------------
- Default `pip install layerlens` install set is unchanged. Each
framework's heavy deps are gated behind their own extra.
- No changes to existing public API surface.
- Importing layerlens.instrument still does NOT pull in any framework
module (lazy registry lookup).
Test plan
---------
- uv run pytest tests/instrument/adapters/frameworks/ -x ->
184 passed, 1 skipped (test_bulk_ported_smoke.py covers all 12
agent-tier adapters plus the orchestration-tier ones from part 1
via the same harness)
Stacks on
---------
- feat/instrument-base-foundation (M1.A) — required for the
BaseAdapter surface this PR consumes.
Sibling of
----------
- feat/instrument-frameworks-orchestration (M1.C part 1) — both
branches stack on the base foundation independently and don't
conflict; they can land in either order.
LAY-3400 umbrella (M1.C part 2).
…on alias
The smolagents adapter is listed in scripts/emit_adapter_manifest.py
_MATURE alongside openai/anthropic/etc., but the manifest spec defines
"mature" as having BOTH a dedicated unit-test file AND a reference doc
in docs/adapters/. Until now smolagents had only the test file - no
sample, no doc - so the catalog was advertising a coverage tier the
artifacts did not back. Per CLAUDE.md (no fake data, no inflated
labels, complete means complete), the label was misleading customers
who saw "mature" and assumed full documentation parity.
This PR closes the artifact gap so the existing label is truthful:
* docs/adapters/frameworks-smolagents.md - install, quick-start,
events emitted, lifecycle hooks, capability matrix, version
compatibility, BYOK, and backward-compat notes. Mirrors the
structure of frameworks-agno.md.
* samples/instrument/smolagents/{main,__init__}.py + README.md - a
fully offline-runnable demo using a duck-typed _FakeAgent so the
wrapper, lifecycle hooks, and event emission can be exercised with
zero dependencies (no smolagents install, no OpenAI key, no
network). Diverges from the agno sample's required-OPENAI_API_KEY
pattern intentionally so contributors can verify the adapter on
any laptop in CI.
* STRATIXSmolAgentsAdapter deprecation alias via PEP 562
__getattr__ in the package __init__.py. The legacy
STRATIX-branded name still imports for one deprecation cycle and
emits DeprecationWarning on first access. New tests cover both
the alias resolution and the unknown-attribute path.
NOT in scope: decomposing the 388-LOC single-file lifecycle.py into
sub-modules. That refactor is a follow-up PR; this one is artifact-
only closure to match the manifest's existing tier claim.
Acceptance:
* uv run pytest tests/instrument/adapters/frameworks/test_smolagents_adapter.py -x -> 14 passed
* uv run mypy --strict src/layerlens/instrument/adapters/frameworks/smolagents -> clean
* uv run ruff check ...smolagents tests/.../test_smolagents_adapter.py -> clean
* uv run python -m samples.instrument.smolagents.main -> 3 events emitted, deterministic output
* Lazy-import + default-install guards still pass for smolagents
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this PR exists
scripts/emit_adapter_manifest.pylistssmolagentsin the_MATUREset(line 156), alongside
openai,anthropic,aws_bedrock, etc. Themanifest schema docstring defines
matureas:Audit finding:
smolagentshad the test file(
tests/instrument/adapters/frameworks/test_smolagents_adapter.py) butno
docs/adapters/frameworks-smolagents.mdand nosamples/instrument/smolagents/. The atlas-app catalog UI wastherefore advertising a tier the SDK could not back, in violation of
CLAUDE.md's "no fake data, no inflated labels, complete means
complete" rule.
This PR closes the artifact gap so the existing
maturelabel istruthful — no scope expansion, no decomposition of the 388-LOC
lifecycle.py(that is a separate follow-up PR).What's in the PR
1. Reference doc (
docs/adapters/frameworks-smolagents.md)Mirrors the structure of
frameworks-agno.md:CodeAgent+HfApiModelCodeAgentvsToolCallingAgent, idempotent re-instrumentation,per-thread
duration_nscorrectnesscapture_content=False(PII-sensitive)
STRATIXSmolAgentsAdapterdeprecation alias2. Offline-runnable sample (
samples/instrument/smolagents/)main.py,__init__.py,README.mdsamples/instrument/agno/"requiresOPENAI_API_KEY"pattern intentionally — the sample uses a duck-typed
_FakeAgentsoevery developer can run
python -m samples.instrument.smolagents.mainwith zero installs, zero network, zero API keys. The README
documents the live-path swap (real
CodeAgent+HttpEventSink).for CI snapshotting.
3. STRATIX → LayerLens deprecation alias
STRATIXSmolAgentsAdapterre-exposed via PEP 562 module__getattr__insrc/.../smolagents/__init__.py, withDeprecationWarningon first access.__all__and__dir__for IDE /dir()discoverability.test_legacy_stratix_alias_warns_and_resolves,test_unknown_attribute_still_raises_attribute_error.strings to sweep within the smolagents adapter package.
Out of scope (explicitly)
lifecycle.pyinto sub-modules — separatefollow-up PR.
callback hooks; documented as caller-driven for now.
Acceptance — STRICT (all green)
Lazy-import + default-install guards still pass for smolagents
(
tests/instrument/test_lazy_imports.py— bothtest_layerlens_import_does_not_pull_frameworksandtest_instrument_import_does_not_pull_frameworksgreen).CLAUDE.md commercial-grade compliance