mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-09-14 21:51:25 +00:00
refactor(agent): Agent modular refactoring (#1487)
This commit is contained in:
4
dbgpt/agent/core/plan/awel/__init__.py
Normal file
4
dbgpt/agent/core/plan/awel/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
"""External planner.
|
||||
|
||||
Use AWEL as the external planner.
|
||||
"""
|
311
dbgpt/agent/core/plan/awel/agent_operator.py
Normal file
311
dbgpt/agent/core/plan/awel/agent_operator.py
Normal file
@@ -0,0 +1,311 @@
|
||||
"""Agent Operator for AWEL."""
|
||||
|
||||
from abc import ABC
|
||||
from typing import List, Optional, Type
|
||||
|
||||
from dbgpt.core.awel import MapOperator
|
||||
from dbgpt.core.awel.flow import (
|
||||
IOField,
|
||||
OperatorCategory,
|
||||
OperatorType,
|
||||
Parameter,
|
||||
ViewMetadata,
|
||||
)
|
||||
from dbgpt.core.awel.trigger.base import Trigger
|
||||
from dbgpt.core.interface.message import ModelMessageRoleType
|
||||
|
||||
# TODO: Don't dependent on MixinLLMOperator
|
||||
from dbgpt.model.operators.llm_operator import MixinLLMOperator
|
||||
|
||||
from ....util.llm.llm import LLMConfig
|
||||
from ...agent import Agent, AgentGenerateContext, AgentMessage
|
||||
from ...agent_manage import get_agent_manager
|
||||
from ...base_agent import ConversableAgent
|
||||
from .agent_operator_resource import AWELAgent
|
||||
|
||||
|
||||
class BaseAgentOperator:
|
||||
"""The abstract operator for an Agent."""
|
||||
|
||||
SHARE_DATA_KEY_MODEL_NAME = "share_data_key_agent_name"
|
||||
|
||||
def __init__(self, agent: Optional[Agent] = None):
|
||||
"""Create an AgentOperator."""
|
||||
self._agent = agent
|
||||
|
||||
@property
|
||||
def agent(self) -> Agent:
|
||||
"""Return the Agent."""
|
||||
if not self._agent:
|
||||
raise ValueError("agent is not set")
|
||||
return self._agent
|
||||
|
||||
|
||||
class WrappedAgentOperator(
|
||||
BaseAgentOperator, MapOperator[AgentGenerateContext, AgentGenerateContext], ABC
|
||||
):
|
||||
"""The Agent operator.
|
||||
|
||||
Wrap the agent and trigger the agent to generate a reply.
|
||||
"""
|
||||
|
||||
def __init__(self, agent: Agent, **kwargs):
|
||||
"""Create an WrappedAgentOperator."""
|
||||
super().__init__(agent=agent)
|
||||
MapOperator.__init__(self, **kwargs)
|
||||
|
||||
async def map(self, input_value: AgentGenerateContext) -> AgentGenerateContext:
|
||||
"""Trigger agent to generate a reply."""
|
||||
now_rely_messages: List[AgentMessage] = []
|
||||
if not input_value.message:
|
||||
raise ValueError("The message is empty.")
|
||||
input_message = input_value.message.copy()
|
||||
|
||||
# Isolate the message delivery mechanism and pass it to the operator
|
||||
_goal = self.agent.name if self.agent.name else self.agent.role
|
||||
current_goal = f"[{_goal}]:"
|
||||
|
||||
if input_message.content:
|
||||
current_goal += input_message.content
|
||||
input_message.current_goal = current_goal
|
||||
|
||||
# What was received was the User message
|
||||
human_message = input_message.copy()
|
||||
human_message.role = ModelMessageRoleType.HUMAN
|
||||
now_rely_messages.append(human_message)
|
||||
|
||||
# Send a message (no reply required) and pass the message content
|
||||
now_message = input_message
|
||||
if input_value.rely_messages and len(input_value.rely_messages) > 0:
|
||||
now_message = input_value.rely_messages[-1]
|
||||
if not input_value.sender:
|
||||
raise ValueError("The sender is empty.")
|
||||
await input_value.sender.send(
|
||||
now_message, self.agent, input_value.reviewer, False
|
||||
)
|
||||
|
||||
agent_reply_message = await self.agent.generate_reply(
|
||||
received_message=input_message,
|
||||
sender=input_value.sender,
|
||||
reviewer=input_value.reviewer,
|
||||
rely_messages=input_value.rely_messages,
|
||||
)
|
||||
is_success = agent_reply_message.success
|
||||
|
||||
if not is_success:
|
||||
raise ValueError(
|
||||
f"The task failed at step {self.agent.role} and the attempt "
|
||||
f"to repair it failed. The final reason for "
|
||||
f"failure:{agent_reply_message.content}!"
|
||||
)
|
||||
|
||||
# What is sent is an AI message
|
||||
ai_message = agent_reply_message.copy()
|
||||
ai_message.role = ModelMessageRoleType.AI
|
||||
|
||||
now_rely_messages.append(ai_message)
|
||||
|
||||
# Handle user goals and outcome dependencies
|
||||
return AgentGenerateContext(
|
||||
message=input_message,
|
||||
sender=self.agent,
|
||||
reviewer=input_value.reviewer,
|
||||
# Default single step transfer of information
|
||||
rely_messages=now_rely_messages,
|
||||
silent=input_value.silent,
|
||||
)
|
||||
|
||||
|
||||
class AWELAgentOperator(
|
||||
MixinLLMOperator, MapOperator[AgentGenerateContext, AgentGenerateContext]
|
||||
):
|
||||
"""The Agent operator for AWEL."""
|
||||
|
||||
metadata = ViewMetadata(
|
||||
label="AWEL Agent Operator",
|
||||
name="agent_operator",
|
||||
category=OperatorCategory.AGENT,
|
||||
description="The Agent operator.",
|
||||
parameters=[
|
||||
Parameter.build_from(
|
||||
"Agent",
|
||||
"awel_agent",
|
||||
AWELAgent,
|
||||
description="The dbgpt agent.",
|
||||
),
|
||||
],
|
||||
inputs=[
|
||||
IOField.build_from(
|
||||
"Agent Operator Request",
|
||||
"agent_operator_request",
|
||||
AgentGenerateContext,
|
||||
"The Agent Operator request.",
|
||||
)
|
||||
],
|
||||
outputs=[
|
||||
IOField.build_from(
|
||||
"Agent Operator Output",
|
||||
"agent_operator_output",
|
||||
AgentGenerateContext,
|
||||
description="The Agent Operator output.",
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
def __init__(self, awel_agent: AWELAgent, **kwargs):
|
||||
"""Create an AgentOperator."""
|
||||
MixinLLMOperator.__init__(self)
|
||||
MapOperator.__init__(self, **kwargs)
|
||||
self.awel_agent = awel_agent
|
||||
|
||||
async def map(
|
||||
self,
|
||||
input_value: AgentGenerateContext,
|
||||
) -> AgentGenerateContext:
|
||||
"""Trigger agent to generate a reply."""
|
||||
if not input_value.message:
|
||||
raise ValueError("The message is empty.")
|
||||
input_message = input_value.message.copy()
|
||||
agent = await self.get_agent(input_value)
|
||||
if agent.fixed_subgoal and len(agent.fixed_subgoal) > 0:
|
||||
# Isolate the message delivery mechanism and pass it to the operator
|
||||
current_goal = f"[{agent.name if agent.name else agent.role}]:"
|
||||
if agent.fixed_subgoal:
|
||||
current_goal += agent.fixed_subgoal
|
||||
input_message.current_goal = current_goal
|
||||
input_message.content = agent.fixed_subgoal
|
||||
else:
|
||||
# Isolate the message delivery mechanism and pass it to the operator
|
||||
current_goal = f"[{agent.name if agent.name else agent.role}]:"
|
||||
if input_message.content:
|
||||
current_goal += input_message.content
|
||||
input_message.current_goal = current_goal
|
||||
|
||||
now_rely_messages: List[AgentMessage] = []
|
||||
# What was received was the User message
|
||||
human_message = input_message.copy()
|
||||
human_message.role = ModelMessageRoleType.HUMAN
|
||||
now_rely_messages.append(human_message)
|
||||
|
||||
# Send a message (no reply required) and pass the message content
|
||||
|
||||
now_message = input_message
|
||||
if input_value.rely_messages and len(input_value.rely_messages) > 0:
|
||||
now_message = input_value.rely_messages[-1]
|
||||
sender = input_value.sender
|
||||
if not sender:
|
||||
raise ValueError("The sender is empty.")
|
||||
await sender.send(now_message, agent, input_value.reviewer, False)
|
||||
|
||||
agent_reply_message = await agent.generate_reply(
|
||||
received_message=input_message,
|
||||
sender=sender,
|
||||
reviewer=input_value.reviewer,
|
||||
rely_messages=input_value.rely_messages,
|
||||
)
|
||||
|
||||
is_success = agent_reply_message.success
|
||||
|
||||
if not is_success:
|
||||
raise ValueError(
|
||||
f"The task failed at step {agent.role} and the attempt to "
|
||||
f"repair it failed. The final reason for "
|
||||
f"failure:{agent_reply_message.content}!"
|
||||
)
|
||||
|
||||
# What is sent is an AI message
|
||||
ai_message: AgentMessage = agent_reply_message.copy()
|
||||
ai_message.role = ModelMessageRoleType.AI
|
||||
now_rely_messages.append(ai_message)
|
||||
|
||||
# Handle user goals and outcome dependencies
|
||||
return AgentGenerateContext(
|
||||
message=input_message,
|
||||
sender=agent,
|
||||
reviewer=input_value.reviewer,
|
||||
# Default single step transfer of information
|
||||
rely_messages=now_rely_messages,
|
||||
silent=input_value.silent,
|
||||
memory=input_value.memory.structure_clone() if input_value.memory else None,
|
||||
agent_context=input_value.agent_context,
|
||||
resource_loader=input_value.resource_loader,
|
||||
llm_client=input_value.llm_client,
|
||||
round_index=agent.consecutive_auto_reply_counter,
|
||||
)
|
||||
|
||||
async def get_agent(
|
||||
self,
|
||||
input_value: AgentGenerateContext,
|
||||
) -> ConversableAgent:
|
||||
"""Build the agent."""
|
||||
# agent build
|
||||
agent_cls: Type[ConversableAgent] = get_agent_manager().get_by_name(
|
||||
self.awel_agent.agent_profile
|
||||
)
|
||||
llm_config = self.awel_agent.llm_config
|
||||
|
||||
if not llm_config:
|
||||
if input_value.llm_client:
|
||||
llm_config = LLMConfig(llm_client=input_value.llm_client)
|
||||
else:
|
||||
llm_config = LLMConfig(llm_client=self.llm_client)
|
||||
else:
|
||||
if not llm_config.llm_client:
|
||||
if input_value.llm_client:
|
||||
llm_config.llm_client = input_value.llm_client
|
||||
else:
|
||||
llm_config.llm_client = self.llm_client
|
||||
|
||||
kwargs = {}
|
||||
if self.awel_agent.role_name:
|
||||
kwargs["name"] = self.awel_agent.role_name
|
||||
if self.awel_agent.fixed_subgoal:
|
||||
kwargs["fixed_subgoal"] = self.awel_agent.fixed_subgoal
|
||||
|
||||
agent = (
|
||||
await agent_cls(**kwargs)
|
||||
.bind(input_value.memory)
|
||||
.bind(llm_config)
|
||||
.bind(input_value.agent_context)
|
||||
.bind(self.awel_agent.resources)
|
||||
.bind(input_value.resource_loader)
|
||||
.build()
|
||||
)
|
||||
|
||||
return agent
|
||||
|
||||
|
||||
class AgentDummyTrigger(Trigger):
|
||||
"""Http trigger for AWEL.
|
||||
|
||||
Http trigger is used to trigger a DAG by http request.
|
||||
"""
|
||||
|
||||
metadata = ViewMetadata(
|
||||
label="Agent Trigger",
|
||||
name="agent_trigger",
|
||||
category=OperatorCategory.AGENT,
|
||||
operator_type=OperatorType.INPUT,
|
||||
description="Trigger your workflow by agent",
|
||||
inputs=[],
|
||||
parameters=[],
|
||||
outputs=[
|
||||
IOField.build_from(
|
||||
"Agent Operator Context",
|
||||
"agent_operator_context",
|
||||
AgentGenerateContext,
|
||||
description="The Agent Operator output.",
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Initialize a HttpTrigger."""
|
||||
super().__init__(**kwargs)
|
||||
|
||||
async def trigger(self, **kwargs) -> None:
|
||||
"""Trigger the DAG. Not used in HttpTrigger."""
|
||||
raise NotImplementedError("Dummy trigger does not support trigger.")
|
209
dbgpt/agent/core/plan/awel/agent_operator_resource.py
Normal file
209
dbgpt/agent/core/plan/awel/agent_operator_resource.py
Normal file
@@ -0,0 +1,209 @@
|
||||
"""The AWEL Agent Operator Resource."""
|
||||
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from dbgpt._private.pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
from dbgpt.core import LLMClient
|
||||
from dbgpt.core.awel.flow import (
|
||||
FunctionDynamicOptions,
|
||||
OptionValue,
|
||||
Parameter,
|
||||
ResourceCategory,
|
||||
register_resource,
|
||||
)
|
||||
|
||||
from ....resource.resource_api import AgentResource, ResourceType
|
||||
from ....util.llm.llm import LLMConfig, LLMStrategyType
|
||||
from ...agent_manage import get_agent_manager
|
||||
|
||||
|
||||
@register_resource(
|
||||
label="AWEL Agent Resource",
|
||||
name="agent_operator_resource",
|
||||
description="The Agent Resource.",
|
||||
category=ResourceCategory.AGENT,
|
||||
parameters=[
|
||||
Parameter.build_from(
|
||||
label="Agent Resource Type",
|
||||
name="agent_resource_type",
|
||||
type=str,
|
||||
optional=True,
|
||||
default=None,
|
||||
options=[
|
||||
OptionValue(label=item.name, name=item.value, value=item.value)
|
||||
for item in ResourceType
|
||||
],
|
||||
),
|
||||
Parameter.build_from(
|
||||
label="Agent Resource Name",
|
||||
name="agent_resource_name",
|
||||
type=str,
|
||||
optional=True,
|
||||
default=None,
|
||||
description="The agent resource name.",
|
||||
),
|
||||
Parameter.build_from(
|
||||
label="Agent Resource Value",
|
||||
name="agent_resource_value",
|
||||
type=str,
|
||||
optional=True,
|
||||
default=None,
|
||||
description="The agent resource value.",
|
||||
),
|
||||
],
|
||||
alias=[
|
||||
"dbgpt.serve.agent.team.layout.agent_operator_resource.AwelAgentResource",
|
||||
"dbgpt.agent.plan.awel.agent_operator_resource.AWELAgentResource",
|
||||
],
|
||||
)
|
||||
class AWELAgentResource(AgentResource):
|
||||
"""AWEL Agent Resource."""
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def pre_fill(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Pre fill the agent ResourceType."""
|
||||
if not isinstance(values, dict):
|
||||
return values
|
||||
name = values.pop("agent_resource_name")
|
||||
type = values.pop("agent_resource_type")
|
||||
value = values.pop("agent_resource_value")
|
||||
|
||||
values["name"] = name
|
||||
values["type"] = ResourceType(type)
|
||||
values["value"] = value
|
||||
|
||||
return values
|
||||
|
||||
|
||||
@register_resource(
|
||||
label="AWEL Agent LLM Config",
|
||||
name="agent_operator_llm_config",
|
||||
description="The Agent LLM Config.",
|
||||
category=ResourceCategory.AGENT,
|
||||
parameters=[
|
||||
Parameter.build_from(
|
||||
"LLM Client",
|
||||
"llm_client",
|
||||
LLMClient,
|
||||
optional=True,
|
||||
default=None,
|
||||
description="The LLM Client.",
|
||||
),
|
||||
Parameter.build_from(
|
||||
label="Agent LLM Strategy",
|
||||
name="llm_strategy",
|
||||
type=str,
|
||||
optional=True,
|
||||
default=None,
|
||||
options=[
|
||||
OptionValue(label=item.name, name=item.value, value=item.value)
|
||||
for item in LLMStrategyType
|
||||
],
|
||||
description="The Agent LLM Strategy.",
|
||||
),
|
||||
Parameter.build_from(
|
||||
label="Agent LLM Strategy Value",
|
||||
name="strategy_context",
|
||||
type=str,
|
||||
optional=True,
|
||||
default=None,
|
||||
description="The agent LLM Strategy Value.",
|
||||
),
|
||||
],
|
||||
alias=[
|
||||
"dbgpt.serve.agent.team.layout.agent_operator_resource.AwelAgentConfig",
|
||||
"dbgpt.agent.plan.awel.agent_operator_resource.AWELAgentConfig",
|
||||
],
|
||||
)
|
||||
class AWELAgentConfig(LLMConfig):
|
||||
"""AWEL Agent Config."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def _agent_resource_option_values() -> List[OptionValue]:
|
||||
return [
|
||||
OptionValue(label=item["name"], name=item["name"], value=item["name"])
|
||||
for item in get_agent_manager().list_agents()
|
||||
]
|
||||
|
||||
|
||||
@register_resource(
|
||||
label="AWEL Layout Agent",
|
||||
name="agent_operator_agent",
|
||||
description="The Agent to build the Agent Operator.",
|
||||
category=ResourceCategory.AGENT,
|
||||
parameters=[
|
||||
Parameter.build_from(
|
||||
label="Agent Profile",
|
||||
name="agent_profile",
|
||||
type=str,
|
||||
description="Which agent want use.",
|
||||
options=FunctionDynamicOptions(func=_agent_resource_option_values),
|
||||
),
|
||||
Parameter.build_from(
|
||||
label="Role Name",
|
||||
name="role_name",
|
||||
type=str,
|
||||
optional=True,
|
||||
default=None,
|
||||
description="The agent role name.",
|
||||
),
|
||||
Parameter.build_from(
|
||||
label="Fixed Gogal",
|
||||
name="fixed_subgoal",
|
||||
type=str,
|
||||
optional=True,
|
||||
default=None,
|
||||
description="The agent fixed gogal.",
|
||||
),
|
||||
Parameter.build_from(
|
||||
label="Agent Resource",
|
||||
name="agent_resource",
|
||||
type=AWELAgentResource,
|
||||
optional=True,
|
||||
default=None,
|
||||
description="The agent resource.",
|
||||
),
|
||||
Parameter.build_from(
|
||||
label="Agent LLM Config",
|
||||
name="agent_llm_Config",
|
||||
type=AWELAgentConfig,
|
||||
optional=True,
|
||||
default=None,
|
||||
description="The agent llm config.",
|
||||
),
|
||||
],
|
||||
alias=[
|
||||
"dbgpt.serve.agent.team.layout.agent_operator_resource.AwelAgent",
|
||||
"dbgpt.agent.plan.awel.agent_operator_resource.AWELAgent",
|
||||
],
|
||||
)
|
||||
class AWELAgent(BaseModel):
|
||||
"""AWEL Agent."""
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
agent_profile: str
|
||||
role_name: Optional[str] = None
|
||||
llm_config: Optional[LLMConfig] = None
|
||||
resources: List[AgentResource] = Field(default_factory=list)
|
||||
fixed_subgoal: Optional[str] = None
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def pre_fill(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Pre fill the agent ResourceType."""
|
||||
if not isinstance(values, dict):
|
||||
return values
|
||||
resource = values.pop("agent_resource")
|
||||
llm_config = values.pop("agent_llm_Config")
|
||||
|
||||
if resource is not None:
|
||||
values["resources"] = [resource]
|
||||
|
||||
if llm_config is not None:
|
||||
values["llm_config"] = llm_config
|
||||
|
||||
return values
|
268
dbgpt/agent/core/plan/awel/team_awel_layout.py
Normal file
268
dbgpt/agent/core/plan/awel/team_awel_layout.py
Normal file
@@ -0,0 +1,268 @@
|
||||
"""The manager of the team for the AWEL layout."""
|
||||
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Optional, cast
|
||||
|
||||
from dbgpt._private.config import Config
|
||||
from dbgpt._private.pydantic import (
|
||||
BaseModel,
|
||||
ConfigDict,
|
||||
Field,
|
||||
model_to_dict,
|
||||
validator,
|
||||
)
|
||||
from dbgpt.core.awel import DAG
|
||||
from dbgpt.core.awel.dag.dag_manager import DAGManager
|
||||
|
||||
from ...action.base import ActionOutput
|
||||
from ...agent import Agent, AgentGenerateContext, AgentMessage
|
||||
from ...base_team import ManagerAgent
|
||||
from ...profile import DynConfig, ProfileConfig
|
||||
from .agent_operator import AWELAgentOperator, WrappedAgentOperator
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AWELTeamContext(BaseModel):
|
||||
"""The context of the team for the AWEL layout."""
|
||||
|
||||
dag_id: str = Field(
|
||||
...,
|
||||
description="The unique id of dag",
|
||||
examples=["flow_dag_testflow_66d8e9d6-f32e-4540-a5bd-ea0648145d0e"],
|
||||
)
|
||||
uid: str = Field(
|
||||
default=None,
|
||||
description="The unique id of flow",
|
||||
examples=["66d8e9d6-f32e-4540-a5bd-ea0648145d0e"],
|
||||
)
|
||||
name: Optional[str] = Field(
|
||||
default=None,
|
||||
description="The name of dag",
|
||||
)
|
||||
label: Optional[str] = Field(
|
||||
default=None,
|
||||
description="The label of dag",
|
||||
)
|
||||
version: Optional[str] = Field(
|
||||
default=None,
|
||||
description="The version of dag",
|
||||
)
|
||||
description: Optional[str] = Field(
|
||||
default=None,
|
||||
description="The description of dag",
|
||||
)
|
||||
editable: bool = Field(
|
||||
default=False,
|
||||
description="is the dag is editable",
|
||||
examples=[True, False],
|
||||
)
|
||||
state: Optional[str] = Field(
|
||||
default=None,
|
||||
description="The state of dag",
|
||||
)
|
||||
user_name: Optional[str] = Field(
|
||||
default=None,
|
||||
description="The owner of current dag",
|
||||
)
|
||||
sys_code: Optional[str] = Field(
|
||||
default=None,
|
||||
description="The system code of current dag",
|
||||
)
|
||||
flow_category: Optional[str] = Field(
|
||||
default="common",
|
||||
description="The flow category of current dag",
|
||||
)
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert the object to a dictionary."""
|
||||
return model_to_dict(self)
|
||||
|
||||
|
||||
class AWELBaseManager(ManagerAgent, ABC):
|
||||
"""AWEL base manager."""
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
profile: ProfileConfig = ProfileConfig(
|
||||
name="AWELBaseManager",
|
||||
role=DynConfig(
|
||||
"PlanManager", category="agent", key="dbgpt_agent_plan_awel_profile_name"
|
||||
),
|
||||
goal=DynConfig(
|
||||
"Promote and solve user problems according to the process arranged "
|
||||
"by AWEL.",
|
||||
category="agent",
|
||||
key="dbgpt_agent_plan_awel_profile_goal",
|
||||
),
|
||||
desc=DynConfig(
|
||||
"Promote and solve user problems according to the process arranged "
|
||||
"by AWEL.",
|
||||
category="agent",
|
||||
key="dbgpt_agent_plan_awel_profile_desc",
|
||||
),
|
||||
)
|
||||
|
||||
async def _a_process_received_message(self, message: AgentMessage, sender: Agent):
|
||||
"""Process the received message."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_dag(self) -> DAG:
|
||||
"""Get the DAG of the manager."""
|
||||
|
||||
async def act(
|
||||
self,
|
||||
message: Optional[str],
|
||||
sender: Optional[Agent] = None,
|
||||
reviewer: Optional[Agent] = None,
|
||||
**kwargs,
|
||||
) -> Optional[ActionOutput]:
|
||||
"""Perform the action."""
|
||||
try:
|
||||
agent_dag = self.get_dag()
|
||||
last_node: AWELAgentOperator = cast(
|
||||
AWELAgentOperator, agent_dag.leaf_nodes[0]
|
||||
)
|
||||
|
||||
start_message_context: AgentGenerateContext = AgentGenerateContext(
|
||||
message=AgentMessage(content=message, current_goal=message),
|
||||
sender=sender,
|
||||
reviewer=reviewer,
|
||||
memory=self.memory.structure_clone(),
|
||||
agent_context=self.agent_context,
|
||||
resource_loader=self.resource_loader,
|
||||
llm_client=self.not_null_llm_config.llm_client,
|
||||
)
|
||||
final_generate_context: AgentGenerateContext = await last_node.call(
|
||||
call_data=start_message_context
|
||||
)
|
||||
last_message = final_generate_context.rely_messages[-1]
|
||||
|
||||
last_agent = await last_node.get_agent(final_generate_context)
|
||||
if final_generate_context.round_index is not None:
|
||||
last_agent.consecutive_auto_reply_counter = (
|
||||
final_generate_context.round_index
|
||||
)
|
||||
if not sender:
|
||||
raise ValueError("sender is required!")
|
||||
await last_agent.send(
|
||||
last_message, sender, start_message_context.reviewer, False
|
||||
)
|
||||
|
||||
view_message: Optional[str] = None
|
||||
if last_message.action_report:
|
||||
view_message = last_message.action_report.get("view", None)
|
||||
|
||||
return ActionOutput(
|
||||
content=last_message.content,
|
||||
view=view_message,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(f"DAG run failed!{str(e)}")
|
||||
|
||||
return ActionOutput(
|
||||
is_exe_success=False,
|
||||
content=f"Failed to complete goal! {str(e)}",
|
||||
)
|
||||
|
||||
|
||||
class WrappedAWELLayoutManager(AWELBaseManager):
|
||||
"""The manager of the team for the AWEL layout.
|
||||
|
||||
Receives a DAG or builds a DAG from the agents.
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
dag: Optional[DAG] = Field(None, description="The DAG of the manager")
|
||||
|
||||
def get_dag(self) -> DAG:
|
||||
"""Get the DAG of the manager."""
|
||||
if self.dag:
|
||||
return self.dag
|
||||
conv_id = self.not_null_agent_context.conv_id
|
||||
last_node: Optional[WrappedAgentOperator] = None
|
||||
with DAG(
|
||||
f"layout_agents_{self.not_null_agent_context.gpts_app_name}_{conv_id}"
|
||||
) as dag:
|
||||
for agent in self.agents:
|
||||
now_node = WrappedAgentOperator(agent=agent)
|
||||
if not last_node:
|
||||
last_node = now_node
|
||||
else:
|
||||
last_node >> now_node
|
||||
last_node = now_node
|
||||
self.dag = dag
|
||||
return dag
|
||||
|
||||
async def act(
|
||||
self,
|
||||
message: Optional[str],
|
||||
sender: Optional[Agent] = None,
|
||||
reviewer: Optional[Agent] = None,
|
||||
**kwargs,
|
||||
) -> Optional[ActionOutput]:
|
||||
"""Perform the action."""
|
||||
try:
|
||||
dag = self.get_dag()
|
||||
last_node: WrappedAgentOperator = cast(
|
||||
WrappedAgentOperator, dag.leaf_nodes[0]
|
||||
)
|
||||
start_message_context: AgentGenerateContext = AgentGenerateContext(
|
||||
message=AgentMessage(content=message, current_goal=message),
|
||||
sender=self,
|
||||
reviewer=reviewer,
|
||||
)
|
||||
final_generate_context: AgentGenerateContext = await last_node.call(
|
||||
call_data=start_message_context
|
||||
)
|
||||
last_message = final_generate_context.rely_messages[-1]
|
||||
|
||||
last_agent = last_node.agent
|
||||
await last_agent.send(
|
||||
last_message,
|
||||
self,
|
||||
start_message_context.reviewer,
|
||||
False,
|
||||
)
|
||||
|
||||
view_message: Optional[str] = None
|
||||
if last_message.action_report:
|
||||
view_message = last_message.action_report.get("view", None)
|
||||
|
||||
return ActionOutput(
|
||||
content=last_message.content,
|
||||
view=view_message,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(f"DAG run failed!{str(e)}")
|
||||
|
||||
return ActionOutput(
|
||||
is_exe_success=False,
|
||||
content=f"Failed to complete goal! {str(e)}",
|
||||
)
|
||||
|
||||
|
||||
class DefaultAWELLayoutManager(AWELBaseManager):
|
||||
"""The manager of the team for the AWEL layout."""
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
dag: AWELTeamContext = Field(...)
|
||||
|
||||
@validator("dag")
|
||||
def check_dag(cls, value):
|
||||
"""Check the DAG of the manager."""
|
||||
assert value is not None and value != "", "dag must not be empty"
|
||||
return value
|
||||
|
||||
def get_dag(self) -> DAG:
|
||||
"""Get the DAG of the manager."""
|
||||
cfg = Config()
|
||||
_dag_manager = DAGManager.get_instance(cfg.SYSTEM_APP) # type: ignore
|
||||
agent_dag: Optional[DAG] = _dag_manager.get_dag(alias_name=self.dag.uid)
|
||||
if agent_dag is None:
|
||||
raise ValueError(f"The configured flow cannot be found![{self.dag.name}]")
|
||||
return agent_dag
|
Reference in New Issue
Block a user