Skip to content

Commit a289322

Browse files
author
lihao
committed
feat: Enhance Agent and Crew functionality with context management and execution plan support
- Added context management capabilities to the Agent class, allowing for dynamic context configuration. - Introduced ExecutionPlan class for managing multi-step workflows, including initialization and progress tracking. - Updated Crew class to synchronize message deletions in subgraphs and validate HITL configurations based on execution mode. - Enhanced various tools and message handling for improved integration and user notifications. - Added new dependencies in pyproject.toml for additional functionality.
1 parent 3293308 commit a289322

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+5899
-649
lines changed

examples/components/mcp/src/mcp/crew.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from langcrew.project import CrewBase, agent, crew, task
99

1010

11+
1112
@CrewBase
1213
class MapCrew:
1314
"""Map crew"""
@@ -31,7 +32,7 @@ def planner(self) -> Agent:
3132
return Agent(
3233
config=self.agents_config["planner"],
3334
mcp_servers=mcp_server_configs,
34-
mcp_tool_filter=["xxx"], # 只引入固定的tool
35+
mcp_tool_filter=["xxx"], #只引入固定的tool
3536
llm=self._get_default_llm(),
3637
verbose=True,
3738
)
@@ -82,7 +83,7 @@ def planner(self) -> Agent:
8283
"url": f"https://mcp.amap.com/mcp?key={os.getenv('AMAP_TOKEN')}",
8384
"transport": "streamable_http",
8485
}
85-
86+
8687
mcp_server_configs = {"amap-streamable_http": server_config}
8788
return Agent(
8889
config=self.agents_config["planner"],

examples/components/mcp/src/mcp/main.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,36 @@
77

88
load_dotenv(os.path.join(os.path.dirname(__file__), "..", "..", ".env.example"))
99

10-
1110
# sse use case
1211
async def map_sse_mcp():
13-
inputs = {"user_instruction": "Optimal route from Shanghai to Beijing"}
14-
crew = MapCrew().crew()
15-
result = await crew.akickoff(inputs=inputs)
12+
inputs = {
13+
"user_instruction": "Optimal route from Shanghai to Beijing"
14+
}
15+
crew = MapCrew().crew()
16+
result= await crew.akickoff(inputs=inputs)
1617
print(f"map result: {result}")
1718

18-
1919
# streamHttp use case
2020
async def map_streamHttp_mcp():
21-
inputs = {"user_instruction": "Optimal route from Shanghai to Beijing"}
22-
crew = MapStreamHttpCrew().crew()
23-
result = await crew.akickoff(inputs=inputs)
21+
inputs = {
22+
"user_instruction": "Optimal route from Shanghai to Beijing"
23+
}
24+
crew = MapStreamHttpCrew().crew()
25+
result= await crew.akickoff(inputs=inputs)
2426
print(f"map result: {result}")
2527

26-
2728
# stdio use case
2829
async def calculator_stdio_mcp():
2930
inputs = {
3031
"user_instruction": "Calculate 100+100 using tools, and explain which tool you used"
3132
}
32-
crew = CalculatorCrew().crew()
33-
result = await crew.akickoff(inputs=inputs)
33+
crew = CalculatorCrew().crew()
34+
result= await crew.akickoff(inputs=inputs)
3435
print(f"calculator result: {result}")
3536

3637

3738
if __name__ == "__main__":
3839
# asyncio.run(map_sse_mcp())
3940
# asyncio.run(map_streamHttp_mcp())
4041
asyncio.run(calculator_stdio_mcp())
42+

examples/components/mcp/src/mcp/tools/calculator_stdio.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
@mcp.tool()
99
def add(a: int, b: int) -> int:
10-
"""Add two numbers together"""
10+
"""Add two numbers together"""
1111
return a + b
1212

1313

@@ -33,4 +33,4 @@ def divide(a: float, b: float) -> float:
3333

3434
if __name__ == "__main__":
3535
# Start server using stdio transport
36-
mcp.run(transport="stdio")
36+
mcp.run(transport="stdio")

examples/components/web/super_agent/.env.example

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,9 @@ IN_DOCKER=true
3030
ANONYMIZED_TELEMETRY=false
3131
BROWSER_USE_LOGGING_LEVEL=debug
3232
BROWSER_USE_CLOUD_SYNC=false
33-
IS_IN_EVALS=true
33+
IS_IN_EVALS=true
34+
35+
# cloud phone
36+
AGENTBOX_API_KEY=
37+
AGENTBOX_TEMPLATE=
38+
AGENTBOX_TIMEOUT=1800

examples/components/web/super_agent/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ pnpm install
216216
pnpm dev
217217
```
218218

219-
Visit http://localhost:3000/chat for graphical interaction.
219+
Visit http://localhost:3600/chat for graphical interaction.
220220

221221
## Agent Capabilities
222222

examples/components/web/super_agent/compose-super-agent.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ services:
55
ports:
66
- "3600:3600"
77
volumes:
8-
- ./web:/app
8+
- ../../../../web:/app
99
- /app/node_modules
1010
- /app/.pnpm-store
1111
working_dir: /app
@@ -27,7 +27,7 @@ services:
2727
# Super Agent API service
2828
super-agent:
2929
build:
30-
context: .
30+
context: ../../../../
3131
dockerfile: examples/components/web/super_agent/Dockerfile
3232
ports:
3333
- "8000:8000"

examples/components/web/super_agent/pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ dependencies = [
3131
"tenacity>=8.2.0",
3232
# Browser automation
3333
"browser-use==0.5.5",
34+
"openai>=1.81.0,<1.82.0",
35+
"adb-shell>=0.4.4",
3436
]
3537

3638
[tool.uv.sources]
@@ -50,4 +52,4 @@ packages = ["src/super_agent"]
5052
requires = [
5153
"hatchling",
5254
]
53-
build-backend = "hatchling.build"
55+
build-backend = "hatchling.build"

examples/components/web/super_agent/src/super_agent/agent/crew.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
from langgraph.checkpoint.base import BaseCheckpointSaver
1616

1717
from super_agent.common.session_state import SessionState
18-
from super_agent.common.sandbox_config import create_sandbox_source_by_session_id
18+
from super_agent.common.sandbox_config import (
19+
create_cloud_phone_sandbox_by_session_id,
20+
create_sandbox_source_by_session_id,
21+
)
1922
from super_agent.config.config import SuperAgentConfig, default_config
2023
from langcrew_tools.utils.s3.factory import create_s3_client
2124
from langcrew_tools.hitl.langchain_tools import UserInputTool
@@ -30,6 +33,7 @@
3033
from langcrew_tools.image_gen import ImageGenerationTool
3134
from langcrew_tools.code_interpreter import CodeInterpreterTool
3235
from langcrew_tools.commands import RunCommandTool
36+
from super_agent.tool.cloud_phone_streaming_tool import CloudPhoneStreamingTool
3337

3438
logger = logging.getLogger(__name__)
3539

@@ -96,14 +100,19 @@ def get_llm_client(self) -> BaseChatModel:
96100
)
97101

98102
def get_tools(self) -> list[BaseTool]:
99-
"""Create browser tools"""
100103
# Web and search tools
101104
tools = [
102105
BrowserStreamingTool(
103106
vl_llm=self.get_browser_llm(),
104107
async_s3_client=self.async_s3_client,
105108
# sandbox_source=none_sandbox,
106109
),
110+
CloudPhoneStreamingTool(
111+
base_model=self.get_llm_client(),
112+
sandbox_source=create_cloud_phone_sandbox_by_session_id(
113+
self.session_id, checkpointer=self.checkpointer
114+
),
115+
),
107116
UserInputTool(),
108117
WebSearchTool(),
109118
WebFetchTool(),

examples/components/web/super_agent/src/super_agent/agent/enhanced_crew.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,29 @@ async def _aprocess_output(self, output: Any) -> Any:
186186
# Execute function callbacks
187187
for callback_fn in callback_copy:
188188
try:
189-
if inspect.iscoroutinefunction(callback_fn):
190-
prev_result = await callback_fn(prev_result)
191-
else:
192-
prev_result = callback_fn(prev_result)
189+
if prev_result:
190+
# Handle the case where prev_result might be a list
191+
if isinstance(prev_result, list):
192+
# Process each item in the list through the callback
193+
processed_items = []
194+
for item in prev_result:
195+
if inspect.iscoroutinefunction(callback_fn):
196+
processed_item = await callback_fn(item)
197+
else:
198+
processed_item = callback_fn(item)
199+
if processed_item:
200+
# If processed_item is also a list, extend instead of append
201+
if isinstance(processed_item, list):
202+
processed_items.extend(processed_item)
203+
else:
204+
processed_items.append(processed_item)
205+
prev_result = processed_items
206+
else:
207+
# Original logic for dict input
208+
if inspect.iscoroutinefunction(callback_fn):
209+
prev_result = await callback_fn(prev_result)
210+
else:
211+
prev_result = callback_fn(prev_result)
193212
except Exception as e:
194213
logger.error(f"Error in output processing callback: {e}")
195214

examples/components/web/super_agent/src/super_agent/common/sandbox_config.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
from .checkpointer_state_manager import CheckpointerStateManager
99
from langcrew_tools.utils.sandbox import sandbox_toolkit
10-
10+
from agentbox import Sandbox
11+
from langcrew_tools.cloud_phone.base import enable_a11y
12+
from langcrew_tools.utils.env_config import env_config
13+
from langchain_core.callbacks.manager import dispatch_custom_event
1114

1215
logger = logging.getLogger(__name__)
1316

@@ -47,3 +50,64 @@ async def _get_async_sandbox() -> "AsyncSandbox":
4750
return sandbox
4851

4952
return _get_async_sandbox
53+
54+
55+
def create_cloud_phone_sandbox_by_session_id(
56+
session_id: str,
57+
checkpointer: BaseCheckpointSaver | None = None,
58+
) -> Callable[[], Awaitable["str"]]:
59+
async def _get_cloud_phone_async_sandbox() -> "str":
60+
# For now, create a new sandbox (placeholder implementation)
61+
sandbox_id = await CheckpointerStateManager(checkpointer).get_value(
62+
session_id, "cloud_phone_sandbox_id"
63+
)
64+
if sandbox_id:
65+
logger.info(
66+
f"cloud_phone_sandbox_id session_id: {session_id} cloud_phone_sandbox_id: {sandbox_id}"
67+
)
68+
return sandbox_id
69+
else:
70+
logger.info(f"create cloud_phone_sandbox_id session_id: {session_id}")
71+
config = env_config.get_dict("AGENTBOX_")
72+
config = env_config.filter_valid_parameters(Sandbox, config)
73+
sbx = Sandbox(**config)
74+
sbx.adb_shell.connect()
75+
await enable_a11y(sbx)
76+
auth_info = sbx.get_instance_auth_info(config["timeout"])
77+
78+
logger.info(
79+
f"cloud_phone_sandbox_id session_id: {session_id} auth_info: {auth_info}"
80+
)
81+
82+
try:
83+
dispatch_custom_event(
84+
"on_langcrew_agentbox_created",
85+
{
86+
"sandbox_id": sbx.sandbox_id,
87+
"session_id": session_id,
88+
"instance_no": auth_info.instance_no,
89+
**(
90+
{
91+
"access_key": auth_info.access_key,
92+
"access_secret_key": auth_info.access_secret_key,
93+
"expire_time": auth_info.expire_time,
94+
"user_id": auth_info.user_id,
95+
}
96+
if auth_info
97+
else {}
98+
),
99+
},
100+
config={"configurable": {"thread_id": session_id}},
101+
)
102+
except Exception as e:
103+
logger.warning(
104+
f"create cloud_phone_sandbox_id session_id: {session_id} error: {e}"
105+
)
106+
107+
await CheckpointerStateManager(checkpointer).set_state(
108+
session_id, {"cloud_phone_sandbox_id": sbx.sandbox_id}
109+
)
110+
# Safely call the async callback if provided
111+
return sbx.sandbox_id
112+
113+
return _get_cloud_phone_async_sandbox

0 commit comments

Comments
 (0)