Skip to content

Commit 8eeb8e5

Browse files
committed
feat: bump langgraph dependency to >=v1.0.2 with fixed ExecutorToolNode
1 parent 122a0c9 commit 8eeb8e5

File tree

4 files changed

+1975
-1492
lines changed

4 files changed

+1975
-1492
lines changed

minitap/mobile_use/agents/executor/tool_node.py

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from langchain_core.messages import AnyMessage, ToolCall, ToolMessage
66
from langchain_core.runnables import RunnableConfig
77
from langgraph.prebuilt import ToolNode
8-
from langgraph.store.base import BaseStore
8+
from langgraph.prebuilt.tool_node import ToolRuntime
9+
from langgraph.runtime import Runtime
910
from langgraph.types import Command
1011
from pydantic import BaseModel
1112

@@ -30,46 +31,61 @@ async def _afunc(
3031
self,
3132
input: list[AnyMessage] | dict[str, Any] | BaseModel,
3233
config: RunnableConfig,
33-
*,
34-
store: BaseStore | None,
34+
runtime: Runtime,
3535
):
36-
return await self.__func(is_async=True, input=input, config=config, store=store)
36+
return await self.__func(is_async=True, input=input, config=config, runtime=runtime)
3737

3838
@override
3939
def _func(
4040
self,
4141
input: list[AnyMessage] | dict[str, Any] | BaseModel,
4242
config: RunnableConfig,
43-
*,
44-
store: BaseStore | None,
43+
runtime: Runtime,
4544
) -> Any:
4645
loop = asyncio.get_event_loop()
4746
return loop.run_until_complete(
48-
self.__func(is_async=False, input=input, config=config, store=store)
47+
self.__func(is_async=False, input=input, config=config, runtime=runtime)
48+
)
49+
50+
def _build_tool_runtime(
51+
self,
52+
call: ToolCall,
53+
input: list[AnyMessage] | dict[str, Any] | BaseModel,
54+
config: RunnableConfig,
55+
runtime: Runtime,
56+
) -> Any:
57+
state = self._extract_state(input)
58+
return ToolRuntime(
59+
state=state,
60+
tool_call_id=call["id"],
61+
config=config,
62+
context=runtime.context,
63+
store=runtime.store,
64+
stream_writer=runtime.stream_writer,
4965
)
5066

5167
async def __func(
5268
self,
5369
is_async: bool,
5470
input: list[AnyMessage] | dict[str, Any] | BaseModel,
5571
config: RunnableConfig,
56-
*,
57-
store: BaseStore | None,
72+
runtime: Runtime,
5873
) -> Any:
59-
tool_calls, input_type = self._parse_input(input, store)
74+
tool_calls, input_type = self._parse_input(input)
6075
outputs: list[Command | ToolMessage] = []
6176
failed = False
6277
for call in tool_calls:
78+
tool_runtime = self._build_tool_runtime(call, input, config, runtime)
6379
if failed:
6480
output = self._get_erroneous_command(
6581
call=call,
6682
message="Aborted: a previous tool call failed!",
6783
)
6884
else:
6985
if is_async:
70-
output = await self._arun_one(call, input_type, config)
86+
output = await self._arun_one(call, input_type, tool_runtime)
7187
else:
72-
output = self._run_one(call, input_type, config)
88+
output = self._run_one(call, input_type, tool_runtime)
7389
failed = self._has_tool_call_failed(call, output)
7490
if failed is None:
7591
output = self._get_erroneous_command(
@@ -133,11 +149,11 @@ def _get_erroneous_command(self, call: ToolCall, message: str) -> Command:
133149
tool_message = ToolMessage(
134150
name=call["name"], tool_call_id=call["id"], content=message, status="error"
135151
)
136-
return Command(update={self.messages_key: [tool_message]})
152+
return Command(update={self._messages_key: [tool_message]})
137153

138154
def _get_tool_message(self, cmd: Command) -> ToolMessage:
139155
if isinstance(cmd.update, dict):
140-
msg = cmd.update.get(self.messages_key)
156+
msg = cmd.update.get(self._messages_key)
141157
if isinstance(msg, list):
142158
if len(msg) == 0:
143159
raise ValueError("No messages found in command update")
@@ -147,6 +163,6 @@ def _get_tool_message(self, cmd: Command) -> ToolMessage:
147163
elif isinstance(msg, ToolMessage):
148164
return msg
149165
elif msg is None:
150-
raise ValueError(f"Missing '{self.messages_key}' in command update")
166+
raise ValueError(f"Missing '{self._messages_key}' in command update")
151167
raise ValueError(f"Unexpected message type in command update: {type(msg)}")
152168
raise ValueError("Command update is not a dict")

minitap/mobile_use/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import typer
88
from adbutils import AdbClient
9-
from langchain.callbacks.base import Callbacks
9+
from langchain_core.callbacks.base import Callbacks
1010
from rich.console import Console
1111

1212
from minitap.mobile_use.clients.ios_client_config import (

pyproject.toml

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "minitap-mobile-use"
3-
version = "3.5.7"
3+
version = "3.6.0"
44
description = "AI-powered multi-agent system that automates real Android and iOS devices through low-level control using LangGraph."
55
readme = "README.md"
66
license = { file = "LICENSE" }
@@ -14,25 +14,25 @@ authors = [
1414
requires-python = ">=3.12"
1515

1616
dependencies = [
17-
"langgraph>=1.0.0",
18-
"adbutils>=2.9.3",
19-
"langchain-google-genai>=2.1.10",
20-
"langchain>=0.3.27",
21-
"langchain-core>=0.3.75",
22-
"jinja2>=3.1.6",
23-
"python-dotenv>=1.1.1",
24-
"pydantic-settings>=2.10.1",
25-
"langchain-mcp-adapters>=0.1.7",
26-
"langchain-openai>=0.3.27",
27-
"typer>=0.16.0",
28-
"langchain-cerebras>=0.5.0",
17+
"langgraph>=1.0.2,<2.0.0",
18+
"adbutils==2.9.3",
19+
"langchain-google-genai>=4.0.0",
20+
"langchain>=1.0.0",
21+
"langchain-core>=1.0.0",
22+
"jinja2==3.1.6",
23+
"python-dotenv==1.1.1",
24+
"pydantic-settings==2.10.1",
25+
"langchain-mcp-adapters>=0.2.0",
26+
"langchain-openai>=1.0.0",
27+
"typer==0.16.0",
28+
"langchain-cerebras>=0.8.0",
2929
"inquirer>=3.4.0",
3030
"sseclient-py>=1.8.0",
3131
"fastapi>=0.111.0",
3232
"uvicorn[standard]>=0.30.1",
3333
"colorama>=0.4.6",
3434
"psutil>=5.9.0",
35-
"langchain-google-vertexai>=2.0.28",
35+
"langchain-google-vertexai>=3.0.0",
3636
"httpx>=0.28.1",
3737
"uiautomator2>=3.5.0",
3838
"fb-idb>=1.1.7",

0 commit comments

Comments
 (0)