Loader

Load an installed extension’s code into the running process.

Extensions are installed at run time, on a platform whose app, worker and beat processes run in many pods. The archive of each ExtensionVersion is stored in the database, so each process loads an extension the first time it needs it:

  1. Materialize: the archive is extracted to <tempdir>/smarter-extensions/<slug>/<version>-<sha256 prefix>/, once per pod. It is extracted to a temporary directory and renamed into place, so that two processes that extract it at the same time cannot see a partial copy.

  2. Import: the package is imported under a namespace that is unique to the version and its contents, smarter_extensions.<slug>.v<version>_<sha256 prefix>.<package>. An update imports the new version beside the old one, rather than reloading modules, which Python does not do reliably: a tool call that is running finishes on the old code. Old modules stay in memory until the process restarts.

An extension’s own modules must import each other with relative imports (from .models import WeatherArguments), because the package is not on sys.path.

class smarter.apps.llmtool.extension.loader.LoadedExtension(slug, version, sha256, manifest, module_name, path, tools=<factory>, lifecycle=None)[source]

Bases: object

An extension version whose code is imported into this process.

Parameters:
__init__(slug, version, sha256, manifest, module_name, path, tools=<factory>, lifecycle=None)
entry_point(entry)[source]

Return the object that an entry point, <module>:<attribute>, names.

Parameters:

entry (str) – e.g. weather.tools:GetWeather.

Return type:

object

lifecycle: type[SmarterExtensionLifecycle] | None = None
manifest: ExtensionManifest
module_name: str
path: Path
sha256: str
slug: str
tools: dict[str, type[SmarterExtensionTool]]
version: str
smarter.apps.llmtool.extension.loader.extensions_root()[source]

The directory into which extension archives are extracted.

Return type:

Path

smarter.apps.llmtool.extension.loader.load_archive(archive)[source]

Import an extension archive’s code into this process, and find its tools and lifecycle hooks.

Loading the same archive again returns the extension that is already loaded.

Parameters:

archive (ExtensionArchive) – The archive.

Return type:

LoadedExtension

Returns:

The loaded extension.

Raises:

SmarterExtensionLoadError – If the code cannot be imported, or its tools are not valid.

smarter.apps.llmtool.extension.loader.load_version(version)[source]

Import an installed extension version’s code into this process.

The archive is read from the database only the first time a process loads the version.

Parameters:

version (ExtensionVersion) – The installed version.

Return type:

LoadedExtension

Returns:

The loaded extension.

Raises:

SmarterExtensionLoadError – If the code cannot be imported, or its tools are not valid.

smarter.apps.llmtool.extension.loader.materialize(archive)[source]

Extract an archive into this pod’s extensions directory, unless it is already there.

Parameters:

archive (ExtensionArchive) – The archive.

Return type:

Path

Returns:

The directory that holds the archive’s files.

smarter.apps.llmtool.extension.loader.module_name_for(manifest, sha256)[source]

Return the full name under which an extension version’s package is imported.

Parameters:
  • manifest (ExtensionManifest) – The version’s manifest.

  • sha256 (str) – The sha256 of its archive.

Return type:

str

Returns:

e.g. smarter_extensions.weather.v1_2_0_0123456789ab.weather.

smarter.apps.llmtool.extension.loader.unload(slug)[source]

Forget every loaded version of an extension, e.g. after it is uninstalled.

The modules stay in sys.modules, so a tool call that is running is not affected.

Parameters:

slug (str) – The extension’s slug.

Return type:

None