Skip to content

Commit 26dd56c

Browse files
refactor(langchain): keep sandbox_client enhancements, remove thread manager
Thread-aware sandbox management (ThreadedSandboxManager, create_threaded_backend_factory, multi_thread_chat example) is application-specific and belongs in the consuming project, not in the generic agent-sandbox library. Retained in sandbox_client.py: claim_name, delete_on_exit, connect(), delete(), was_reconnected.
1 parent cf9ce3c commit 26dd56c

File tree

5 files changed

+0
-1313
lines changed

5 files changed

+0
-1313
lines changed

clients/python/langchain-agent-sandbox/langchain_agent_sandbox/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,11 @@
33
SandboxPolicyWrapper,
44
WarmPoolBackend,
55
create_sandbox_backend_factory,
6-
create_threaded_backend_factory,
76
)
8-
from .thread_manager import ThreadedSandboxManager
97

108
__all__ = [
119
"AgentSandboxBackend",
1210
"SandboxPolicyWrapper",
1311
"WarmPoolBackend",
14-
"ThreadedSandboxManager",
1512
"create_sandbox_backend_factory",
16-
"create_threaded_backend_factory",
1713
]

clients/python/langchain-agent-sandbox/langchain_agent_sandbox/backend.py

Lines changed: 0 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -669,97 +669,6 @@ def factory(_runtime: Any) -> AgentSandboxBackend:
669669
return factory
670670

671671

672-
def _get_thread_manager_class() -> type:
673-
"""Lazy import of ThreadedSandboxManager to avoid circular imports."""
674-
from .thread_manager import ThreadedSandboxManager
675-
return ThreadedSandboxManager
676-
677-
678-
def create_threaded_backend_factory(
679-
template_name: str,
680-
manager: Optional[Any] = None,
681-
namespace: str = "default",
682-
**kwargs: Any,
683-
) -> Callable[[Any], AgentSandboxBackend]:
684-
"""Create a BackendFactory that provides per-thread sandbox isolation.
685-
686-
This factory reads the thread_id from the LangGraph config and uses a
687-
ThreadedSandboxManager to provide isolated sandboxes per conversation thread.
688-
Each thread gets its own sandbox with persistent filesystem.
689-
690-
Usage:
691-
from deepagents import create_deep_agent
692-
from langgraph.checkpoint.memory import MemorySaver
693-
from langchain_agent_sandbox import (
694-
ThreadedSandboxManager,
695-
create_threaded_backend_factory,
696-
)
697-
698-
# Create manager for lifecycle control
699-
manager = ThreadedSandboxManager(
700-
template_name="python-deepagent",
701-
idle_ttl=timedelta(hours=1),
702-
)
703-
704-
# Create agent with threaded backend
705-
agent = create_deep_agent(
706-
model=model,
707-
backend=create_threaded_backend_factory("python-deepagent", manager=manager),
708-
checkpointer=MemorySaver(), # For message history
709-
)
710-
711-
# Same thread = same sandbox (filesystem persists)
712-
agent.invoke(msg1, config={"configurable": {"thread_id": "user-123"}})
713-
agent.invoke(msg2, config={"configurable": {"thread_id": "user-123"}})
714-
715-
# Different thread = different sandbox
716-
agent.invoke(msg3, config={"configurable": {"thread_id": "user-456"}})
717-
718-
# Cleanup when done
719-
manager.close()
720-
721-
Args:
722-
template_name: Name of the SandboxTemplate to claim.
723-
manager: Optional ThreadedSandboxManager instance. If not provided,
724-
one will be created (but you won't have lifecycle control).
725-
namespace: Kubernetes namespace for the sandbox.
726-
**kwargs: Additional arguments passed to ThreadedSandboxManager.
727-
728-
Returns:
729-
A factory callable that accepts a ToolRuntime and returns an
730-
AgentSandboxBackend for the current thread.
731-
732-
Note:
733-
The thread_id is read from `runtime.config.get("configurable", {}).get("thread_id")`.
734-
If no thread_id is found, a default "default-thread" is used.
735-
736-
Warning:
737-
If no manager is provided, an internal manager is created but you will
738-
have no way to call close() or delete_thread(). For production use,
739-
always pass an explicit manager instance for lifecycle control.
740-
"""
741-
# Create manager if not provided
742-
_manager = manager
743-
if _manager is None:
744-
ThreadedSandboxManager = _get_thread_manager_class()
745-
_manager = ThreadedSandboxManager(
746-
template_name=template_name,
747-
namespace=namespace,
748-
**kwargs,
749-
)
750-
751-
def factory(runtime: Any) -> AgentSandboxBackend:
752-
# Extract thread_id from LangGraph config
753-
config = getattr(runtime, "config", {}) or {}
754-
configurable = config.get("configurable", {}) or {}
755-
thread_id = configurable.get("thread_id", "default-thread")
756-
757-
logger.debug("Creating backend for thread_id: %s", thread_id)
758-
return _manager.get_backend(thread_id)
759-
760-
return factory
761-
762-
763672
class SandboxPolicyWrapper:
764673
"""Wraps AgentSandboxBackend with policy enforcement.
765674

0 commit comments

Comments
 (0)