From 829a135072b843b6d1153fe2c6ad097c3e306824 Mon Sep 17 00:00:00 2001 From: Abhishek Mishra Date: Wed, 16 Sep 2026 00:13:40 +0530 Subject: [PATCH 1/3] fix(crew): export public API from smallestai.atoms.crew (lazy) crew/__init__.py was docstring-only, so 'from smallestai.atoms.crew import AtomsCrewApp' raised ImportError (customer-reported) even though the docstring advertised that path. Add a PEP 562 __getattr__ that lazily imports the public symbols (AtomsCrewApp, CrewSession, OutputCrewNode, BackgroundCrewNode, OpenAIClient, function_tool, ToolRegistry) from their submodules. Lazy so importing the package doesn't eagerly pull crew runtime deps (fastapi/uvicorn); the .server submodule paths still work. TYPE_CHECKING block keeps type/IDE resolution. Verified: package import needs no fastapi; short import resolves. --- src/smallestai/atoms/crew/__init__.py | 47 ++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/smallestai/atoms/crew/__init__.py b/src/smallestai/atoms/crew/__init__.py index e63509ac..d0c52f54 100644 --- a/src/smallestai/atoms/crew/__init__.py +++ b/src/smallestai/atoms/crew/__init__.py @@ -5,9 +5,48 @@ chatbots, and other interactive AI applications. Usage: + from smallestai.atoms.crew import AtomsCrewApp + from smallestai.atoms.crew import CrewSession + from smallestai.atoms.crew import OutputCrewNode, BackgroundCrewNode + from smallestai.atoms.crew import OpenAIClient + from smallestai.atoms.crew import function_tool, ToolRegistry + +The submodule paths (e.g. ``smallestai.atoms.crew.server``) also work. +""" + +from typing import TYPE_CHECKING + +# Public API. Imported lazily via __getattr__ (PEP 562) so that importing this +# package does not eagerly pull in the crew runtime deps (fastapi, uvicorn, ...) +# that `server` and friends need. Access a name and it is imported on demand. +_LAZY_EXPORTS = { + "AtomsCrewApp": "smallestai.atoms.crew.server", + "CrewSession": "smallestai.atoms.crew.session", + "OutputCrewNode": "smallestai.atoms.crew.nodes", + "BackgroundCrewNode": "smallestai.atoms.crew.nodes", + "OpenAIClient": "smallestai.atoms.crew.clients.openai", + "function_tool": "smallestai.atoms.crew.tools", + "ToolRegistry": "smallestai.atoms.crew.tools", +} + +__all__ = list(_LAZY_EXPORTS.keys()) + +if TYPE_CHECKING: + from smallestai.atoms.crew.clients.openai import OpenAIClient + from smallestai.atoms.crew.nodes import BackgroundCrewNode, OutputCrewNode from smallestai.atoms.crew.server import AtomsCrewApp from smallestai.atoms.crew.session import CrewSession - from smallestai.atoms.crew.nodes import OutputCrewNode, BackgroundCrewNode - from smallestai.atoms.crew.clients.openai import OpenAIClient - from smallestai.atoms.crew.tools import function_tool, ToolRegistry -""" + from smallestai.atoms.crew.tools import ToolRegistry, function_tool + + +def __getattr__(name: str): + module_path = _LAZY_EXPORTS.get(name) + if module_path is None: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + import importlib + + return getattr(importlib.import_module(module_path), name) + + +def __dir__(): + return sorted(list(globals().keys()) + __all__) From dc2f65c4a90a2892ed83d4d8ced19d33c88c6045 Mon Sep 17 00:00:00 2001 From: Abhishek Mishra Date: Wed, 16 Sep 2026 01:13:31 +0530 Subject: [PATCH 2/3] fix(crew): redundant-alias re-exports in TYPE_CHECKING to satisfy ruff F401 --- src/smallestai/atoms/crew/__init__.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/smallestai/atoms/crew/__init__.py b/src/smallestai/atoms/crew/__init__.py index d0c52f54..fbd176f0 100644 --- a/src/smallestai/atoms/crew/__init__.py +++ b/src/smallestai/atoms/crew/__init__.py @@ -32,11 +32,13 @@ __all__ = list(_LAZY_EXPORTS.keys()) if TYPE_CHECKING: - from smallestai.atoms.crew.clients.openai import OpenAIClient - from smallestai.atoms.crew.nodes import BackgroundCrewNode, OutputCrewNode - from smallestai.atoms.crew.server import AtomsCrewApp - from smallestai.atoms.crew.session import CrewSession - from smallestai.atoms.crew.tools import ToolRegistry, function_tool + from smallestai.atoms.crew.clients.openai import OpenAIClient as OpenAIClient + from smallestai.atoms.crew.nodes import BackgroundCrewNode as BackgroundCrewNode + from smallestai.atoms.crew.nodes import OutputCrewNode as OutputCrewNode + from smallestai.atoms.crew.server import AtomsCrewApp as AtomsCrewApp + from smallestai.atoms.crew.session import CrewSession as CrewSession + from smallestai.atoms.crew.tools import ToolRegistry as ToolRegistry + from smallestai.atoms.crew.tools import function_tool as function_tool def __getattr__(name: str): From aa090b6cb002c1bb09ffcb44c5f7d2178314004b Mon Sep 17 00:00:00 2001 From: Abhishek Mishra Date: Wed, 16 Sep 2026 01:16:43 +0530 Subject: [PATCH 3/3] test(crew): lock the documented public import surface (regression guard) Executes 'from smallestai.atoms.crew import AtomsCrewApp, CrewSession, ...' so the exact ImportError a customer hit can't silently come back. Lives in tests/custom (fernignored), runs in the SDK test CI. --- tests/custom/test_public_imports.py | 57 +++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/custom/test_public_imports.py diff --git a/tests/custom/test_public_imports.py b/tests/custom/test_public_imports.py new file mode 100644 index 00000000..2e46aeb6 --- /dev/null +++ b/tests/custom/test_public_imports.py @@ -0,0 +1,57 @@ +"""Guards the documented public import surface of `smallestai.atoms.crew`. + +A customer hit `ImportError` on `from smallestai.atoms.crew import AtomsCrewApp` +because `crew/__init__` exported nothing (the imports there lived only in the +docstring). Both the module docstring and the docs advertise this short path, so +lock it here: if the package stops exporting a public symbol, this test fails in +CI rather than in a customer's notebook. +""" + +import importlib + +CREW_PUBLIC = [ + "AtomsCrewApp", + "CrewSession", + "OutputCrewNode", + "BackgroundCrewNode", + "OpenAIClient", + "function_tool", + "ToolRegistry", +] + + +def test_crew_all_advertises_public_api(): + mod = importlib.import_module("smallestai.atoms.crew") + assert set(CREW_PUBLIC) <= set(mod.__all__) + + +def test_crew_public_symbols_resolve_from_short_path(): + from smallestai.atoms.crew import ( # noqa: F401 + AtomsCrewApp, + BackgroundCrewNode, + CrewSession, + OpenAIClient, + OutputCrewNode, + ToolRegistry, + function_tool, + ) + + for sym in ( + AtomsCrewApp, + CrewSession, + OutputCrewNode, + BackgroundCrewNode, + OpenAIClient, + ToolRegistry, + function_tool, + ): + assert sym is not None + + +def test_unknown_attr_raises_attributeerror(): + mod = importlib.import_module("smallestai.atoms.crew") + try: + mod.DefinitelyNotAThing + except AttributeError: + return + raise AssertionError("expected AttributeError for an unknown attribute")