Skip to content

langchain: ShellToolMiddleware breaks with HIL #33684

@ccurme

Description

@ccurme

Privileged issue

  • I am a LangChain maintainer, or was asked directly by a LangChain maintainer to create an issue here.

Issue Content

ShellToolMiddleware creates resources in the before_agent hook:

def before_agent(self, state: ShellToolState, runtime: Runtime) -> dict[str, Any] | None: # noqa: ARG002
"""Start the shell session and run startup commands."""
resources = self._create_resources()
return {"shell_session_resources": resources}

These resources are not checkpointed (they are annotated as UntrackedValue), so they are lost after execution is paused during human-in-the-loop workflows and we raise an error when resuming.

minimal example:

import os

from langchain.agents import create_agent
from langchain.agents.middleware import (
    HostExecutionPolicy,
    HumanInTheLoopMiddleware,
    ShellToolMiddleware,
)
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import Command


shell_middleware = ShellToolMiddleware(
    workspace_root=os.getcwd(),
    env=os.environ,  # danger
    execution_policy=HostExecutionPolicy()
)

hil_middleware = HumanInTheLoopMiddleware(interrupt_on={"shell": True})

checkpointer = InMemorySaver()

agent = create_agent(
    "openai:gpt-4.1-mini",
    middleware=[shell_middleware, hil_middleware],
    checkpointer=checkpointer,
)

input_message = {"role": "user", "content": "run `which python`"}

config = {"configurable": {"thread_id": "1"}}

result = agent.invoke(
    {"messages": [input_message]},
    config=config,
    durability="exit",
)

for message in result["messages"]:
    message.pretty_print()

print("\n--- interrupted ---\n")
for request in result["__interrupt__"][0].value["action_requests"]:
    print(request["description"])

next_result = agent.invoke(
    Command(resume={"decisions": [{"type": "approve"}]}),
    config=config,
    durability="exit",
)

for message in next_result["messages"]:
    message.pretty_print()

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions