diff --git a/libs/code/deepagents_code/app.py b/libs/code/deepagents_code/app.py index a8e926af4e..8a70c1abf9 100644 --- a/libs/code/deepagents_code/app.py +++ b/libs/code/deepagents_code/app.py @@ -1163,6 +1163,7 @@ def reset_thread(self) -> str: _SANDBOX_DISPLAY_NAMES: dict[str, str] = { "agentcore": "AgentCore", "daytona": "Daytona", + "e2b": "E2B", "langsmith": "LangSmith", "modal": "Modal", "runloop": "Runloop", diff --git a/libs/code/deepagents_code/extras_info.py b/libs/code/deepagents_code/extras_info.py index 0767e1dce1..8f2cd6c5c7 100644 --- a/libs/code/deepagents_code/extras_info.py +++ b/libs/code/deepagents_code/extras_info.py @@ -66,7 +66,9 @@ class ExtrasIntrospectionError(RuntimeError): Keep in sync with `[project.optional-dependencies]` in `pyproject.toml`. """ -SANDBOX_EXTRAS: frozenset[str] = frozenset({"agentcore", "daytona", "modal", "runloop"}) +SANDBOX_EXTRAS: frozenset[str] = frozenset( + {"agentcore", "daytona", "e2b", "modal", "runloop"} +) """Optional extras that add sandbox integrations.""" STANDALONE_EXTRAS: frozenset[str] = frozenset({"quickjs"}) diff --git a/libs/code/deepagents_code/integrations/sandbox_factory.py b/libs/code/deepagents_code/integrations/sandbox_factory.py index 318a8a7e96..93a1ce5b22 100644 --- a/libs/code/deepagents_code/integrations/sandbox_factory.py +++ b/libs/code/deepagents_code/integrations/sandbox_factory.py @@ -73,6 +73,7 @@ def _run_sandbox_setup(backend: SandboxBackendProtocol, setup_script_path: str) _PROVIDER_TO_WORKING_DIR = { "agentcore": "/tmp", # noqa: S108 # AgentCore Code Interpreter working directory "daytona": "/home/daytona", + "e2b": "/home/user", "langsmith": "/root", # `$HOME` in the LangSmith sandbox "modal": "/workspace", "runloop": "/home/user", @@ -94,8 +95,8 @@ def create_sandbox( provider abstraction. Args: - provider: Sandbox provider (`'agentcore'`, `'daytona'`, `'langsmith'`, - `'modal'`, `'runloop'`) + provider: Sandbox provider (`'agentcore'`, `'daytona'`, `'e2b'`, + `'langsmith'`, `'modal'`, `'runloop'`) sandbox_id: Optional existing sandbox ID to reuse snapshot_name: Optional sandbox snapshot name to use or create. Honored by `'langsmith'` (snapshot) and `'runloop'` (blueprint); @@ -179,8 +180,8 @@ def get_default_working_dir(provider: str) -> str: """Get the default working directory for a given sandbox provider. Args: - provider: Sandbox provider name (`'agentcore'`, `'daytona'`, `'langsmith'`, - `'modal'`, `'runloop'`) + provider: Sandbox provider name (`'agentcore'`, `'daytona'`, `'e2b'`, + `'langsmith'`, `'modal'`, `'runloop'`) Returns: Default working directory path as string @@ -698,6 +699,78 @@ def delete(self, *, sandbox_id: str, **kwargs: Any) -> None: # noqa: ARG002 self._provider.delete(sandbox_id=sandbox_id) +class _E2BProvider(SandboxProvider): + """E2B sandbox provider — delegates to `langchain_e2b.E2BProvider`.""" + + def __init__(self) -> None: + e2b_module = _import_provider_module( + "langchain_e2b", + provider="e2b", + package="langchain-e2b", + ) + + from deepagents_code.model_config import resolve_env_var + + api_key = resolve_env_var("E2B_API_KEY") + if not api_key: + msg = ( + "No E2B API key found. Set E2B_API_KEY or DEEPAGENTS_CODE_E2B_API_KEY." + ) + raise ValueError(msg) + try: + provider = e2b_module.E2BProvider + except AttributeError as exc: + msg = ( + "The 'e2b' sandbox provider requires langchain-e2b>=0.0.2. " + "Upgrade with `pip install -U langchain-e2b`." + ) + raise ImportError(msg) from exc + self._provider = provider( + api_key=api_key, + resolve_env_var=resolve_env_var, + ) + + def get_or_create( + self, + *, + sandbox_id: str | None = None, + timeout: int = 180, + **kwargs: Any, + ) -> SandboxBackendProtocol: + """Get or create an E2B sandbox. + + Args: + sandbox_id: Existing sandbox ID, or None to create. + timeout: Accepted for parity with other providers and forwarded to + `langchain_e2b.E2BProvider`. + **kwargs: E2B provider options. + + Returns: + `E2BSandbox` instance. + + Raises: + SandboxNotFoundError: If `sandbox_id` does not exist. `E2BProvider` + translates the SDK's not-found error into a `KeyError`, which is + mapped here. + KeyError: If a `KeyError` is raised while no `sandbox_id` was supplied + (re-raised unchanged rather than mislabeled as not-found). + """ + try: + return self._provider.get_or_create( + sandbox_id=sandbox_id, + timeout=timeout, + **kwargs, + ) + except KeyError as e: + if sandbox_id is None: + raise + raise SandboxNotFoundError(sandbox_id) from e + + def delete(self, *, sandbox_id: str, **kwargs: Any) -> None: # noqa: ARG002 + """Shut down an E2B sandbox by id.""" + self._provider.delete(sandbox_id=sandbox_id) + + class _AgentCoreProvider(SandboxProvider): """AgentCore Code Interpreter sandbox provider. @@ -829,8 +902,8 @@ def _get_provider(provider_name: str) -> SandboxProvider: """Get a `SandboxProvider` instance for the specified provider (internal). Args: - provider_name: Name of the provider (`'agentcore'`, `'daytona'`, `'langsmith'`, - `'modal'`, `'runloop'`) + provider_name: Name of the provider (`'agentcore'`, `'daytona'`, `'e2b'`, + `'langsmith'`, `'modal'`, `'runloop'`) Returns: `SandboxProvider` instance @@ -842,6 +915,8 @@ def _get_provider(provider_name: str) -> SandboxProvider: return _AgentCoreProvider() if provider_name == "daytona": return _DaytonaProvider() + if provider_name == "e2b": + return _E2BProvider() if provider_name == "langsmith": return _LangSmithProvider() if provider_name == "modal": @@ -878,6 +953,7 @@ def verify_sandbox_deps(provider: str) -> None: backend_modules: dict[str, tuple[str, str]] = { "agentcore": ("langchain_agentcore_codeinterpreter", "agentcore"), "daytona": ("langchain_daytona", "daytona"), + "e2b": ("langchain_e2b", "e2b"), "modal": ("langchain_modal", "modal"), "runloop": ("langchain_runloop", "runloop"), } diff --git a/libs/code/deepagents_code/main.py b/libs/code/deepagents_code/main.py index 84b32ff509..4480013aa9 100644 --- a/libs/code/deepagents_code/main.py +++ b/libs/code/deepagents_code/main.py @@ -1023,13 +1023,21 @@ def help_parent(help_fn: Callable[[], None]) -> list[argparse.ArgumentParser]: parser.add_argument( "--sandbox", - choices=["none", "agentcore", "modal", "daytona", "runloop", "langsmith"], + choices=[ + "none", + "agentcore", + "modal", + "daytona", + "e2b", + "runloop", + "langsmith", + ], default="none", metavar="TYPE", help=( "Remote sandbox for code execution " "(default: none - local only; langsmith is included, " - "agentcore/modal/daytona/runloop require downloading extras)" + "agentcore/modal/daytona/e2b/runloop require downloading extras)" ), ) @@ -1205,7 +1213,8 @@ async def run_textual_cli_async( assistant_id: Agent identifier for memory storage auto_approve: Whether to auto-approve tool usage sandbox_type: Type of sandbox - ("none", "agentcore", "modal", "runloop", "daytona", "langsmith") + ("none", "agentcore", "modal", "runloop", "daytona", "e2b", + "langsmith") sandbox_id: Optional existing sandbox ID to reuse. sandbox_snapshot_name: Snapshot (langsmith) or blueprint (runloop) name. sandbox_setup: Optional path to setup script to run in the sandbox diff --git a/libs/code/pyproject.toml b/libs/code/pyproject.toml index d7ac0b6347..cb71d2436f 100644 --- a/libs/code/pyproject.toml +++ b/libs/code/pyproject.toml @@ -109,10 +109,11 @@ all-providers = [ # Sandbox providers agentcore = ["langchain-agentcore-codeinterpreter>=0.0.3,<1.0.0"] daytona = ["langchain-daytona>=0.0.6"] +e2b = ["langchain-e2b>=0.0.2"] modal = ["langchain-modal>=0.0.4"] runloop = ["langchain-runloop>=0.0.6"] all-sandboxes = [ - "deepagents-code[agentcore,daytona,modal,runloop]", + "deepagents-code[agentcore,daytona,e2b,modal,runloop]", ] # Standalone integrations (not part of any composite extra) diff --git a/libs/code/tests/unit_tests/test_app.py b/libs/code/tests/unit_tests/test_app.py index 7326bb5e6b..7f8331903d 100644 --- a/libs/code/tests/unit_tests/test_app.py +++ b/libs/code/tests/unit_tests/test_app.py @@ -9167,6 +9167,9 @@ async def test_sandbox_sub_title_proper_casing(self) -> None: app2 = DeepAgentsApp(server_kwargs={"sandbox_type": "agentcore"}) assert app2.sub_title == "Sandbox: AgentCore" + app3 = DeepAgentsApp(server_kwargs={"sandbox_type": "e2b"}) + assert app3.sub_title == "Sandbox: E2B" + async def test_explicit_sub_title_overrides_sandbox(self) -> None: """An explicitly passed sub_title is not overwritten by sandbox info.""" app = DeepAgentsApp(sub_title="custom", server_kwargs={"sandbox_type": "modal"}) diff --git a/libs/code/tests/unit_tests/test_install_command.py b/libs/code/tests/unit_tests/test_install_command.py index dbeeda5865..ae46a74ede 100644 --- a/libs/code/tests/unit_tests/test_install_command.py +++ b/libs/code/tests/unit_tests/test_install_command.py @@ -31,6 +31,7 @@ async def test_install_slash_usage_when_no_extra() -> None: assert "Available extras:" in rendered assert "quickjs" in rendered assert "daytona" in rendered + assert "e2b" in rendered assert "openai" in rendered diff --git a/libs/code/tests/unit_tests/test_launch_init.py b/libs/code/tests/unit_tests/test_launch_init.py index 4d5199b1c3..59b131681a 100644 --- a/libs/code/tests/unit_tests/test_launch_init.py +++ b/libs/code/tests/unit_tests/test_launch_init.py @@ -170,6 +170,11 @@ class TestLaunchDependenciesScreen: installed=(("langchain-daytona", "0.0.5"),), missing=(), ), + ExtraDependencyStatus( + name="e2b", + installed=(), + missing=("langchain-e2b",), + ), ExtraDependencyStatus( name="runloop", installed=(), @@ -194,7 +199,7 @@ async def test_renders_installed_and_available_extras(self) -> None: assert "Sandboxes: daytona" in content assert "Available to add" in content assert "Model providers: bedrock" in content - assert "Sandboxes: runloop" in content + assert "Sandboxes: e2b, runloop" in content assert "Esc skip setup" in content async def test_enter_continues(self) -> None: diff --git a/libs/code/tests/unit_tests/test_sandbox_factory.py b/libs/code/tests/unit_tests/test_sandbox_factory.py index 6171838a1e..33754e6035 100644 --- a/libs/code/tests/unit_tests/test_sandbox_factory.py +++ b/libs/code/tests/unit_tests/test_sandbox_factory.py @@ -4,6 +4,7 @@ import os import sys +from types import SimpleNamespace from unittest.mock import MagicMock, patch import pytest @@ -14,12 +15,14 @@ get_default_working_dir, verify_sandbox_deps, ) +from deepagents_code.integrations.sandbox_provider import SandboxNotFoundError @pytest.mark.parametrize( ("provider", "package"), [ ("daytona", "langchain-daytona"), + ("e2b", "langchain-e2b"), ("modal", "langchain-modal"), ("runloop", "langchain-runloop"), ], @@ -432,11 +435,133 @@ def test_agentcore_delete_untracked_session() -> None: provider.delete(sandbox_id="nonexistent") # should not raise +def test_e2b_raises_on_missing_api_key(monkeypatch: pytest.MonkeyPatch) -> None: + """E2B should raise a helpful error without credentials.""" + monkeypatch.delenv("E2B_API_KEY", raising=False) + monkeypatch.delenv("DEEPAGENTS_CODE_E2B_API_KEY", raising=False) + with ( + patch( + "deepagents_code.integrations.sandbox_factory._import_provider_module", + return_value=MagicMock(), + ), + pytest.raises(ValueError, match="No E2B API key found"), + ): + _get_provider("e2b") + + +def test_e2b_provider_delegates_to_langchain_e2b( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """E2B lifecycle should live in `langchain_e2b.E2BProvider`.""" + monkeypatch.setenv("E2B_API_KEY", "fake-key") + backend = MagicMock(id="sbx-e2b") + fake_provider = MagicMock() + fake_provider.get_or_create.return_value = backend + fake_module = MagicMock() + fake_module.E2BProvider.return_value = fake_provider + + with patch( + "deepagents_code.integrations.sandbox_factory._import_provider_module", + return_value=fake_module, + ): + provider = _get_provider("e2b") + result = provider.get_or_create(timeout=2, metadata={"purpose": "test"}) + provider.delete(sandbox_id="sbx-e2b") + + fake_module.E2BProvider.assert_called_once() + provider_kwargs = fake_module.E2BProvider.call_args.kwargs + assert provider_kwargs["api_key"] == "fake-key" + assert callable(provider_kwargs["resolve_env_var"]) + fake_provider.get_or_create.assert_called_once_with( + sandbox_id=None, + timeout=2, + metadata={"purpose": "test"}, + ) + fake_provider.delete.assert_called_once_with(sandbox_id="sbx-e2b") + assert result is backend + + +def test_e2b_provider_uses_deepagents_prefixed_api_key( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Deep Agents still owns its `DEEPAGENTS_CODE_` env fallback.""" + monkeypatch.delenv("E2B_API_KEY", raising=False) + monkeypatch.setenv("DEEPAGENTS_CODE_E2B_API_KEY", "prefixed-key") + fake_module = MagicMock() + + with patch( + "deepagents_code.integrations.sandbox_factory._import_provider_module", + return_value=fake_module, + ): + _get_provider("e2b") + + assert fake_module.E2BProvider.call_args.kwargs["api_key"] == "prefixed-key" + + +def test_e2b_provider_requires_provider_class( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Older `langchain-e2b` versions should raise an actionable error.""" + monkeypatch.setenv("E2B_API_KEY", "fake-key") + + with ( + patch( + "deepagents_code.integrations.sandbox_factory._import_provider_module", + return_value=SimpleNamespace(), + ), + pytest.raises(ImportError, match=r"langchain-e2b>=0\.0\.2"), + ): + _get_provider("e2b") + + +def test_e2b_connect_not_found_raises_sandbox_not_found( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """E2B provider `KeyError` should normalize to `SandboxNotFoundError`.""" + monkeypatch.setenv("E2B_API_KEY", "fake-key") + + fake_provider = MagicMock() + fake_provider.get_or_create.side_effect = KeyError("sbx-missing") + fake_module = MagicMock() + fake_module.E2BProvider.return_value = fake_provider + + with patch( + "deepagents_code.integrations.sandbox_factory._import_provider_module", + return_value=fake_module, + ): + provider = _get_provider("e2b") + + with pytest.raises(SandboxNotFoundError, match="sbx-missing"): + provider.get_or_create(sandbox_id="sbx-missing") + + +def test_e2b_keyerror_without_sandbox_id_is_not_reclassified( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Unexpected provider `KeyError`s should propagate unchanged.""" + monkeypatch.setenv("E2B_API_KEY", "fake-key") + + fake_provider = MagicMock() + fake_provider.get_or_create.side_effect = KeyError("unexpected") + fake_module = MagicMock() + fake_module.E2BProvider.return_value = fake_provider + + with patch( + "deepagents_code.integrations.sandbox_factory._import_provider_module", + return_value=fake_module, + ): + provider = _get_provider("e2b") + + with pytest.raises(KeyError): + provider.get_or_create(sandbox_id=None) + + @pytest.mark.parametrize( ("provider", "expected"), [ ("agentcore", "/tmp"), ("daytona", "/home/daytona"), + ("e2b", "/home/user"), ("langsmith", "/root"), ("modal", "/workspace"), ("runloop", "/home/user"), @@ -455,6 +580,7 @@ class TestVerifySandboxDeps: [ ("agentcore", "langchain_agentcore_codeinterpreter"), ("daytona", "langchain_daytona"), + ("e2b", "langchain_e2b"), ("modal", "langchain_modal"), ("runloop", "langchain_runloop"), ], @@ -481,7 +607,7 @@ def test_raises_import_error_when_backend_missing( @pytest.mark.parametrize( "provider", - ["agentcore", "daytona", "modal", "runloop"], + ["agentcore", "daytona", "e2b", "modal", "runloop"], ) def test_passes_when_backend_installed(self, provider: str) -> None: """Should not raise when the backend module is found.""" diff --git a/libs/code/uv.lock b/libs/code/uv.lock index 3d3d4b6fe6..bdd93401b1 100644 --- a/libs/code/uv.lock +++ b/libs/code/uv.lock @@ -1094,6 +1094,7 @@ all-providers = [ all-sandboxes = [ { name = "langchain-agentcore-codeinterpreter" }, { name = "langchain-daytona" }, + { name = "langchain-e2b" }, { name = "langchain-modal" }, { name = "langchain-runloop" }, ] @@ -1115,6 +1116,9 @@ daytona = [ deepseek = [ { name = "langchain-deepseek" }, ] +e2b = [ + { name = "langchain-e2b" }, +] fireworks = [ { name = "langchain-fireworks" }, ] @@ -1196,7 +1200,7 @@ requires-dist = [ { name = "aiosqlite", specifier = ">=0.22.1,<1.0.0" }, { name = "deepagents", editable = "../deepagents" }, { name = "deepagents-acp", specifier = ">=0.0.8,<1.0.0" }, - { name = "deepagents-code", extras = ["agentcore", "daytona", "modal", "runloop"], marker = "extra == 'all-sandboxes'" }, + { name = "deepagents-code", extras = ["agentcore", "daytona", "e2b", "modal", "runloop"], marker = "extra == 'all-sandboxes'" }, { name = "deepagents-code", extras = ["anthropic", "baseten", "bedrock", "cohere", "deepseek", "fireworks", "google-genai", "groq", "huggingface", "ibm", "litellm", "mistralai", "nvidia", "ollama", "openai", "openrouter", "perplexity", "together", "vertex", "xai"], marker = "extra == 'all-providers'" }, { name = "httpx", specifier = ">=0.28.1,<1.0.0" }, { name = "langchain", specifier = ">=1.3.4,<2.0.0" }, @@ -1208,6 +1212,7 @@ requires-dist = [ { name = "langchain-cohere", marker = "extra == 'cohere'", specifier = ">=0.6.0,<1.0.0" }, { name = "langchain-daytona", marker = "extra == 'daytona'", editable = "../partners/daytona" }, { name = "langchain-deepseek", marker = "extra == 'deepseek'", specifier = ">=1.0.1,<2.0.0" }, + { name = "langchain-e2b", marker = "extra == 'e2b'", specifier = ">=0.0.2" }, { name = "langchain-fireworks", marker = "extra == 'fireworks'", specifier = ">=1.4.2,<2.0.0" }, { name = "langchain-google-genai", specifier = ">=4.2.4,<5.0.0" }, { name = "langchain-google-genai", marker = "extra == 'google-genai'", specifier = ">=4.2.4,<5.0.0" }, @@ -1250,7 +1255,7 @@ requires-dist = [ { name = "tomli-w", specifier = ">=1.2.0,<2.0.0" }, { name = "uuid-utils", specifier = ">=0.16.0,<1.0.0" }, ] -provides-extras = ["anthropic", "baseten", "bedrock", "cohere", "deepseek", "fireworks", "google-genai", "groq", "huggingface", "ibm", "litellm", "mistralai", "nvidia", "ollama", "openai", "openrouter", "perplexity", "together", "vertex", "xai", "all-providers", "agentcore", "daytona", "modal", "runloop", "all-sandboxes", "quickjs"] +provides-extras = ["anthropic", "baseten", "bedrock", "cohere", "deepseek", "fireworks", "google-genai", "groq", "huggingface", "ibm", "litellm", "mistralai", "nvidia", "ollama", "openai", "openrouter", "perplexity", "together", "vertex", "xai", "all-providers", "agentcore", "daytona", "e2b", "modal", "runloop", "all-sandboxes", "quickjs"] [package.metadata.requires-dev] test = [ @@ -1294,6 +1299,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] +[[package]] +name = "dockerfile-parse" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/92/df/929ee0b5d2c8bd8d713c45e71b94ab57c7e11e322130724d54f469b2cd48/dockerfile-parse-2.0.1.tar.gz", hash = "sha256:3184ccdc513221983e503ac00e1aa504a2aa8f84e5de673c46b0b6eee99ec7bc", size = 24556, upload-time = "2023-07-18T13:36:07.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/6c/79cd5bc1b880d8c1a9a5550aa8dacd57353fa3bb2457227e1fb47383eb49/dockerfile_parse-2.0.1-py2.py3-none-any.whl", hash = "sha256:bdffd126d2eb26acf1066acb54cb2e336682e1d72b974a40894fac76a4df17f6", size = 14845, upload-time = "2023-07-18T13:36:06.052Z" }, +] + [[package]] name = "docstring-parser" version = "0.17.0" @@ -1312,6 +1326,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" }, ] +[[package]] +name = "e2b" +version = "2.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "dockerfile-parse" }, + { name = "h2" }, + { name = "httpcore" }, + { name = "httpx" }, + { name = "packaging" }, + { name = "protobuf" }, + { name = "python-dateutil" }, + { name = "rich" }, + { name = "typing-extensions" }, + { name = "wcmatch" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/07/97604da2a7b7db68b970bab60d1bbffa436e73492c000d1889daf6283cf6/e2b-2.25.1.tar.gz", hash = "sha256:b87f8da3bbcce613e1bef9a90c46ef042a053f3f311b5ab45fcff5bdf1b1b425", size = 163032, upload-time = "2026-05-29T23:45:55.756Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/d5/d04b038ffb56ff6ba76cf6c2438908336aa58a5eb405b2fa191d398106c5/e2b-2.25.1-py3-none-any.whl", hash = "sha256:5ea5d1766082c1db504f86ebe17abe8b6a07f33d8addfb1a7778fae4a9549891", size = 309607, upload-time = "2026-05-29T23:45:54.327Z" }, +] + [[package]] name = "environs" version = "14.5.0" @@ -2685,6 +2721,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cd/dd/a803dfbf64273232f3fc82f859487331abb717671bbcdf266fd80de6ef78/langchain_deepseek-1.0.1-py3-none-any.whl", hash = "sha256:0a9862f335f1873370bb0fe1928ac19b8b9292b014ef5412da462ded8bb82c5a", size = 8325, upload-time = "2025-11-13T16:29:12.385Z" }, ] +[[package]] +name = "langchain-e2b" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "deepagents" }, + { name = "e2b" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/78/dc4c8434745ef3421eb39a3197ddbf59aeaeda5281ce8d9c973d19387546/langchain_e2b-0.0.2.tar.gz", hash = "sha256:a65dd44c2750fff04a62414b95e1c7af843a3ca643b10d66646339dee2fca176", size = 122000, upload-time = "2026-06-10T17:21:50.503Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/28/2030b7f2585af022a04e51fc69477732e51f2681db88b0ec99ee03469386/langchain_e2b-0.0.2-py3-none-any.whl", hash = "sha256:8972cd80e314941040c48a131ba1b6b161a16745108559b4114551f19f8c18fe", size = 6409, upload-time = "2026-06-10T17:21:49.365Z" }, +] + [[package]] name = "langchain-fireworks" version = "1.4.2" diff --git a/libs/evals/uv.lock b/libs/evals/uv.lock index 4fa1f214dc..08ae06326a 100644 --- a/libs/evals/uv.lock +++ b/libs/evals/uv.lock @@ -574,7 +574,7 @@ requires-dist = [ { name = "aiosqlite", specifier = ">=0.22.1,<1.0.0" }, { name = "deepagents", editable = "../deepagents" }, { name = "deepagents-acp", specifier = ">=0.0.8,<1.0.0" }, - { name = "deepagents-code", extras = ["agentcore", "daytona", "modal", "runloop"], marker = "extra == 'all-sandboxes'" }, + { name = "deepagents-code", extras = ["agentcore", "daytona", "e2b", "modal", "runloop"], marker = "extra == 'all-sandboxes'" }, { name = "deepagents-code", extras = ["anthropic", "baseten", "bedrock", "cohere", "deepseek", "fireworks", "google-genai", "groq", "huggingface", "ibm", "litellm", "mistralai", "nvidia", "ollama", "openai", "openrouter", "perplexity", "together", "vertex", "xai"], marker = "extra == 'all-providers'" }, { name = "httpx", specifier = ">=0.28.1,<1.0.0" }, { name = "langchain", specifier = ">=1.3.4,<2.0.0" }, @@ -586,6 +586,7 @@ requires-dist = [ { name = "langchain-cohere", marker = "extra == 'cohere'", specifier = ">=0.6.0,<1.0.0" }, { name = "langchain-daytona", marker = "extra == 'daytona'", editable = "../partners/daytona" }, { name = "langchain-deepseek", marker = "extra == 'deepseek'", specifier = ">=1.0.1,<2.0.0" }, + { name = "langchain-e2b", marker = "extra == 'e2b'", specifier = ">=0.0.2" }, { name = "langchain-fireworks", marker = "extra == 'fireworks'", specifier = ">=1.4.2,<2.0.0" }, { name = "langchain-google-genai", specifier = ">=4.2.4,<5.0.0" }, { name = "langchain-google-genai", marker = "extra == 'google-genai'", specifier = ">=4.2.4,<5.0.0" }, @@ -628,7 +629,7 @@ requires-dist = [ { name = "tomli-w", specifier = ">=1.2.0,<2.0.0" }, { name = "uuid-utils", specifier = ">=0.16.0,<1.0.0" }, ] -provides-extras = ["anthropic", "baseten", "bedrock", "cohere", "deepseek", "fireworks", "google-genai", "groq", "huggingface", "ibm", "litellm", "mistralai", "nvidia", "ollama", "openai", "openrouter", "perplexity", "together", "vertex", "xai", "all-providers", "agentcore", "daytona", "modal", "runloop", "all-sandboxes", "quickjs"] +provides-extras = ["anthropic", "baseten", "bedrock", "cohere", "deepseek", "fireworks", "google-genai", "groq", "huggingface", "ibm", "litellm", "mistralai", "nvidia", "ollama", "openai", "openrouter", "perplexity", "together", "vertex", "xai", "all-providers", "agentcore", "daytona", "e2b", "modal", "runloop", "all-sandboxes", "quickjs"] [package.metadata.requires-dev] test = [