Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions aixplain/factories/agent_factory/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ def create(
raise Exception(error_msg)
return agent

@classmethod
def create_from_dict(cls, dict: Dict) -> Agent:
"""Create an agent from a dictionary."""
agent = Agent.from_dict(dict)
agent.validate(raise_exception=True)
agent.url = urljoin(config.BACKEND_URL, f"sdk/agents/{agent.id}/run")
return agent

@classmethod
def create_task(
cls, name: Text, description: Text, expected_output: Text, dependencies: Optional[List[Text]] = None
Expand Down
8 changes: 8 additions & 0 deletions aixplain/factories/team_agent_factory/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,14 @@ def create(
raise Exception(error_msg)
return team_agent

@classmethod
def create_from_dict(cls, dict: Dict) -> TeamAgent:
"""Create a team agent from a dictionary."""
team_agent = TeamAgent.from_dict(dict)
team_agent.validate(raise_exception=True)
team_agent.url = urljoin(config.BACKEND_URL, f"sdk/agent-communities/{team_agent.id}/run")
return team_agent

@classmethod
def list(cls) -> Dict:
"""List all agents available in the platform."""
Expand Down
76 changes: 76 additions & 0 deletions aixplain/modules/agent/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,84 @@ def to_dict(self) -> Dict:
]
if self.llm is not None
else [],
"cost": self.cost,
"api_key": self.api_key,
}

@classmethod
def from_dict(cls, data: Dict) -> "Agent":
"""Create an Agent instance from a dictionary representation.

Args:
data: Dictionary containing Agent parameters

Returns:
Agent instance
"""
from aixplain.factories.agent_factory.utils import build_tool
from aixplain.enums import AssetStatus
from aixplain.modules.agent_task import AgentTask

# Extract tools from assets using proper tool building
tools = []
if "assets" in data:
for asset_data in data["assets"]:
try:
tool = build_tool(asset_data)
tools.append(tool)
except Exception as e:
# Log warning but continue processing other tools
import logging

logging.warning(f"Failed to build tool from asset data: {e}")

# Extract tasks using from_dict method
tasks = []
if "tasks" in data:
for task_data in data["tasks"]:
tasks.append(AgentTask.from_dict(task_data))

# Extract LLM from tools section (main LLM info)
llm = None
if "tools" in data and data["tools"]:
llm_tool = next((tool for tool in data["tools"] if tool.get("type") == "llm"), None)
if llm_tool and llm_tool.get("parameters"):
# Reconstruct LLM from parameters if available
from aixplain.factories.model_factory import ModelFactory

try:
llm = ModelFactory.get(data.get("llmId", "6646261c6eb563165658bbb1"))
if llm_tool.get("parameters"):
# Apply stored parameters to LLM
llm.set_parameters(llm_tool["parameters"])
except Exception:
# If LLM loading fails, llm remains None and llm_id will be used
pass

# Extract status
status = AssetStatus.DRAFT
if "status" in data:
if isinstance(data["status"], str):
status = AssetStatus(data["status"])
else:
status = data["status"]

return cls(
id=data["id"],
name=data["name"],
description=data["description"],
instructions=data.get("role"),
tools=tools,
llm_id=data.get("llmId", "6646261c6eb563165658bbb1"),
llm=llm,
api_key=data.get("api_key"),
supplier=data.get("supplier", "aiXplain"),
version=data.get("version"),
cost=data.get("cost"),
status=status,
tasks=tasks,
)

def delete(self) -> None:
"""Delete Agent service"""
try:
Expand Down
17 changes: 17 additions & 0 deletions aixplain/modules/agent/agent_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,20 @@ def to_dict(self):
if isinstance(dependency, AgentTask):
agent_task_dict["dependencies"][i] = dependency.name
return agent_task_dict

@classmethod
def from_dict(cls, data: dict) -> "AgentTask":
"""Create an AgentTask instance from a dictionary representation.

Args:
data: Dictionary containing AgentTask parameters

Returns:
AgentTask instance
"""
return cls(
name=data["name"],
description=data["description"],
expected_output=data["expectedOutput"],
dependencies=data.get("dependencies", None),
)
129 changes: 125 additions & 4 deletions aixplain/modules/team_agent/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,29 @@ def delete(self) -> None:
logging.error(message)
raise Exception(f"{message}")

def _serialize_agent(self, agent, idx: int) -> Dict:
"""Serialize an agent for the to_dict method."""
base_dict = {"assetId": agent.id, "number": idx, "type": "AGENT", "label": "AGENT"}

# Try to get additional data from agent's to_dict method
try:
if hasattr(agent, "to_dict") and callable(getattr(agent, "to_dict")):
agent_dict = agent.to_dict()
# Ensure it's actually a dictionary and not a Mock or other object
if isinstance(agent_dict, dict) and hasattr(agent_dict, "items"):
try:
# Add all fields except 'id' to avoid duplication with 'assetId'
additional_data = {k: v for k, v in agent_dict.items() if k not in ["id"]}
base_dict.update(additional_data)
except (TypeError, AttributeError):
# If items() doesn't work or iteration fails, skip the additional data
pass
except Exception:
# If anything goes wrong, just use the base dictionary
pass

return base_dict

def to_dict(self) -> Dict:
if self.use_mentalist:
planner_id = self.mentalist_llm.id if self.mentalist_llm else self.llm_id
Expand All @@ -343,9 +366,7 @@ def to_dict(self) -> Dict:
return {
"id": self.id,
"name": self.name,
"agents": [
{"assetId": agent.id, "number": idx, "type": "AGENT", "label": "AGENT"} for idx, agent in enumerate(self.agents)
],
"agents": [self._serialize_agent(agent, idx) for idx, agent in enumerate(self.agents)],
"links": [],
"description": self.description,
"llmId": self.llm.id if self.llm else self.llm_id,
Expand All @@ -359,6 +380,107 @@ def to_dict(self) -> Dict:
"role": self.instructions,
}

@classmethod
def from_dict(cls, data: Dict) -> "TeamAgent":
"""Create a TeamAgent instance from a dictionary representation.

Args:
data: Dictionary containing TeamAgent parameters

Returns:
TeamAgent instance
"""
from aixplain.factories.agent_factory import AgentFactory
from aixplain.factories.model_factory import ModelFactory
from aixplain.enums import AssetStatus
from aixplain.modules.team_agent import Inspector, InspectorTarget

# Extract agents from agents list using proper agent loading
agents = []
if "agents" in data:
for agent_data in data["agents"]:
if "assetId" in agent_data:
try:
# Load agent using AgentFactory
agent = AgentFactory.get(agent_data["assetId"])
agents.append(agent)
except Exception as e:
# Log warning but continue processing other agents
import logging

logging.warning(f"Failed to load agent {agent_data['assetId']}: {e}")

# Extract inspectors using proper model validation
inspectors = []
if "inspectors" in data:
for inspector_data in data["inspectors"]:
try:
if hasattr(Inspector, "model_validate"):
inspectors.append(Inspector.model_validate(inspector_data))
else:
inspectors.append(Inspector(**inspector_data))
except Exception as e:
import logging

logging.warning(f"Failed to create inspector from data: {e}")

# Extract inspector targets
inspector_targets = [InspectorTarget.STEPS] # default
if "inspectorTargets" in data:
inspector_targets = [InspectorTarget(target) for target in data["inspectorTargets"]]

# Extract status
status = AssetStatus.DRAFT
if "status" in data:
if isinstance(data["status"], str):
status = AssetStatus(data["status"])
else:
status = data["status"]

# Extract LLM instances using proper model loading
llm = None
supervisor_llm = None
mentalist_llm = None

try:
if "llmId" in data:
llm = ModelFactory.get(data["llmId"])
except Exception:
pass # llm remains None, will use llm_id

try:
if "supervisorId" in data and data["supervisorId"] != data.get("llmId"):
supervisor_llm = ModelFactory.get(data["supervisorId"])
except Exception:
pass # supervisor_llm remains None

try:
if "plannerId" in data and data["plannerId"]:
mentalist_llm = ModelFactory.get(data["plannerId"])
except Exception:
pass # mentalist_llm remains None

# Determine if mentalist is used
use_mentalist = data.get("plannerId") is not None

return cls(
id=data["id"],
name=data["name"],
agents=agents,
description=data.get("description", ""),
llm_id=data.get("llmId", "6646261c6eb563165658bbb1"),
llm=llm,
supervisor_llm=supervisor_llm,
mentalist_llm=mentalist_llm,
supplier=data.get("supplier", "aiXplain"),
version=data.get("version"),
use_mentalist=use_mentalist,
status=status,
instructions=data.get("role"),
inspectors=inspectors,
inspector_targets=inspector_targets,
)

def _validate(self) -> None:
from aixplain.utils.llm_utils import get_llm_instance

Expand Down Expand Up @@ -429,4 +551,3 @@ def update(self) -> None:

def __repr__(self):
return f"TeamAgent: {self.name} (id={self.id})"

Loading