Fix alias pre-commit errors (#28)
This commit is contained in:
@@ -66,6 +66,7 @@ repos:
|
|||||||
| \.html$
|
| \.html$
|
||||||
)
|
)
|
||||||
args: [
|
args: [
|
||||||
|
"--init-hook=import sys; sys.path.insert(0, 'alias/src')",
|
||||||
--disable=W0511,
|
--disable=W0511,
|
||||||
--disable=W0718,
|
--disable=W0718,
|
||||||
--disable=W0122,
|
--disable=W0122,
|
||||||
|
|||||||
@@ -3,3 +3,9 @@
|
|||||||
|
|
||||||
__version__ = "0.0.1"
|
__version__ = "0.0.1"
|
||||||
|
|
||||||
|
__all__ = ["agent", "runtime", "__version__"]
|
||||||
|
|
||||||
|
# Import submodules to make them accessible via alias.agent, alias.runtime
|
||||||
|
# Import at the end to avoid circular import issues
|
||||||
|
from . import agent # noqa: E402, F401
|
||||||
|
from . import runtime # noqa: E402, F401
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Agent module for Alias"""
|
||||||
|
|
||||||
|
__all__ = ["agents", "tools", "mock", "utils"]
|
||||||
|
|
||||||
|
# Import submodules to make them accessible via alias.agent.agents, etc.
|
||||||
|
from . import agents # noqa: E402, F401
|
||||||
|
from . import tools # noqa: E402, F401
|
||||||
|
from . import mock # noqa: E402, F401
|
||||||
|
from . import utils # noqa: E402, F401
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from typing import Optional, Any, Type, Callable
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import time
|
|
||||||
from pydantic import BaseModel
|
|
||||||
from loguru import logger
|
|
||||||
import traceback
|
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
from typing import Any, Optional, Type
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from agentscope.agent import ReActAgent
|
from agentscope.agent import ReActAgent
|
||||||
from agentscope.model import ChatModelBase
|
from agentscope.model import ChatModelBase
|
||||||
@@ -49,6 +50,7 @@ class AliasAgentBase(ReActAgent):
|
|||||||
|
|
||||||
async def _reasoning(self):
|
async def _reasoning(self):
|
||||||
"""Override _reasoning to add retry logic."""
|
"""Override _reasoning to add retry logic."""
|
||||||
|
|
||||||
# Call the parent class's _reasoning method directly to
|
# Call the parent class's _reasoning method directly to
|
||||||
# avoid double hook execution
|
# avoid double hook execution
|
||||||
# We need to call the underlying implementation without hooks
|
# We need to call the underlying implementation without hooks
|
||||||
@@ -57,10 +59,10 @@ class AliasAgentBase(ReActAgent):
|
|||||||
# metaclass processing
|
# metaclass processing
|
||||||
# Access the method from the class that defines it
|
# Access the method from the class that defines it
|
||||||
# (before metaclass wrapping)
|
# (before metaclass wrapping)
|
||||||
original_method = ReActAgent.__dict__['_reasoning']
|
original_method = ReActAgent.__dict__["_reasoning"]
|
||||||
# Check if this is the wrapped version by looking for
|
# Check if this is the wrapped version by looking for
|
||||||
# the wrapper attributes
|
# the wrapper attributes
|
||||||
if hasattr(original_method, '__wrapped__'):
|
if hasattr(original_method, "__wrapped__"):
|
||||||
# This is the wrapped version, get the original
|
# This is the wrapped version, get the original
|
||||||
original_method = original_method.__wrapped__
|
original_method = original_method.__wrapped__
|
||||||
return await original_method(self)
|
return await original_method(self)
|
||||||
@@ -68,17 +70,17 @@ class AliasAgentBase(ReActAgent):
|
|||||||
for i in range(MODEL_MAX_RETRIES - 1):
|
for i in range(MODEL_MAX_RETRIES - 1):
|
||||||
try:
|
try:
|
||||||
return await call_parent_reasoning()
|
return await call_parent_reasoning()
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Reasoning fail at attempt {i + 1}. "
|
f"Reasoning fail at attempt {i + 1}. "
|
||||||
f"Max attempts {MODEL_MAX_RETRIES}\n"
|
f"Max attempts {MODEL_MAX_RETRIES}\n"
|
||||||
f"{traceback.format_exc()}"
|
f"{traceback.format_exc()}",
|
||||||
)
|
)
|
||||||
memory_msgs = await self.memory.get_memory()
|
memory_msgs = await self.memory.get_memory()
|
||||||
mem_len = len(memory_msgs)
|
mem_len = len(memory_msgs)
|
||||||
# ensure the last message has no tool_use before next attempt
|
# ensure the last message has no tool_use before next attempt
|
||||||
if mem_len > 0 and memory_msgs[-1].has_content_blocks(
|
if mem_len > 0 and memory_msgs[-1].has_content_blocks(
|
||||||
"tool_use"
|
"tool_use",
|
||||||
):
|
):
|
||||||
await self.memory.delete(index=mem_len - 1)
|
await self.memory.delete(index=mem_len - 1)
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
@@ -241,7 +243,6 @@ class AliasAgentBase(ReActAgent):
|
|||||||
# Skip non-serializable values
|
# Skip non-serializable values
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Skip the printing of the finish function call
|
# Skip the printing of the finish function call
|
||||||
if (
|
if (
|
||||||
tool_call["name"] != self.finish_function_name
|
tool_call["name"] != self.finish_function_name
|
||||||
|
|||||||
@@ -1,51 +1,40 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Deep Research Agent"""
|
"""Deep Research Agent"""
|
||||||
# pylint: disable=too-many-lines, no-name-in-module
|
# pylint: disable=too-many-lines, no-name-in-module
|
||||||
import os
|
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from typing import Type, Optional, Any, Tuple
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Any, Optional, Tuple, Type
|
||||||
|
|
||||||
# from copy import deepcopy
|
# from copy import deepcopy
|
||||||
import shortuuid
|
import shortuuid
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from agentscope import logger
|
||||||
|
from agentscope.formatter import FormatterBase
|
||||||
|
from agentscope.memory import MemoryBase
|
||||||
|
from agentscope.message import Msg, TextBlock, ToolResultBlock, ToolUseBlock
|
||||||
|
from agentscope.model import ChatModelBase
|
||||||
|
from agentscope.tool import ToolResponse
|
||||||
|
|
||||||
from alias.agent.agents import AliasAgentBase
|
from alias.agent.agents import AliasAgentBase
|
||||||
from alias.agent.tools import AliasToolkit
|
from alias.agent.agents._dragent_utils.built_in_prompt.promptmodule import (
|
||||||
|
FollowupJudge,
|
||||||
|
ReflectFailure,
|
||||||
|
SubtasksDecomposition,
|
||||||
|
WebExtraction,
|
||||||
|
)
|
||||||
|
from alias.agent.agents._dragent_utils.utils import (
|
||||||
|
get_dynamic_tool_call_json,
|
||||||
|
get_structure_output,
|
||||||
|
load_prompt_dict,
|
||||||
|
)
|
||||||
from alias.agent.agents._planning_tools._planning_notebook import (
|
from alias.agent.agents._planning_tools._planning_notebook import (
|
||||||
WorkerResponse,
|
WorkerResponse,
|
||||||
)
|
)
|
||||||
|
from alias.agent.tools import AliasToolkit
|
||||||
from alias.agent.agents._dragent_utils.built_in_prompt.promptmodule import (
|
|
||||||
SubtasksDecomposition,
|
|
||||||
WebExtraction,
|
|
||||||
FollowupJudge,
|
|
||||||
ReflectFailure,
|
|
||||||
)
|
|
||||||
from alias.agent.agents._dragent_utils.utils import (
|
|
||||||
load_prompt_dict,
|
|
||||||
get_dynamic_tool_call_json,
|
|
||||||
get_structure_output,
|
|
||||||
)
|
|
||||||
|
|
||||||
from agentscope import logger, setup_logger
|
|
||||||
# from agentscope.mcp import StatefulClientBase
|
|
||||||
# from agentscope.agent import ReActAgent
|
|
||||||
from agentscope.model import ChatModelBase
|
|
||||||
from agentscope.formatter import FormatterBase
|
|
||||||
from agentscope.memory import MemoryBase
|
|
||||||
from agentscope.tool import (
|
|
||||||
ToolResponse,
|
|
||||||
Toolkit,
|
|
||||||
)
|
|
||||||
from agentscope.message import (
|
|
||||||
Msg,
|
|
||||||
ToolUseBlock,
|
|
||||||
TextBlock,
|
|
||||||
ToolResultBlock,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
_DEEP_RESEARCH_AGENT_DEFAULT_SYS_PROMPT = "You're a helpful assistant."
|
_DEEP_RESEARCH_AGENT_DEFAULT_SYS_PROMPT = "You're a helpful assistant."
|
||||||
@@ -61,7 +50,7 @@ class SubTaskItem(BaseModel):
|
|||||||
|
|
||||||
async def deep_research_pre_reply_hook(
|
async def deep_research_pre_reply_hook(
|
||||||
self: "DeepResearchAgent",
|
self: "DeepResearchAgent",
|
||||||
kwargs: dict[str, Any], # pylint: disable=W0613
|
kwargs: dict[str, Any],
|
||||||
):
|
):
|
||||||
# Maintain the subtask list
|
# Maintain the subtask list
|
||||||
msg: Msg = kwargs.get("msg")
|
msg: Msg = kwargs.get("msg")
|
||||||
@@ -82,29 +71,40 @@ async def deep_research_pre_reply_hook(
|
|||||||
|
|
||||||
async def deep_research_post_reply_hook(
|
async def deep_research_post_reply_hook(
|
||||||
self: "DeepResearchAgent",
|
self: "DeepResearchAgent",
|
||||||
kwargs: Any,
|
kwargs: Any, # pylint: disable=W0613
|
||||||
output: Any,
|
output: Any, # pylint: disable=W0613
|
||||||
):
|
):
|
||||||
self.current_subtask = []
|
self.current_subtask = []
|
||||||
|
|
||||||
|
|
||||||
def _dump_json(
|
def _dump_json(
|
||||||
save_info: list[Msg] | dict,
|
save_info: list[Msg] | dict,
|
||||||
dir: str = "./dr_execution_trac"
|
directory: str = "./dr_execution_trac",
|
||||||
):
|
):
|
||||||
if not os.path.isdir(dir):
|
if not os.path.isdir(directory):
|
||||||
os.makedirs(dir, exist_ok=True)
|
os.makedirs(directory, exist_ok=True)
|
||||||
if isinstance(save_info, list) and len(save_info) > 0 and isinstance(save_info[0], Msg):
|
if (
|
||||||
|
isinstance(save_info, list)
|
||||||
|
and len(save_info) > 0
|
||||||
|
and isinstance(save_info[0], Msg)
|
||||||
|
):
|
||||||
save_info = [msg.to_dict() for msg in save_info]
|
save_info = [msg.to_dict() for msg in save_info]
|
||||||
file_path = os.path.join(dir, "memory-" + str(uuid.uuid4().hex) + ".json")
|
file_path = os.path.join(
|
||||||
|
directory,
|
||||||
|
"memory-" + str(uuid.uuid4().hex) + ".json",
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
file_path = os.path.join(dir, "plane-" + str(uuid.uuid4().hex) + ".json")
|
file_path = os.path.join(
|
||||||
with open(file_path, "w") as f:
|
directory,
|
||||||
|
"plane-" + str(uuid.uuid4().hex) + ".json",
|
||||||
|
)
|
||||||
|
with open(file_path, "w", encoding="utf-8") as f:
|
||||||
json.dump(save_info, f, ensure_ascii=False, indent=4)
|
json.dump(save_info, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
|
||||||
async def deep_research_pre_reasoning_hook(
|
async def deep_research_pre_reasoning_hook(
|
||||||
self: "DeepResearchAgent",
|
self: "DeepResearchAgent",
|
||||||
kwargs: Any,
|
kwargs: Any, # pylint: disable=W0613
|
||||||
):
|
):
|
||||||
memory = await self.memory.get_memory()
|
memory = await self.memory.get_memory()
|
||||||
_dump_json(memory)
|
_dump_json(memory)
|
||||||
@@ -117,15 +117,17 @@ async def deep_research_pre_reasoning_hook(
|
|||||||
]
|
]
|
||||||
research_results = []
|
research_results = []
|
||||||
for tool_call in self.search_call_buffer:
|
for tool_call in self.search_call_buffer:
|
||||||
msg = await self._get_research_result(tool_call.get("id"))
|
msg = await self._get_research_result( # pylint: disable=W0212
|
||||||
|
tool_call.get("id"),
|
||||||
|
)
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
research_results.append(
|
research_results.append(
|
||||||
json.dumps(
|
json.dumps(
|
||||||
msg.get_content_blocks("tool_result"),
|
msg.get_content_blocks("tool_result"),
|
||||||
ensure_ascii=False,
|
ensure_ascii=False,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
await self._follow_up( # pylint: disable=W0212
|
||||||
await self._follow_up(
|
|
||||||
search_results="\n".join(research_results),
|
search_results="\n".join(research_results),
|
||||||
search_queries="\n".join(search_queries),
|
search_queries="\n".join(search_queries),
|
||||||
)
|
)
|
||||||
@@ -142,9 +144,7 @@ async def deep_research_pre_reasoning_hook(
|
|||||||
reasoning_prompt = self.prompt_dict["reasoning_prompt"].format_map(
|
reasoning_prompt = self.prompt_dict["reasoning_prompt"].format_map(
|
||||||
{
|
{
|
||||||
"objective": self.current_subtask[-1].objective,
|
"objective": self.current_subtask[-1].objective,
|
||||||
"plan": cur_plan
|
"plan": cur_plan if cur_plan else "There is no working plan now.",
|
||||||
if cur_plan
|
|
||||||
else "There is no working plan now.",
|
|
||||||
"knowledge_gap": f"## Knowledge Gaps:\n {cur_know_gap}"
|
"knowledge_gap": f"## Knowledge Gaps:\n {cur_know_gap}"
|
||||||
if cur_know_gap
|
if cur_know_gap
|
||||||
else "",
|
else "",
|
||||||
@@ -166,8 +166,8 @@ async def deep_research_pre_reasoning_hook(
|
|||||||
|
|
||||||
async def deep_research_post_reasoning_hook(
|
async def deep_research_post_reasoning_hook(
|
||||||
self: "DeepResearchAgent", # pylint: disable=W0613
|
self: "DeepResearchAgent", # pylint: disable=W0613
|
||||||
kwargs: Any,
|
kwargs: Any, # pylint: disable=W0613
|
||||||
output_msg: Msg,
|
output_msg: Msg, # pylint: disable=W0613
|
||||||
):
|
):
|
||||||
num_msgs = await self.memory.size()
|
num_msgs = await self.memory.size()
|
||||||
if num_msgs > 1:
|
if num_msgs > 1:
|
||||||
@@ -178,7 +178,7 @@ async def deep_research_post_reasoning_hook(
|
|||||||
async def deep_research_post_action_hook(
|
async def deep_research_post_action_hook(
|
||||||
self: "DeepResearchAgent",
|
self: "DeepResearchAgent",
|
||||||
kwargs: Any,
|
kwargs: Any,
|
||||||
output_msg: Msg,
|
output_msg: Msg, # pylint: disable=W0613
|
||||||
):
|
):
|
||||||
tool_call = kwargs.get("tool_call", {})
|
tool_call = kwargs.get("tool_call", {})
|
||||||
if tool_call and tool_call.get("name") == self.search_function:
|
if tool_call and tool_call.get("name") == self.search_function:
|
||||||
@@ -274,7 +274,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
"intermediate_summarize": self.summarize_function,
|
"intermediate_summarize": self.summarize_function,
|
||||||
"reflect_failure": "reflect_failure",
|
"reflect_failure": "reflect_failure",
|
||||||
"subtask_finish": "finish_current_subtask",
|
"subtask_finish": "finish_current_subtask",
|
||||||
"finish_function_name": self.finish_function_name
|
"finish_function_name": self.finish_function_name,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
tool_use_rule = self.prompt_dict["tool_use_rule"].format_map(
|
tool_use_rule = self.prompt_dict["tool_use_rule"].format_map(
|
||||||
@@ -311,34 +311,34 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
self.summarize_intermediate_results,
|
self.summarize_intermediate_results,
|
||||||
)
|
)
|
||||||
self.toolkit.register_tool_function(
|
self.toolkit.register_tool_function(
|
||||||
self.finish_current_subtask
|
self.finish_current_subtask,
|
||||||
)
|
)
|
||||||
|
|
||||||
# add hooks
|
# add hooks
|
||||||
self.register_instance_hook(
|
self.register_instance_hook(
|
||||||
"pre_reply",
|
"pre_reply",
|
||||||
"deep_research_pre_reply_hook",
|
"deep_research_pre_reply_hook",
|
||||||
deep_research_pre_reply_hook
|
deep_research_pre_reply_hook,
|
||||||
)
|
)
|
||||||
self.register_instance_hook(
|
self.register_instance_hook(
|
||||||
"post_reply",
|
"post_reply",
|
||||||
"deep_research_post_reply_hook",
|
"deep_research_post_reply_hook",
|
||||||
deep_research_post_reply_hook
|
deep_research_post_reply_hook,
|
||||||
)
|
)
|
||||||
self.register_instance_hook(
|
self.register_instance_hook(
|
||||||
"pre_reasoning",
|
"pre_reasoning",
|
||||||
"deep_research_pre_reasoning_hook",
|
"deep_research_pre_reasoning_hook",
|
||||||
deep_research_pre_reasoning_hook
|
deep_research_pre_reasoning_hook,
|
||||||
)
|
)
|
||||||
self.register_instance_hook(
|
self.register_instance_hook(
|
||||||
"post_reasoning",
|
"post_reasoning",
|
||||||
"deep_research_post_reasoning_hook",
|
"deep_research_post_reasoning_hook",
|
||||||
deep_research_post_reasoning_hook
|
deep_research_post_reasoning_hook,
|
||||||
)
|
)
|
||||||
self.register_instance_hook(
|
self.register_instance_hook(
|
||||||
"post_acting",
|
"post_acting",
|
||||||
"deep_research_post_action_hook",
|
"deep_research_post_action_hook",
|
||||||
deep_research_post_action_hook
|
deep_research_post_action_hook,
|
||||||
)
|
)
|
||||||
self.search_call_buffer = []
|
self.search_call_buffer = []
|
||||||
|
|
||||||
@@ -471,7 +471,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
"Identify the knowledge gaps of the current "
|
"Identify the knowledge gaps of the current "
|
||||||
"subtask and generate a working plan by subtask "
|
"subtask and generate a working plan by subtask "
|
||||||
"decomposition",
|
"decomposition",
|
||||||
"assistant"
|
"assistant",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -548,7 +548,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
"(Follow-up by extraction)"
|
"(Follow-up by extraction)"
|
||||||
"Read the website more intensively to mine more "
|
"Read the website more intensively to mine more "
|
||||||
"information.",
|
"information.",
|
||||||
"assistant"
|
"assistant",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
@@ -568,9 +568,9 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
text=json.dumps(
|
text=json.dumps(
|
||||||
extraction_check,
|
extraction_check,
|
||||||
ensure_ascii=False,
|
ensure_ascii=False,
|
||||||
indent=2
|
indent=2,
|
||||||
)
|
),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
role="assistant",
|
role="assistant",
|
||||||
)
|
)
|
||||||
@@ -579,7 +579,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
except Exception as e: # noqa: F841
|
except Exception as e: # noqa: F841
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Error when checking subtask finish status {e}"
|
f"Error when checking subtask finish status {e}"
|
||||||
f"{traceback.format_exc()}"
|
f"{traceback.format_exc()}",
|
||||||
)
|
)
|
||||||
extraction_check = {}
|
extraction_check = {}
|
||||||
|
|
||||||
@@ -599,9 +599,9 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
Msg(
|
Msg(
|
||||||
self.name,
|
self.name,
|
||||||
[TextBlock(type="text", text=f"Reading {urls}")],
|
[TextBlock(type="text", text=f"Reading {urls}")],
|
||||||
"assistant"
|
"assistant",
|
||||||
),
|
),
|
||||||
last=True
|
last=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# call the extract_function
|
# call the extract_function
|
||||||
@@ -629,7 +629,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
self.name,
|
self.name,
|
||||||
"(Follow-up to explore)"
|
"(Follow-up to explore)"
|
||||||
"Check if current subtask knowledge gaps are fulfilled",
|
"Check if current subtask knowledge gaps are fulfilled",
|
||||||
"assistant"
|
"assistant",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
msgs = [
|
msgs = [
|
||||||
@@ -646,7 +646,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
"user",
|
"user",
|
||||||
self.prompt_dict["follow_up_judge_sys_prompt"],
|
self.prompt_dict["follow_up_judge_sys_prompt"],
|
||||||
role="user",
|
role="user",
|
||||||
)
|
),
|
||||||
]
|
]
|
||||||
follow_up_judge = await self.get_model_output(
|
follow_up_judge = await self.get_model_output(
|
||||||
msgs=msgs,
|
msgs=msgs,
|
||||||
@@ -660,23 +660,26 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
type="text",
|
type="text",
|
||||||
text=json.dumps(
|
text=json.dumps(
|
||||||
follow_up_judge,
|
follow_up_judge,
|
||||||
ensure_ascii=False, indent=2
|
ensure_ascii=False,
|
||||||
)
|
indent=2,
|
||||||
)
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
role="assistant",
|
role="assistant",
|
||||||
)
|
)
|
||||||
await self.memory.add(follow_up_msg)
|
await self.memory.add(follow_up_msg)
|
||||||
except Exception as e: # noqa: F841
|
except Exception as e: # noqa: F841
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Error when checking subtask finish status {e}"
|
f"Error when checking subtask finish status {e}",
|
||||||
)
|
)
|
||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
follow_up_judge = {}
|
follow_up_judge = {}
|
||||||
|
|
||||||
if follow_up_judge.get("knowledge_gap_revision", ""):
|
if follow_up_judge.get("knowledge_gap_revision", ""):
|
||||||
self.current_subtask[-1].knowledge_gaps = \
|
self.current_subtask[-1].knowledge_gaps = follow_up_judge.get(
|
||||||
follow_up_judge.get("knowledge_gap_revision", "")
|
"knowledge_gap_revision",
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
follow_up_judge.get("to_further_explore", False)
|
follow_up_judge.get("to_further_explore", False)
|
||||||
@@ -691,14 +694,12 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
type="text",
|
type="text",
|
||||||
text="Still need to do more research "
|
text="Still need to do more research "
|
||||||
f"to figure out {subtask}",
|
f"to figure out {subtask}",
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
role="assistant"
|
role="assistant",
|
||||||
)
|
),
|
||||||
)
|
|
||||||
intermediate_report = (
|
|
||||||
await self.summarize_intermediate_results()
|
|
||||||
)
|
)
|
||||||
|
intermediate_report = await self.summarize_intermediate_results()
|
||||||
self.current_subtask.append(
|
self.current_subtask.append(
|
||||||
SubTaskItem(objective=subtask),
|
SubTaskItem(objective=subtask),
|
||||||
)
|
)
|
||||||
@@ -748,14 +749,12 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
for msg in reversed(memory_msgs):
|
for msg in reversed(memory_msgs):
|
||||||
if msg.metadata and msg.metadata.get("is_report_msg"):
|
if msg.metadata and msg.metadata.get("is_report_msg"):
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
intermediate_memory.append(msg)
|
intermediate_memory.append(msg)
|
||||||
intermediate_memory.reverse()
|
intermediate_memory.reverse()
|
||||||
if remove_last_tool_use:
|
if remove_last_tool_use:
|
||||||
while (
|
while len(intermediate_memory) > 0 and intermediate_memory[
|
||||||
len(intermediate_memory) > 0 and
|
-1
|
||||||
intermediate_memory[-1].has_content_blocks("tool_use")
|
].has_content_blocks("tool_use"):
|
||||||
):
|
|
||||||
intermediate_memory.pop(-1)
|
intermediate_memory.pop(-1)
|
||||||
return intermediate_memory
|
return intermediate_memory
|
||||||
|
|
||||||
@@ -765,34 +764,33 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
for msg in reversed(memory_msgs):
|
for msg in reversed(memory_msgs):
|
||||||
if msg.metadata and msg.metadata.get("is_report_msg"):
|
if msg.metadata and msg.metadata.get("is_report_msg"):
|
||||||
break
|
break
|
||||||
elif msg.role == "user":
|
if msg.role == "user":
|
||||||
break
|
break
|
||||||
elif msg.has_content_blocks("tool_use"):
|
if msg.has_content_blocks("tool_use"):
|
||||||
stop = False
|
stop = False
|
||||||
for block in msg.get_content_blocks("tool_use"):
|
for block in msg.get_content_blocks("tool_use"):
|
||||||
if block.get("name") == self.summarize_function:
|
if block.get("name") == self.summarize_function:
|
||||||
stop = True
|
stop = True
|
||||||
if stop:
|
if stop:
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
remove_num += 1
|
remove_num += 1
|
||||||
else:
|
else:
|
||||||
remove_num += 1
|
remove_num += 1
|
||||||
start_index = len(memory_msgs) - remove_num
|
start_index = len(memory_msgs) - remove_num
|
||||||
logger.info(
|
logger.info(
|
||||||
"---> delete messages: "
|
"---> delete messages: "
|
||||||
f"{list(range(start_index, len(memory_msgs)))}"
|
f"{list(range(start_index, len(memory_msgs)))}",
|
||||||
)
|
)
|
||||||
await self.memory.delete(list(range(start_index, len(memory_msgs))))
|
await self.memory.delete(list(range(start_index, len(memory_msgs))))
|
||||||
|
|
||||||
async def _get_research_result(
|
async def _get_research_result(
|
||||||
self,
|
self,
|
||||||
tool_call_id: str
|
tool_call_id: str,
|
||||||
) -> Msg | None:
|
) -> Msg | None:
|
||||||
memory_msgs = await self.memory.get_memory()
|
memory_msgs = await self.memory.get_memory()
|
||||||
for msg in reversed(memory_msgs):
|
for msg in reversed(memory_msgs):
|
||||||
if msg.has_content_blocks("tool_result"):
|
if msg.has_content_blocks("tool_result"):
|
||||||
for block in msg.get_content_blocks('tool_result'):
|
for block in msg.get_content_blocks("tool_result"):
|
||||||
if block.get("id") == tool_call_id:
|
if block.get("id") == tool_call_id:
|
||||||
return msg
|
return msg
|
||||||
return None
|
return None
|
||||||
@@ -823,7 +821,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
"[summarize_intermediate_results]"
|
"[summarize_intermediate_results]"
|
||||||
"Examine whether the knowledge gaps or objective"
|
"Examine whether the knowledge gaps or objective"
|
||||||
"have been fulfill",
|
"have been fulfill",
|
||||||
"assistant"
|
"assistant",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -883,7 +881,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
Msg(
|
Msg(
|
||||||
self.name,
|
self.name,
|
||||||
"Summarize the intermediate results into a report",
|
"Summarize the intermediate results into a report",
|
||||||
"assistant"
|
"assistant",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -934,7 +932,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
metadata={"is_report_msg": True,}
|
metadata={"is_report_msg": True},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# add to memory for the follow-up case
|
# add to memory for the follow-up case
|
||||||
@@ -948,7 +946,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
role="assistant",
|
role="assistant",
|
||||||
metadata={"is_report_msg": True}
|
metadata={"is_report_msg": True},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return ToolResponse(
|
return ToolResponse(
|
||||||
@@ -989,7 +987,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
tmp_report_path = os.path.join(
|
tmp_report_path = os.path.join(
|
||||||
self.tmp_file_storage_dir,
|
self.tmp_file_storage_dir,
|
||||||
f"{self.report_path_based}_"
|
f"{self.report_path_based}_"
|
||||||
f"inprocess_report_{index + 1}.md"
|
f"inprocess_report_{index + 1}.md",
|
||||||
)
|
)
|
||||||
params = {
|
params = {
|
||||||
"file_path": tmp_report_path,
|
"file_path": tmp_report_path,
|
||||||
@@ -1010,11 +1008,11 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
TextBlock(
|
TextBlock(
|
||||||
type="text",
|
type="text",
|
||||||
text="Reading progress report: "
|
text="Reading progress report: "
|
||||||
f"{tmp_report_path}"
|
f"{tmp_report_path}",
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
"assistant"
|
"assistant",
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
msgs = [
|
msgs = [
|
||||||
@@ -1031,7 +1029,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
]
|
]
|
||||||
else: # Use only intermediate memory to generate report
|
else: # Use only intermediate memory to generate report
|
||||||
intermediate_memory = await self._get_intermediate_memory(
|
intermediate_memory = await self._get_intermediate_memory(
|
||||||
remove_last_tool_use=True
|
remove_last_tool_use=True,
|
||||||
)
|
)
|
||||||
msgs = [
|
msgs = [
|
||||||
Msg(
|
Msg(
|
||||||
@@ -1045,7 +1043,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
Msg(
|
Msg(
|
||||||
self.name,
|
self.name,
|
||||||
"Collect and polish all draft reports into a final report",
|
"Collect and polish all draft reports into a final report",
|
||||||
"assistant"
|
"assistant",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
@@ -1104,8 +1102,10 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
name=self.name,
|
name=self.name,
|
||||||
role="assistant",
|
role="assistant",
|
||||||
content=[
|
content=[
|
||||||
TextBlock(type="text",
|
TextBlock(
|
||||||
text=subtask_progress_summary, )
|
type="text",
|
||||||
|
text=subtask_progress_summary,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
metadata=structure_response.model_dump(),
|
metadata=structure_response.model_dump(),
|
||||||
)
|
)
|
||||||
@@ -1122,7 +1122,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
The reflection about plan rephrasing and subtask decomposition.
|
The reflection about plan rephrasing and subtask decomposition.
|
||||||
"""
|
"""
|
||||||
intermediate_memory = await self._get_intermediate_memory(
|
intermediate_memory = await self._get_intermediate_memory(
|
||||||
remove_last_tool_use=True
|
remove_last_tool_use=True,
|
||||||
)
|
)
|
||||||
reflect_sys_prompt = self.prompt_dict["reflect_sys_prompt"]
|
reflect_sys_prompt = self.prompt_dict["reflect_sys_prompt"]
|
||||||
conversation_history = ""
|
conversation_history = ""
|
||||||
@@ -1148,7 +1148,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
Msg(
|
Msg(
|
||||||
self.name,
|
self.name,
|
||||||
"Reflect on the failure of the action",
|
"Reflect on the failure of the action",
|
||||||
"assistant"
|
"assistant",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
reflection = await self.get_model_output(
|
reflection = await self.get_model_output(
|
||||||
@@ -1193,7 +1193,7 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
save_msg = None
|
save_msg = None
|
||||||
for msg in reversed(msgs):
|
for msg in reversed(msgs):
|
||||||
for i, block in enumerate(
|
for i, block in enumerate(
|
||||||
msg.get_content_blocks("tool_use")
|
msg.get_content_blocks("tool_use"),
|
||||||
):
|
):
|
||||||
if block.get("name") == "reflect_failure":
|
if block.get("name") == "reflect_failure":
|
||||||
save_msg = msg
|
save_msg = msg
|
||||||
@@ -1296,7 +1296,6 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
is_last=True,
|
is_last=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=invalid-overridden-method, unused-argument
|
# pylint: disable=invalid-overridden-method, unused-argument
|
||||||
async def generate_response( #
|
async def generate_response( #
|
||||||
self,
|
self,
|
||||||
@@ -1333,15 +1332,17 @@ class DeepResearchAgent(AliasAgentBase):
|
|||||||
detailed_report_path: (
|
detailed_report_path: (
|
||||||
f"Final detailed report generated by {self.name}"
|
f"Final detailed report generated by {self.name}"
|
||||||
f"for '{str(self.user_query)}'"
|
f"for '{str(self.user_query)}'"
|
||||||
)
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
response_msg = Msg(
|
response_msg = Msg(
|
||||||
name=self.name,
|
name=self.name,
|
||||||
role="assistant",
|
role="assistant",
|
||||||
content=[
|
content=[
|
||||||
TextBlock(type="text",
|
TextBlock(
|
||||||
text=subtask_progress_summary,)
|
type="text",
|
||||||
|
text=subtask_progress_summary,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
metadata=structure_response.model_dump(),
|
metadata=structure_response.model_dump(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class SubtasksDecomposition(BaseModel):
|
class SubtasksDecomposition(BaseModel):
|
||||||
"""
|
"""
|
||||||
Model for structured subtask decomposition output in deep research.
|
Model for structured subtask decomposition output in deep research.
|
||||||
@@ -7,20 +9,23 @@ class SubtasksDecomposition(BaseModel):
|
|||||||
|
|
||||||
knowledge_gaps: str = Field(
|
knowledge_gaps: str = Field(
|
||||||
description=(
|
description=(
|
||||||
"A markdown checklist of essential knowledge gaps and optional "
|
"A markdown checklist of essential knowledge gaps and "
|
||||||
"perspective-expansion gaps (flagged with (EXPANSION)), each on its own line. "
|
"optional perspective-expansion gaps (flagged with "
|
||||||
"E.g. '- [ ] Detailed analysis of JD.com's ...\\n- [ ] (EXPANSION) X...'."
|
"(EXPANSION)), each on its own line. E.g. '- [ ] Detailed "
|
||||||
|
"analysis of JD.com's ...\\n- [ ] (EXPANSION) X...'."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
working_plan: str = Field(
|
working_plan: str = Field(
|
||||||
description=(
|
description=(
|
||||||
"A logically ordered step-by-step working plan (3-5 steps), "
|
"A logically ordered step-by-step working plan (3-5 steps),"
|
||||||
"each step starting with its number (1., 2., etc), including both "
|
" each step starting with its number (1., 2., etc), "
|
||||||
"core and expansion steps. Expanded steps should be clearly marked "
|
"including both core and expansion steps. Expanded steps "
|
||||||
"with (EXPANSION) and provide contextual or analytical depth.."
|
"should be clearly marked with (EXPANSION) and provide "
|
||||||
|
"contextual or analytical depth.."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class WebExtraction(BaseModel):
|
class WebExtraction(BaseModel):
|
||||||
"""
|
"""
|
||||||
Model for structured follow-up web extraction output in deep research.
|
Model for structured follow-up web extraction output in deep research.
|
||||||
@@ -42,6 +47,7 @@ class WebExtraction(BaseModel):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class FollowupJudge(BaseModel):
|
class FollowupJudge(BaseModel):
|
||||||
"""
|
"""
|
||||||
Model for structured follow-up decompose judging output in deep research.
|
Model for structured follow-up decompose judging output in deep research.
|
||||||
@@ -49,15 +55,15 @@ class FollowupJudge(BaseModel):
|
|||||||
|
|
||||||
reasoning: str = Field(
|
reasoning: str = Field(
|
||||||
description=(
|
description=(
|
||||||
"The reasoning for your decision, including a summary of evidence "
|
"The reasoning for your decision, including a summary of "
|
||||||
"and logic for whether more information is needed. You should "
|
"evidence and logic for whether more information is needed. "
|
||||||
"include specific gaps or opportunities if the current "
|
"You should include specific gaps or opportunities if the "
|
||||||
"information is still insufficient"
|
"current information is still insufficient"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
knowledge_gap_revision: str = Field(
|
knowledge_gap_revision: str = Field(
|
||||||
"Revise the knowledge gaps in the current. "
|
"Revise the knowledge gaps in the current. "
|
||||||
"Mark the gaps with sufficient information as [x]."
|
"Mark the gaps with sufficient information as [x].",
|
||||||
)
|
)
|
||||||
to_further_explore: bool = Field(
|
to_further_explore: bool = Field(
|
||||||
description=(
|
description=(
|
||||||
@@ -81,10 +87,11 @@ class ReflectFailure(BaseModel):
|
|||||||
|
|
||||||
rephrase_subtask: dict = Field(
|
rephrase_subtask: dict = Field(
|
||||||
description=(
|
description=(
|
||||||
"Information about whether the problematic subtask needs to be "
|
"Information about whether the problematic subtask needs to "
|
||||||
"rephrased due to a design flaw or misunderstanding. If rephrasing "
|
"be rephrased due to a design flaw or misunderstanding. If "
|
||||||
"is needed, provide the modified working plan with only the inappropriate "
|
"rephrasing is needed, provide the modified working plan with"
|
||||||
"subtask replaced by its improved version."
|
" only the inappropriate subtask replaced by its improved "
|
||||||
|
"version."
|
||||||
),
|
),
|
||||||
json_schema_extra={
|
json_schema_extra={
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
@@ -92,25 +99,30 @@ class ReflectFailure(BaseModel):
|
|||||||
"properties": {
|
"properties": {
|
||||||
"need_rephrase": {
|
"need_rephrase": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Set to 'true' if the failed subtask "
|
"description": (
|
||||||
"needs to be rephrased due to a design "
|
"Set to 'true' if the failed subtask needs "
|
||||||
"flaw or misunderstanding; otherwise, 'false'.",
|
"to be rephrased due to a design flaw or "
|
||||||
|
"misunderstanding; otherwise, 'false'."
|
||||||
|
),
|
||||||
},
|
},
|
||||||
"rephrased_plan": {
|
"rephrased_plan": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The modified working plan with only the inappropriate "
|
"description": (
|
||||||
"subtask replaced by its improved version. If no "
|
"The modified working plan with only the "
|
||||||
"rephrasing is needed, provide an empty string.",
|
"inappropriate subtask replaced by its "
|
||||||
|
"improved version. If no rephrasing is "
|
||||||
|
"needed, provide an empty string."
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
decompose_subtask: dict = Field(
|
decompose_subtask: dict = Field(
|
||||||
description=(
|
description=(
|
||||||
"Information about whether the problematic subtask should be further "
|
"Information about whether the problematic subtask should be "
|
||||||
"decomposed. If decomposition is required, provide the failed subtask "
|
"further decomposed. If decomposition is required, provide "
|
||||||
"and the reason for its decomposition."
|
"the failed subtask and the reason for its decomposition."
|
||||||
),
|
),
|
||||||
json_schema_extra={
|
json_schema_extra={
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
@@ -118,15 +130,19 @@ class ReflectFailure(BaseModel):
|
|||||||
"properties": {
|
"properties": {
|
||||||
"need_decompose": {
|
"need_decompose": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Set to 'true' if the failed subtask should "
|
"description": (
|
||||||
"be further decomposed; otherwise, 'false'.",
|
"Set to 'true' if the failed subtask should "
|
||||||
|
"be further decomposed; otherwise, 'false'."
|
||||||
|
),
|
||||||
},
|
},
|
||||||
"failed_subtask": {
|
"failed_subtask": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The failed subtask that needs to be further "
|
"description": (
|
||||||
"decomposed.",
|
"The failed subtask that needs to be further "
|
||||||
|
"decomposed."
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""The utilities for deep research agent"""
|
"""The utilities for deep research agent"""
|
||||||
import os
|
|
||||||
import json
|
import json
|
||||||
from typing import Union, Sequence, Any, Type
|
import os
|
||||||
from pydantic import BaseModel
|
|
||||||
import re
|
import re
|
||||||
|
from typing import Any, Sequence, Type, Union
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from agentscope.tool import Toolkit, ToolResponse
|
from agentscope.tool import Toolkit, ToolResponse
|
||||||
from agentscope.agent import ReActAgent
|
|
||||||
|
|
||||||
TOOL_RESULTS_MAX_WORDS = 30000
|
TOOL_RESULTS_MAX_WORDS = 30000
|
||||||
|
|
||||||
@@ -24,12 +24,13 @@ def get_prompt_from_file(
|
|||||||
prompt = f.read()
|
prompt = f.read()
|
||||||
return prompt
|
return prompt
|
||||||
|
|
||||||
|
|
||||||
async def count_by_words(sentence: str) -> float:
|
async def count_by_words(sentence: str) -> float:
|
||||||
"""Count words of a sentence"""
|
"""Count words of a sentence"""
|
||||||
words = re.findall(
|
words = re.findall(
|
||||||
r"\w+|[^\w\s]",
|
r"\w+|[^\w\s]",
|
||||||
sentence,
|
sentence,
|
||||||
re.UNICODE
|
re.UNICODE,
|
||||||
)
|
)
|
||||||
|
|
||||||
word_count = 0.0
|
word_count = 0.0
|
||||||
|
|||||||
@@ -4,19 +4,20 @@ Meta Planner agent class that can handle complicated tasks with
|
|||||||
planning-execution pattern.
|
planning-execution pattern.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=W0613
|
# pylint: disable=W0613
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Optional, Any, Literal, Callable
|
|
||||||
import json
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any, Callable, Literal, Optional
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from agentscope import logger
|
|
||||||
from agentscope.message import Msg, ToolUseBlock, TextBlock, ToolResultBlock
|
|
||||||
from agentscope.tool import ToolResponse
|
|
||||||
from agentscope.model import ChatModelBase
|
|
||||||
from agentscope.formatter import FormatterBase
|
from agentscope.formatter import FormatterBase
|
||||||
from agentscope.memory import MemoryBase
|
from agentscope.memory import MemoryBase
|
||||||
|
from agentscope.message import Msg, TextBlock, ToolResultBlock, ToolUseBlock
|
||||||
|
from agentscope.model import ChatModelBase
|
||||||
|
from agentscope.tool import ToolResponse
|
||||||
|
|
||||||
from alias.agent.agents import AliasAgentBase
|
from alias.agent.agents import AliasAgentBase
|
||||||
from alias.agent.tools import AliasToolkit
|
from alias.agent.tools import AliasToolkit
|
||||||
@@ -306,7 +307,6 @@ class MetaPlanner(AliasAgentBase):
|
|||||||
generate_response_post_action_hook,
|
generate_response_post_action_hook,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def prepare_planner_tools(
|
def prepare_planner_tools(
|
||||||
self,
|
self,
|
||||||
planner_mode: Literal["disable", "enforced", "dynamic"],
|
planner_mode: Literal["disable", "enforced", "dynamic"],
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class RoadmapManager(StateModule):
|
|||||||
|
|
||||||
async def decompose_task_and_build_roadmap(
|
async def decompose_task_and_build_roadmap(
|
||||||
self,
|
self,
|
||||||
user_latest_input: str,
|
user_latest_input: str, # pylint: disable=W0613
|
||||||
given_task_conclusion: str,
|
given_task_conclusion: str,
|
||||||
detail_analysis_for_plan: str,
|
detail_analysis_for_plan: str,
|
||||||
decomposed_subtasks: list[SubTaskSpecification],
|
decomposed_subtasks: list[SubTaskSpecification],
|
||||||
|
|||||||
@@ -514,7 +514,7 @@ class WorkerManager(StateModule):
|
|||||||
subtask_idx: int,
|
subtask_idx: int,
|
||||||
selected_worker_name: str,
|
selected_worker_name: str,
|
||||||
detailed_instruction: str,
|
detailed_instruction: str,
|
||||||
reset_worker_memory: bool = False
|
reset_worker_memory: bool = False,
|
||||||
) -> ToolResponse:
|
) -> ToolResponse:
|
||||||
"""
|
"""
|
||||||
Execute a worker agent for the next unfinished subtask.
|
Execute a worker agent for the next unfinished subtask.
|
||||||
@@ -539,7 +539,7 @@ class WorkerManager(StateModule):
|
|||||||
memory can also be reset for better performance (but require
|
memory can also be reset for better performance (but require
|
||||||
providing sufficient context information in
|
providing sufficient context information in
|
||||||
`detailed_instruction`); 3) if a worker is stopped just because
|
`detailed_instruction`); 3) if a worker is stopped just because
|
||||||
hitting th maximum round constraint in the previous execution
|
hitting the maximum round constraint in the previous execution
|
||||||
and it's going to work on the sam task, DO NOT reset the
|
and it's going to work on the sam task, DO NOT reset the
|
||||||
memory.
|
memory.
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from .mock_message_models import (
|
|||||||
BaseMessage,
|
BaseMessage,
|
||||||
MessageState,
|
MessageState,
|
||||||
MockMessage,
|
MockMessage,
|
||||||
UserMessage
|
UserMessage,
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Mock message models for local testing without api_server dependency."""
|
"""Mock message models for local testing without api_server dependency."""
|
||||||
from enum import Enum
|
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Any, Optional, List
|
from enum import Enum
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class MessageState(str, Enum):
|
class MessageState(str, Enum):
|
||||||
"""Message state enumeration."""
|
"""Message state enumeration."""
|
||||||
|
|
||||||
RUNNING = "running"
|
RUNNING = "running"
|
||||||
FINISHED = "finished"
|
FINISHED = "finished"
|
||||||
FAILED = "failed"
|
FAILED = "failed"
|
||||||
@@ -15,6 +17,7 @@ class MessageState(str, Enum):
|
|||||||
|
|
||||||
class MessageType(str, Enum):
|
class MessageType(str, Enum):
|
||||||
"""Message type enumeration."""
|
"""Message type enumeration."""
|
||||||
|
|
||||||
RESPONSE = "response"
|
RESPONSE = "response"
|
||||||
SUB_RESPONSE = "sub_response"
|
SUB_RESPONSE = "sub_response"
|
||||||
THOUGHT = "thought"
|
THOUGHT = "thought"
|
||||||
@@ -27,6 +30,7 @@ class MessageType(str, Enum):
|
|||||||
|
|
||||||
class BaseMessage(BaseModel):
|
class BaseMessage(BaseModel):
|
||||||
"""Base message class for local testing."""
|
"""Base message class for local testing."""
|
||||||
|
|
||||||
role: str = "assistant"
|
role: str = "assistant"
|
||||||
content: Any = ""
|
content: Any = ""
|
||||||
name: Optional[str] = None
|
name: Optional[str] = None
|
||||||
@@ -36,6 +40,7 @@ class BaseMessage(BaseModel):
|
|||||||
|
|
||||||
class UserMessage(BaseMessage):
|
class UserMessage(BaseMessage):
|
||||||
"""User message for local testing."""
|
"""User message for local testing."""
|
||||||
|
|
||||||
role: str = "user"
|
role: str = "user"
|
||||||
name: str = "User"
|
name: str = "User"
|
||||||
|
|
||||||
|
|||||||
@@ -211,4 +211,3 @@ class MockSessionService:
|
|||||||
|
|
||||||
async def get_state(self) -> dict:
|
async def get_state(self) -> dict:
|
||||||
return self.state
|
return self.state
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,27 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# pylint: disable=W0612,E0611,C2801
|
# pylint: disable=W0612,E0611,C2801
|
||||||
import os
|
import os
|
||||||
from typing import Optional
|
|
||||||
from datetime import datetime
|
|
||||||
import traceback
|
import traceback
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from agentscope.message import Msg
|
from agentscope.formatter import DashScopeChatFormatter
|
||||||
from agentscope.model import (
|
from agentscope.mcp import StdIOStatefulClient
|
||||||
OpenAIChatModel,
|
|
||||||
AnthropicChatModel,
|
|
||||||
DashScopeChatModel,
|
|
||||||
)
|
|
||||||
from agentscope.formatter import (
|
|
||||||
OpenAIChatFormatter,
|
|
||||||
AnthropicChatFormatter,
|
|
||||||
DashScopeChatFormatter,
|
|
||||||
)
|
|
||||||
from agentscope.memory import InMemoryMemory
|
from agentscope.memory import InMemoryMemory
|
||||||
from agentscope.mcp import StdIOStatefulClient, StatefulClientBase
|
from agentscope.message import Msg
|
||||||
from agentscope.token import OpenAITokenCounter
|
from agentscope.model import DashScopeChatModel
|
||||||
from agentscope_runtime.sandbox.box.sandbox import Sandbox
|
from agentscope_runtime.sandbox.box.sandbox import Sandbox
|
||||||
|
|
||||||
from alias.agent.agents import (
|
from alias.agent.agents import BrowserAgent, DeepResearchAgent, MetaPlanner
|
||||||
MetaPlanner,
|
|
||||||
DeepResearchAgent,
|
|
||||||
BrowserAgent,
|
|
||||||
)
|
|
||||||
from alias.agent.tools import AliasToolkit
|
|
||||||
from alias.agent.agents._planning_tools._worker_manager import share_tools
|
from alias.agent.agents._planning_tools._worker_manager import share_tools
|
||||||
from alias.agent.utils.constants import BROWSER_AGENT_DESCRIPTION
|
from alias.agent.mock import MockSessionService
|
||||||
|
from alias.agent.tools import AliasToolkit
|
||||||
from alias.agent.tools.improved_tools import DashScopeMultiModalTools
|
from alias.agent.tools.improved_tools import DashScopeMultiModalTools
|
||||||
from alias.agent.tools.toolkit_hooks import LongTextPostHook
|
from alias.agent.tools.toolkit_hooks import LongTextPostHook
|
||||||
|
from alias.agent.utils.constants import BROWSER_AGENT_DESCRIPTION
|
||||||
|
|
||||||
# Open source version always uses mock services
|
# Open source version always uses mock services
|
||||||
from alias.agent.mock import MockSessionService
|
|
||||||
|
|
||||||
SessionService = MockSessionService
|
SessionService = MockSessionService
|
||||||
|
|
||||||
|
|
||||||
@@ -126,7 +112,7 @@ async def add_tools(
|
|||||||
|
|
||||||
|
|
||||||
async def arun_agents(
|
async def arun_agents(
|
||||||
session_service: SessionService,
|
session_service: SessionService, # type: ignore[valid-type]
|
||||||
sandbox: Sandbox = None,
|
sandbox: Sandbox = None,
|
||||||
enable_clarification: bool = True,
|
enable_clarification: bool = True,
|
||||||
):
|
):
|
||||||
@@ -188,7 +174,7 @@ async def arun_agents(
|
|||||||
|
|
||||||
async def test_deepresearch_agent(
|
async def test_deepresearch_agent(
|
||||||
task_str: str,
|
task_str: str,
|
||||||
session_service: SessionService,
|
session_service: SessionService, # type: ignore[valid-type]
|
||||||
sandbox: Sandbox = None,
|
sandbox: Sandbox = None,
|
||||||
):
|
):
|
||||||
instruction = Msg(
|
instruction = Msg(
|
||||||
@@ -234,7 +220,7 @@ async def test_deepresearch_agent(
|
|||||||
|
|
||||||
async def test_browseruse_agent(
|
async def test_browseruse_agent(
|
||||||
task_str: str,
|
task_str: str,
|
||||||
session_service: SessionService,
|
session_service: SessionService, # type: ignore[valid-type]
|
||||||
sandbox: Sandbox = None,
|
sandbox: Sandbox = None,
|
||||||
):
|
):
|
||||||
time_str = datetime.now().strftime("%Y%m%d%H%M%S")
|
time_str = datetime.now().strftime("%Y%m%d%H%M%S")
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# pylint: disable=R1724
|
# pylint: disable=R1724
|
||||||
from typing import Optional, Callable, Any
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from typing import Any, Callable, Optional
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from agentscope.mcp import StatefulClientBase, MCPClientBase
|
from agentscope.mcp import MCPClientBase, StatefulClientBase
|
||||||
from agentscope.tool import (
|
from agentscope.message import TextBlock, ToolUseBlock
|
||||||
Toolkit,
|
from agentscope.tool import ToolResponse, Toolkit
|
||||||
ToolResponse,
|
|
||||||
)
|
|
||||||
from agentscope.message import ToolUseBlock, TextBlock
|
|
||||||
from agentscope_runtime.sandbox import FilesystemSandbox, BrowserSandbox
|
|
||||||
|
|
||||||
from alias.agent.tools.toolkit_hooks import (
|
from alias.agent.tools.toolkit_hooks import (
|
||||||
LongTextPostHook
|
LongTextPostHook,
|
||||||
)
|
)
|
||||||
from alias.agent.tools.improved_tools import ImprovedFileOperations
|
from alias.agent.tools.improved_tools import ImprovedFileOperations
|
||||||
from alias.agent.tools.tool_blacklist import TOOL_BLACKLIST
|
from alias.agent.tools.tool_blacklist import TOOL_BLACKLIST
|
||||||
@@ -21,6 +18,9 @@ from alias.agent.tools.toolkit_hooks import read_file_post_hook
|
|||||||
from alias.runtime.alias_sandbox.alias_sandbox import AliasSandbox
|
from alias.runtime.alias_sandbox.alias_sandbox import AliasSandbox
|
||||||
|
|
||||||
|
|
||||||
|
FilesystemSandbox = AliasSandbox
|
||||||
|
|
||||||
|
|
||||||
class AliasToolkit(Toolkit):
|
class AliasToolkit(Toolkit):
|
||||||
def __init__( # pylint: disable=W0102
|
def __init__( # pylint: disable=W0102
|
||||||
self,
|
self,
|
||||||
@@ -44,9 +44,8 @@ class AliasToolkit(Toolkit):
|
|||||||
# Get tools
|
# Get tools
|
||||||
tools_schema = self.sandbox.list_tools()
|
tools_schema = self.sandbox.list_tools()
|
||||||
for category, function_dicts in tools_schema.items():
|
for category, function_dicts in tools_schema.items():
|
||||||
if (
|
if (is_browser_toolkit and category == "playwright") or (
|
||||||
(is_browser_toolkit and category == "playwright")
|
not is_browser_toolkit and category != "playwright"
|
||||||
or (not is_browser_toolkit and category != "playwright")
|
|
||||||
):
|
):
|
||||||
for _, function_json in function_dicts.items():
|
for _, function_json in function_dicts.items():
|
||||||
if function_json["name"] not in self.tool_blacklist:
|
if function_json["name"] not in self.tool_blacklist:
|
||||||
@@ -66,7 +65,7 @@ class AliasToolkit(Toolkit):
|
|||||||
def _add_io_function(
|
def _add_io_function(
|
||||||
self,
|
self,
|
||||||
json_schema: dict,
|
json_schema: dict,
|
||||||
is_browser_tool: bool = False
|
is_browser_tool: bool = False, # pylint: disable=W0613
|
||||||
) -> None:
|
) -> None:
|
||||||
tool_name = json_schema["name"]
|
tool_name = json_schema["name"]
|
||||||
|
|
||||||
@@ -142,8 +141,9 @@ class AliasToolkit(Toolkit):
|
|||||||
if tool_func.startswith(("read_file", "read_multiple_files")):
|
if tool_func.startswith(("read_file", "read_multiple_files")):
|
||||||
self.tools[tool_func].postprocess_func = read_file_post_hook
|
self.tools[tool_func].postprocess_func = read_file_post_hook
|
||||||
if tool_func.startswith("tavily"):
|
if tool_func.startswith("tavily"):
|
||||||
self.tools[tool_func].postprocess_func = \
|
self.tools[
|
||||||
long_text_hook.truncate_and_save_response
|
tool_func
|
||||||
|
].postprocess_func = long_text_hook.truncate_and_save_response
|
||||||
|
|
||||||
async def add_and_connet_mcp_client(
|
async def add_and_connet_mcp_client(
|
||||||
self,
|
self,
|
||||||
@@ -193,10 +193,10 @@ async def test_toolkit():
|
|||||||
type="tool_use",
|
type="tool_use",
|
||||||
id="",
|
id="",
|
||||||
name="list_allowed_directories",
|
name="list_allowed_directories",
|
||||||
input={}
|
input={},
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
print("Allow directory:")
|
||||||
print(f"Allow directory:")
|
|
||||||
async for response in res:
|
async for response in res:
|
||||||
print(response)
|
print(response)
|
||||||
|
|
||||||
@@ -216,5 +216,6 @@ async def test_toolkit():
|
|||||||
|
|
||||||
await toolkit.close_mcp_clients()
|
await toolkit.close_mcp_clients()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(test_toolkit())
|
asyncio.run(test_toolkit())
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
"""
|
"""
|
||||||
Improved tools module for Alias agent toolkit.
|
Improved tools module for Alias agent toolkit.
|
||||||
|
|
||||||
This module contains enhanced tool functions that provide additional functionality
|
This module contains enhanced tool functions that provide additional
|
||||||
beyond the basic tools available in the standard toolkit.
|
functionality beyond the basic tools available in the standard toolkit.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .file_operations import ImprovedFileOperations
|
from .file_operations import ImprovedFileOperations
|
||||||
|
|||||||
@@ -7,19 +7,20 @@ original read_file functionality and adds support for
|
|||||||
reading specific line ranges from files.
|
reading specific line ranges from files.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
from loguru import logger
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from agentscope.tool import ToolResponse
|
|
||||||
from agentscope.message import TextBlock
|
from agentscope.message import TextBlock
|
||||||
|
from agentscope.tool import ToolResponse
|
||||||
|
|
||||||
from alias.agent.utils.constants import TMP_FILE_DIR
|
from alias.agent.utils.constants import TMP_FILE_DIR
|
||||||
from alias.agent.tools.sandbox_util import (
|
from alias.agent.tools.sandbox_util import (
|
||||||
TEXT_EXTENSIONS,
|
TEXT_EXTENSIONS,
|
||||||
create_or_edit_workspace_file,
|
create_or_edit_workspace_file,
|
||||||
create_workspace_directory
|
create_workspace_directory,
|
||||||
)
|
)
|
||||||
from alias.runtime.alias_sandbox import AliasSandbox
|
from alias.runtime.alias_sandbox import AliasSandbox
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ class ImprovedFileOperations:
|
|||||||
"""init with sandbox"""
|
"""init with sandbox"""
|
||||||
self.sandbox = sandbox
|
self.sandbox = sandbox
|
||||||
|
|
||||||
async def read_file(
|
async def read_file( # pylint: disable=R0911,R0912
|
||||||
self,
|
self,
|
||||||
file_path: str,
|
file_path: str,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
@@ -96,7 +97,8 @@ class ImprovedFileOperations:
|
|||||||
if self.sandbox is None:
|
if self.sandbox is None:
|
||||||
return ToolResponse(
|
return ToolResponse(
|
||||||
metadata={
|
metadata={
|
||||||
"success": False, "error": "No sandbox provided"
|
"success": False,
|
||||||
|
"error": "No sandbox provided",
|
||||||
},
|
},
|
||||||
content=[
|
content=[
|
||||||
TextBlock(
|
TextBlock(
|
||||||
@@ -116,7 +118,7 @@ class ImprovedFileOperations:
|
|||||||
# Call the original read_file tool
|
# Call the original read_file tool
|
||||||
tool_res = self.sandbox.call_tool(
|
tool_res = self.sandbox.call_tool(
|
||||||
name="read_file",
|
name="read_file",
|
||||||
arguments=params
|
arguments=params,
|
||||||
)
|
)
|
||||||
elif file_extension in TO_MARKDOWN_SUPPORT_MAPPING:
|
elif file_extension in TO_MARKDOWN_SUPPORT_MAPPING:
|
||||||
tool_res = _transfer_to_markdown_text(file_path, self.sandbox)
|
tool_res = _transfer_to_markdown_text(file_path, self.sandbox)
|
||||||
@@ -130,9 +132,10 @@ class ImprovedFileOperations:
|
|||||||
):
|
):
|
||||||
return ToolResponse(
|
return ToolResponse(
|
||||||
metadata={
|
metadata={
|
||||||
"success": False, "error": "Error when read file"
|
"success": False,
|
||||||
|
"error": "Error when read file",
|
||||||
},
|
},
|
||||||
content=tool_res.get("content", [])
|
content=tool_res.get("content", []),
|
||||||
)
|
)
|
||||||
elif (
|
elif (
|
||||||
tool_res.get("isError", True)
|
tool_res.get("isError", True)
|
||||||
@@ -144,15 +147,15 @@ class ImprovedFileOperations:
|
|||||||
TextBlock(
|
TextBlock(
|
||||||
type="text",
|
type="text",
|
||||||
text=f"Fail to read file on path {file_path}",
|
text=f"Fail to read file on path {file_path}",
|
||||||
)
|
),
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get the text content from the first content block
|
# Get the text content from the first content block
|
||||||
full_content = ""
|
full_content = ""
|
||||||
for block in tool_res.get("content", []):
|
for block in tool_res.get("content", []):
|
||||||
if isinstance(block, dict) and 'text' in block:
|
if isinstance(block, dict) and "text" in block:
|
||||||
full_content += block['text'] + "\n"
|
full_content += block["text"] + "\n"
|
||||||
|
|
||||||
# Split into lines
|
# Split into lines
|
||||||
lines = full_content.splitlines(keepends=True)
|
lines = full_content.splitlines(keepends=True)
|
||||||
@@ -171,7 +174,7 @@ class ImprovedFileOperations:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Handle offset and limit
|
# Handle offset and limit
|
||||||
start_line = (offset or 0) # 0-based index
|
start_line = offset or 0 # 0-based index
|
||||||
end_line = start_line + (limit or total_lines)
|
end_line = start_line + (limit or total_lines)
|
||||||
|
|
||||||
# Validate range
|
# Validate range
|
||||||
@@ -193,11 +196,13 @@ class ImprovedFileOperations:
|
|||||||
# Extract the requested lines
|
# Extract the requested lines
|
||||||
selected_lines = lines[start_line:end_line]
|
selected_lines = lines[start_line:end_line]
|
||||||
|
|
||||||
content = ''.join(selected_lines)
|
content = "".join(selected_lines)
|
||||||
|
|
||||||
# Add summary information
|
# Add summary information
|
||||||
summary = (f"Read lines {start_line}-{end_line} of "
|
summary = (
|
||||||
f"{total_lines} total lines from '{file_path}'")
|
f"Read lines {start_line}-{end_line} of "
|
||||||
|
f"{total_lines} total lines from '{file_path}'"
|
||||||
|
)
|
||||||
|
|
||||||
# save as markdown
|
# save as markdown
|
||||||
return_content = [
|
return_content = [
|
||||||
@@ -208,18 +213,20 @@ class ImprovedFileOperations:
|
|||||||
TextBlock(
|
TextBlock(
|
||||||
type="text",
|
type="text",
|
||||||
text=summary,
|
text=summary,
|
||||||
)
|
),
|
||||||
]
|
]
|
||||||
if file_extension in TO_MARKDOWN_SUPPORT_MAPPING:
|
if file_extension in TO_MARKDOWN_SUPPORT_MAPPING:
|
||||||
file_name_with_ext = os.path.basename(file_path)
|
file_name_with_ext = os.path.basename(file_path)
|
||||||
filename_without_ext = os.path.splitext(file_name_with_ext)[0]
|
filename_without_ext = os.path.splitext(file_name_with_ext)[0]
|
||||||
file_path = os.path.join(
|
file_path = os.path.join(
|
||||||
TMP_FILE_DIR,
|
TMP_FILE_DIR,
|
||||||
filename_without_ext + ".md"
|
filename_without_ext + ".md",
|
||||||
)
|
)
|
||||||
create_workspace_directory(self.sandbox, TMP_FILE_DIR)
|
create_workspace_directory(self.sandbox, TMP_FILE_DIR)
|
||||||
create_or_edit_workspace_file(
|
create_or_edit_workspace_file(
|
||||||
self.sandbox, file_path, full_content
|
self.sandbox,
|
||||||
|
file_path,
|
||||||
|
full_content,
|
||||||
)
|
)
|
||||||
return_content.append(
|
return_content.append(
|
||||||
TextBlock(
|
TextBlock(
|
||||||
@@ -229,8 +236,8 @@ class ImprovedFileOperations:
|
|||||||
"The (full) file is converted as markdown file"
|
"The (full) file is converted as markdown file"
|
||||||
" and saved completely at: "
|
" and saved completely at: "
|
||||||
f"{file_path}"
|
f"{file_path}"
|
||||||
)
|
),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return ToolResponse(
|
return ToolResponse(
|
||||||
@@ -257,7 +264,8 @@ class ImprovedFileOperations:
|
|||||||
|
|
||||||
|
|
||||||
def _transfer_to_markdown_text(
|
def _transfer_to_markdown_text(
|
||||||
file_path: str, sandbox: AliasSandbox = None
|
file_path: str,
|
||||||
|
sandbox: AliasSandbox = None,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
ext = os.path.splitext(file_path)[1].lower()
|
ext = os.path.splitext(file_path)[1].lower()
|
||||||
|
|
||||||
@@ -268,46 +276,46 @@ def _transfer_to_markdown_text(
|
|||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"text": f"File extension '{ext}' not supported in "
|
"text": f"File extension '{ext}' not supported in "
|
||||||
f"{TO_MARKDOWN_SUPPORT_MAPPING}."
|
f"{TO_MARKDOWN_SUPPORT_MAPPING}.",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
"uri": "file:" + file_path
|
"uri": "file:" + file_path,
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
res = sandbox.call_tool(
|
result = sandbox.call_tool( # pylint: disable=W0621
|
||||||
name="convert_to_markdown",
|
name="convert_to_markdown",
|
||||||
arguments=params
|
arguments=params,
|
||||||
)
|
)
|
||||||
content = res.get("content", [])
|
content = result.get("content", [])
|
||||||
new_content = []
|
new_content = []
|
||||||
for i, block in enumerate(content):
|
for i, _block in enumerate(content):
|
||||||
if content[i].get("text", "").startswith("Converted content:"):
|
if content[i].get("text", "").startswith("Converted content:"):
|
||||||
continue
|
continue
|
||||||
elif content[i].get("text", "").startswith("Output file:"):
|
if content[i].get("text", "").startswith("Output file:"):
|
||||||
continue
|
continue
|
||||||
else:
|
new_content.append(result["content"][i])
|
||||||
new_content.append(res["content"][i])
|
|
||||||
|
|
||||||
res["content"] = new_content
|
result["content"] = new_content
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
res = {
|
result = {
|
||||||
"isError": True,
|
"isError": True,
|
||||||
"error": str(e)
|
"error": str(e),
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return result
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from alias.agent.tools.sandbox_util import copy_local_file_to_workspace
|
from alias.agent.tools.sandbox_util import copy_local_file_to_workspace
|
||||||
|
|
||||||
with AliasSandbox() as box:
|
with AliasSandbox() as box:
|
||||||
res = copy_local_file_to_workspace(
|
res = copy_local_file_to_workspace(
|
||||||
box,
|
box,
|
||||||
"/Users/zitao.l/Downloads/22051_Which_LLM_Multi_Agent.pdf",
|
"/Users/zitao.l/Downloads/22051_Which_LLM_Multi_Agent.pdf",
|
||||||
"/workspace/test.pdf"
|
"/workspace/test.pdf",
|
||||||
)
|
)
|
||||||
print(res)
|
print(res)
|
||||||
toolset = ImprovedFileOperations(box)
|
toolset = ImprovedFileOperations(box)
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class DashScopeMultiModalTools:
|
|||||||
"content": [
|
"content": [
|
||||||
{
|
{
|
||||||
"text": "Transcript the content in the audio "
|
"text": "Transcript the content in the audio "
|
||||||
"to text."
|
"to text.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -253,6 +253,7 @@ class DashScopeMultiModalTools:
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
print(traceback.format_exc())
|
print(traceback.format_exc())
|
||||||
return ToolResponse(
|
return ToolResponse(
|
||||||
[
|
[
|
||||||
@@ -268,7 +269,7 @@ if __name__ == "__main__":
|
|||||||
with AliasSandbox() as box:
|
with AliasSandbox() as box:
|
||||||
tool_result = box.call_tool(
|
tool_result = box.call_tool(
|
||||||
"run_shell_command",
|
"run_shell_command",
|
||||||
arguments={"command": "apt update"}
|
arguments={"command": "apt update"},
|
||||||
)
|
)
|
||||||
print(tool_result)
|
print(tool_result)
|
||||||
tool_result = box.call_tool(
|
tool_result = box.call_tool(
|
||||||
@@ -299,7 +300,7 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
toolset = DashScopeMultiModalTools(
|
toolset = DashScopeMultiModalTools(
|
||||||
sandbox=box,
|
sandbox=box,
|
||||||
dashscope_api_key=os.getenv("DASHSCOPE_API_KEY", "")
|
dashscope_api_key=os.getenv("DASHSCOPE_API_KEY", ""),
|
||||||
)
|
)
|
||||||
result = toolset.dashscope_image_to_text(
|
result = toolset.dashscope_image_to_text(
|
||||||
image_url=picture_path,
|
image_url=picture_path,
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
|
||||||
from typing import Optional
|
|
||||||
import json
|
|
||||||
from pathlib import Path
|
|
||||||
import base64
|
import base64
|
||||||
from loguru import logger
|
|
||||||
import io
|
import io
|
||||||
|
import json
|
||||||
|
import os
|
||||||
import tarfile
|
import tarfile
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from agentscope_runtime.sandbox.manager.container_clients.docker_client import DockerClient
|
from loguru import logger
|
||||||
|
|
||||||
|
from agentscope_runtime.sandbox.manager.container_clients.docker_client import ( # noqa: E501 # pylint: disable=C0301
|
||||||
|
DockerClient,
|
||||||
|
)
|
||||||
from alias.runtime.alias_sandbox import AliasSandbox
|
from alias.runtime.alias_sandbox import AliasSandbox
|
||||||
|
|
||||||
|
|
||||||
@@ -395,7 +398,8 @@ def copy_local_file_to_workspace(
|
|||||||
|
|
||||||
# Create a tar archive in memory
|
# Create a tar archive in memory
|
||||||
tar_stream = io.BytesIO()
|
tar_stream = io.BytesIO()
|
||||||
tar = tarfile.open(fileobj=tar_stream, mode='w')
|
# pylint: disable=R1732
|
||||||
|
tar = tarfile.open(fileobj=tar_stream, mode="w")
|
||||||
|
|
||||||
# Add file to tar archive
|
# Add file to tar archive
|
||||||
tar.add(local_path, arcname=os.path.basename(target_path))
|
tar.add(local_path, arcname=os.path.basename(target_path))
|
||||||
@@ -418,7 +422,6 @@ def copy_local_file_to_workspace(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
with AliasSandbox() as box:
|
with AliasSandbox() as box:
|
||||||
create_or_edit_workspace_file(
|
create_or_edit_workspace_file(
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
from .long_text_post_hook import LongTextPostHook
|
from .long_text_post_hook import LongTextPostHook
|
||||||
from .read_file_post_hook import read_file_post_hook
|
from .read_file_post_hook import read_file_post_hook
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from agentscope.message import ToolUseBlock, TextBlock
|
|||||||
from alias.agent.utils.constants import TMP_FILE_DIR
|
from alias.agent.utils.constants import TMP_FILE_DIR
|
||||||
from alias.agent.tools.sandbox_util import (
|
from alias.agent.tools.sandbox_util import (
|
||||||
create_or_edit_workspace_file,
|
create_or_edit_workspace_file,
|
||||||
create_workspace_directory
|
create_workspace_directory,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ class LongTextPostHook:
|
|||||||
def __init__(self, sandbox):
|
def __init__(self, sandbox):
|
||||||
self.sandbox = sandbox
|
self.sandbox = sandbox
|
||||||
|
|
||||||
def truncate_and_save_response(
|
def truncate_and_save_response( # pylint: disable=R1710
|
||||||
self,
|
self,
|
||||||
tool_use: ToolUseBlock, # pylint: disable=W0613
|
tool_use: ToolUseBlock, # pylint: disable=W0613
|
||||||
tool_response: ToolResponse,
|
tool_response: ToolResponse,
|
||||||
@@ -35,25 +35,24 @@ class LongTextPostHook:
|
|||||||
tool_response: The tool response to potentially truncate.
|
tool_response: The tool response to potentially truncate.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
The budget is set to approximately 80K tokens (8194 * 10 characters)
|
The budget is set to approximately 80K tokens
|
||||||
to ensure responses remain manageable for the language model.
|
(8194 * 10 characters) to ensure responses remain
|
||||||
|
manageable for the language model.
|
||||||
"""
|
"""
|
||||||
# Set budget to prevent overwhelming the model with too much content
|
# Set budget to prevent overwhelming the model with too much content
|
||||||
budget = 8194 * 10 # Approximately 80K tokens of content
|
budget = 8194 * 10 # Approximately 80K tokens of content
|
||||||
append_hint = (
|
append_hint = "\n\n[Content is too long and truncated....]"
|
||||||
"\n\n[Content is too long and truncated....]"
|
|
||||||
)
|
|
||||||
|
|
||||||
new_tool_response = ToolResponse(
|
new_tool_response = ToolResponse(
|
||||||
id=tool_response.id,
|
id=tool_response.id,
|
||||||
stream=tool_response.stream,
|
stream=tool_response.stream,
|
||||||
is_last=tool_response.is_last,
|
is_last=tool_response.is_last,
|
||||||
is_interrupted=tool_response.is_interrupted,
|
is_interrupted=tool_response.is_interrupted,
|
||||||
content=[]
|
content=[],
|
||||||
)
|
)
|
||||||
if isinstance(tool_response.content, list):
|
if isinstance(tool_response.content, list):
|
||||||
save_text_block = None
|
save_text_block = None
|
||||||
for i, block in enumerate(tool_response.content):
|
for _i, block in enumerate(tool_response.content):
|
||||||
if block["type"] == "text":
|
if block["type"] == "text":
|
||||||
text = block["text"]
|
text = block["text"]
|
||||||
text_len = len(text)
|
text_len = len(text)
|
||||||
@@ -67,7 +66,7 @@ class LongTextPostHook:
|
|||||||
tmp_file_name_prefix = tool_use.get("name", "")
|
tmp_file_name_prefix = tool_use.get("name", "")
|
||||||
save_text_block = self._save_tmp_file(
|
save_text_block = self._save_tmp_file(
|
||||||
tmp_file_name_prefix,
|
tmp_file_name_prefix,
|
||||||
tool_response.content
|
tool_response.content,
|
||||||
)
|
)
|
||||||
new_tool_response.append = (
|
new_tool_response.append = (
|
||||||
text[:threshold] + append_hint
|
text[:threshold] + append_hint
|
||||||
@@ -75,8 +74,8 @@ class LongTextPostHook:
|
|||||||
new_tool_response.content.append(
|
new_tool_response.content.append(
|
||||||
TextBlock(
|
TextBlock(
|
||||||
type="text",
|
type="text",
|
||||||
text=text[:threshold] + append_hint
|
text=text[:threshold] + append_hint,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
new_tool_response.content.append(block)
|
new_tool_response.content.append(block)
|
||||||
@@ -91,29 +90,32 @@ class LongTextPostHook:
|
|||||||
tmp_file_name_prefix = tool_use.get("name", "")
|
tmp_file_name_prefix = tool_use.get("name", "")
|
||||||
save_text_block = self._save_tmp_file(
|
save_text_block = self._save_tmp_file(
|
||||||
tmp_file_name_prefix,
|
tmp_file_name_prefix,
|
||||||
tool_response.content
|
tool_response.content,
|
||||||
)
|
)
|
||||||
# Calculate truncation threshold (80% of proportional budget)
|
# Calculate truncation threshold (80% of proportional budget)
|
||||||
threshold = int(budget / text_len * len(text) * 0.8)
|
threshold = int(budget / text_len * len(text) * 0.8)
|
||||||
tool_response.content = (
|
tool_response.content = text[:threshold] + append_hint
|
||||||
text[:threshold] + append_hint
|
|
||||||
)
|
|
||||||
tool_response.content = [
|
tool_response.content = [
|
||||||
TextBlock(type="text", text=tool_response.content),
|
TextBlock(type="text", text=tool_response.content),
|
||||||
save_text_block
|
save_text_block,
|
||||||
]
|
]
|
||||||
|
return tool_response
|
||||||
return tool_response
|
return tool_response
|
||||||
|
|
||||||
def _save_tmp_file(self, save_file_name_prefix: str, content: list | str):
|
def _save_tmp_file(self, save_file_name_prefix: str, content: list | str):
|
||||||
create_workspace_directory(self.sandbox, TMP_FILE_DIR)
|
create_workspace_directory(self.sandbox, TMP_FILE_DIR)
|
||||||
save_file_name = save_file_name_prefix + "-" + str(
|
save_file_name = (
|
||||||
uuid.uuid4().hex[:8]
|
save_file_name_prefix
|
||||||
|
+ "-"
|
||||||
|
+ str(
|
||||||
|
uuid.uuid4().hex[:8],
|
||||||
|
)
|
||||||
)
|
)
|
||||||
file_path = os.path.join(TMP_FILE_DIR, save_file_name)
|
file_path = os.path.join(TMP_FILE_DIR, save_file_name)
|
||||||
json_str = json.dumps(content, ensure_ascii=False, indent=2)
|
json_str = json.dumps(content, ensure_ascii=False, indent=2)
|
||||||
wrapped = '\\n'.join(
|
wrapped = "\\n".join(
|
||||||
[textwrap.fill(line, width=500) for line in json_str.split('\\n')])
|
[textwrap.fill(line, width=500) for line in json_str.split("\\n")],
|
||||||
|
)
|
||||||
create_or_edit_workspace_file(
|
create_or_edit_workspace_file(
|
||||||
self.sandbox,
|
self.sandbox,
|
||||||
file_path,
|
file_path,
|
||||||
@@ -127,5 +129,3 @@ class LongTextPostHook:
|
|||||||
"other bash command to extract "
|
"other bash command to extract "
|
||||||
"useful information.",
|
"useful information.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
from agentscope.message import ToolUseBlock, TextBlock
|
from agentscope.message import ToolUseBlock, TextBlock
|
||||||
from agentscope.tool import ToolResponse
|
from agentscope.tool import ToolResponse
|
||||||
|
|
||||||
|
|||||||
@@ -6,20 +6,17 @@ Alias Command Line Interface
|
|||||||
This module provides a terminal executable entry point
|
This module provides a terminal executable entry point
|
||||||
for the Alias agent application.
|
for the Alias agent application.
|
||||||
"""
|
"""
|
||||||
import json
|
|
||||||
from typing import Optional
|
|
||||||
import asyncio
|
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import asyncio
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from agentscope.agent import UserAgent, TerminalUserInput
|
|
||||||
from agentscope_runtime.sandbox import FilesystemSandbox, BrowserSandbox
|
from agentscope.agent import TerminalUserInput, UserAgent
|
||||||
from agentscope_runtime.sandbox.box.sandbox import Sandbox
|
|
||||||
from agentscope.mcp import StdIOStatefulClient
|
|
||||||
|
|
||||||
from alias.agent.mock import MockSessionService, UserMessage
|
from alias.agent.mock import MockSessionService, UserMessage
|
||||||
from alias.agent.run import (
|
from alias.agent.run import (
|
||||||
@@ -27,10 +24,8 @@ from alias.agent.run import (
|
|||||||
test_browseruse_agent,
|
test_browseruse_agent,
|
||||||
test_deepresearch_agent,
|
test_deepresearch_agent,
|
||||||
)
|
)
|
||||||
from alias.agent.tools import AliasToolkit
|
|
||||||
from alias.agent.tools.improved_tools import DashScopeMultiModalTools
|
|
||||||
from alias.runtime.alias_sandbox.alias_sandbox import AliasSandbox
|
|
||||||
from alias.agent.tools.sandbox_util import copy_local_file_to_workspace
|
from alias.agent.tools.sandbox_util import copy_local_file_to_workspace
|
||||||
|
from alias.runtime.alias_sandbox.alias_sandbox import AliasSandbox
|
||||||
|
|
||||||
|
|
||||||
async def run_agent_task(
|
async def run_agent_task(
|
||||||
@@ -52,15 +47,15 @@ async def run_agent_task(
|
|||||||
# Create initial user message
|
# Create initial user message
|
||||||
user_agent = UserAgent(name="User")
|
user_agent = UserAgent(name="User")
|
||||||
user_agent.override_instance_input_method(
|
user_agent.override_instance_input_method(
|
||||||
input_method = TerminalUserInput(
|
input_method=TerminalUserInput(
|
||||||
input_hint = "User (Enter `exit` or `quit` to exit): "
|
input_hint="User (Enter `exit` or `quit` to exit): ",
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Run agent with sandbox context
|
# Run agent with sandbox context
|
||||||
with AliasSandbox() as sandbox:
|
with AliasSandbox() as sandbox:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Sandbox mount dir: {sandbox.get_info().get('mount_dir')}"
|
f"Sandbox mount dir: {sandbox.get_info().get('mount_dir')}",
|
||||||
)
|
)
|
||||||
logger.info(f"Sandbox desktop URL: {sandbox.desktop_url}")
|
logger.info(f"Sandbox desktop URL: {sandbox.desktop_url}")
|
||||||
webbrowser.open(sandbox.desktop_url)
|
webbrowser.open(sandbox.desktop_url)
|
||||||
@@ -68,7 +63,7 @@ async def run_agent_task(
|
|||||||
if files:
|
if files:
|
||||||
target_paths = []
|
target_paths = []
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Uploading {len(files)} file(s) to sandbox workspace..."
|
f"Uploading {len(files)} file(s) to sandbox workspace...",
|
||||||
)
|
)
|
||||||
for file_path in files:
|
for file_path in files:
|
||||||
if not os.path.exists(file_path):
|
if not os.path.exists(file_path):
|
||||||
@@ -88,7 +83,6 @@ async def run_agent_task(
|
|||||||
|
|
||||||
if result.get("isError"):
|
if result.get("isError"):
|
||||||
raise ValueError(f"Failed to upload {file_path}: {result}")
|
raise ValueError(f"Failed to upload {file_path}: {result}")
|
||||||
else:
|
|
||||||
logger.info(f"Successfully uploaded to {result}")
|
logger.info(f"Successfully uploaded to {result}")
|
||||||
|
|
||||||
target_paths.append(result.get("content", [])[0].get("text"))
|
target_paths.append(result.get("content", [])[0].get("text"))
|
||||||
@@ -104,14 +98,15 @@ async def run_agent_task(
|
|||||||
mode=mode,
|
mode=mode,
|
||||||
session=session,
|
session=session,
|
||||||
user_agent=user_agent,
|
user_agent=user_agent,
|
||||||
sandbox=sandbox
|
sandbox=sandbox,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _run_agent_loop(
|
async def _run_agent_loop(
|
||||||
mode: str,
|
mode: str,
|
||||||
session: MockSessionService,
|
session: MockSessionService,
|
||||||
user_agent: UserAgent,
|
user_agent: UserAgent,
|
||||||
sandbox: FilesystemSandbox,
|
sandbox: AliasSandbox,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Execute the agent loop with follow-up interactions.
|
Execute the agent loop with follow-up interactions.
|
||||||
@@ -133,8 +128,10 @@ async def _run_agent_loop(
|
|||||||
sandbox=sandbox,
|
sandbox=sandbox,
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
elif mode == "dr":
|
if mode == "dr":
|
||||||
usr_msg = (await session.get_messages())[-1].message.get("content")
|
usr_msg = (await session.get_messages())[-1].message.get(
|
||||||
|
"content",
|
||||||
|
)
|
||||||
logger.info(f"--> user_msg: {usr_msg}")
|
logger.info(f"--> user_msg: {usr_msg}")
|
||||||
await test_deepresearch_agent(
|
await test_deepresearch_agent(
|
||||||
usr_msg,
|
usr_msg,
|
||||||
@@ -142,7 +139,7 @@ async def _run_agent_loop(
|
|||||||
sandbox=sandbox,
|
sandbox=sandbox,
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
elif mode == "all":
|
if mode == "all":
|
||||||
await arun_agents(
|
await arun_agents(
|
||||||
session,
|
session,
|
||||||
sandbox=sandbox,
|
sandbox=sandbox,
|
||||||
@@ -153,10 +150,10 @@ async def _run_agent_loop(
|
|||||||
|
|
||||||
# Check for follow-up interaction
|
# Check for follow-up interaction
|
||||||
follow_msg = await user_agent()
|
follow_msg = await user_agent()
|
||||||
if (
|
if len(follow_msg.content) == 0 or follow_msg.content.lower() in [
|
||||||
len(follow_msg.content) == 0
|
"exit",
|
||||||
or follow_msg.content.lower() in ["exit", "quit"]
|
"quit",
|
||||||
):
|
]:
|
||||||
logger.info("Exiting agent loop")
|
logger.info("Exiting agent loop")
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -176,7 +173,8 @@ def main():
|
|||||||
)
|
)
|
||||||
|
|
||||||
subparsers = parser.add_subparsers(
|
subparsers = parser.add_subparsers(
|
||||||
dest="command", help="Available commands"
|
dest="command",
|
||||||
|
help="Available commands",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Run command
|
# Run command
|
||||||
@@ -244,7 +242,7 @@ def main():
|
|||||||
user_msg=args.task,
|
user_msg=args.task,
|
||||||
mode=args.mode,
|
mode=args.mode,
|
||||||
files=args.files if hasattr(args, "files") else None,
|
files=args.files if hasattr(args, "files") else None,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
logger.info("\nInterrupted by user")
|
logger.info("\nInterrupted by user")
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Runtime module for Alias"""
|
||||||
|
|
||||||
from agentscope_runtime.sandbox.box.sandbox import Sandbox
|
__all__ = ["alias_sandbox"]
|
||||||
|
|
||||||
|
# Import submodule to make it accessible via alias.runtime.alias_sandbox
|
||||||
|
from . import alias_sandbox # noqa: E402, F401
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
from .alias_sandbox import AliasSandbox
|
from .alias_sandbox import AliasSandbox
|
||||||
|
|
||||||
__all__ = ['AliasSandbox']
|
__all__ = ["AliasSandbox"]
|
||||||
|
|||||||
Reference in New Issue
Block a user