Skip to content

trading_agent.extensions.package_installer

Installs and removes packages: trading-agent packages install|remove.

Installing copies the package's folder into workspace/shared/packages//; the desks, the hook runner and the MCP manager read its parts from there. Before copying, the installer checks that the folder holds at least one package part and that its mcp_servers.json is valid, and scans its text files for prompt injection. A package whose name is already installed is kept unless replacing is asked for.

Typical usage example:

report = PackageInstaller(packages).install('https://github.com/someone/news-pack.git', replace=False)

PackageError

Bases: RuntimeError

A package could not be installed or removed, with the reason.

InstallReport dataclass

InstallReport(summary, replaced, warnings)

What one install did.

Attributes:

Name Type Description
summary PackageSummary

The installed package's contents.

replaced bool

Whether an installed package of the same name was replaced.

warnings tuple[str, ...]

Passages that look like prompt injection, and hook files that cannot run.

PackageInstaller

PackageInstaller(packages)

Installs packages into the packages folder.

Creates the installer.

Parameters:

Name Type Description Default
packages InstalledPackages

The installed packages.

required
Source code in src/trading_agent/extensions/package_installer.py
def __init__(self, packages: installed_packages_module.InstalledPackages):
    """Creates the installer.

    Args:
        packages (installed_packages_module.InstalledPackages): The installed packages.
    """
    self._packages = packages
    self._scanner = injection_scanner.InjectionScanner()

install

install(source, replace)

Installs a package from a folder, a zip file or a git URL.

Parameters:

Name Type Description Default
source str

The package.

required
replace bool

Whether to replace an installed package of the same name.

required

Returns:

Type Description
InstallReport

What was installed.

Raises:

Type Description
PackageError

The source cannot be fetched, holds no package part, has an invalid name or mcp_servers.json, or is already installed.

Source code in src/trading_agent/extensions/package_installer.py
def install(self, source: str, replace: bool) -> InstallReport:
    """Installs a package from a folder, a zip file or a git URL.

    Args:
        source (str): The package.
        replace (bool): Whether to replace an installed package of the same name.

    Returns:
        InstallReport: What was installed.

    Raises:
        PackageError: The source cannot be fetched, holds no package part, has an invalid name or mcp_servers.json, or is already installed.
    """
    with tempfile.TemporaryDirectory(prefix='package-install-') as scratch:
        try:
            folder = source_fetcher.SourceFetcher().local_folder(
                source,
                Path(scratch),
            )
        except source_fetcher.SourceError as error:
            raise PackageError(str(error)) from error
        name = self._name(folder, source)
        self._check_contents(folder)
        target = self._packages.packages_directory / name
        replaced = False
        if target.exists():
            if not replace:
                raise PackageError(
                    f'A package named {name} is installed; use --replace to replace it.'
                )
            shutil.rmtree(target)
            replaced = True
        self._packages.packages_directory.mkdir(parents=True, exist_ok=True)
        shutil.copytree(
            folder,
            target,
            ignore=shutil.ignore_patterns('.git'),
        )
    return InstallReport(
        summary=self._packages.summary(target),
        replaced=replaced,
        warnings=tuple(self._warnings(target)),
    )

remove

remove(name)

Deletes an installed package's folder.

Parameters:

Name Type Description Default
name str

The package's name.

required

Returns:

Type Description
Path

The folder that was deleted.

Raises:

Type Description
PackageError

No package of that name is installed.

Source code in src/trading_agent/extensions/package_installer.py
def remove(self, name: str) -> Path:
    """Deletes an installed package's folder.

    Args:
        name (str): The package's name.

    Returns:
        Path: The folder that was deleted.

    Raises:
        PackageError: No package of that name is installed.
    """
    target = self._packages.packages_directory / name
    if not _NAME_PATTERN.match(name) or not target.is_dir():
        raise PackageError(f'No package named {name} is installed.')
    shutil.rmtree(target)
    return target