Add dynamic analyst runtime updates and deployment guides
This commit is contained in:
@@ -13,8 +13,11 @@ as described in the Dynamic Team Architecture.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any, Dict, List, Optional, Callable
|
||||
from dataclasses import asdict
|
||||
|
||||
from agentscope.message import TextBlock
|
||||
from agentscope.tool import ToolResponse
|
||||
|
||||
from backend.agents.dynamic_team_types import (
|
||||
AnalystPersona,
|
||||
@@ -22,7 +25,7 @@ from backend.agents.dynamic_team_types import (
|
||||
CreateAnalystResult,
|
||||
AnalystTypeInfo,
|
||||
)
|
||||
from backend.config.constants import ANALYST_TYPES
|
||||
from backend.config.constants import ANALYST_TYPES, AGENT_CONFIG
|
||||
|
||||
|
||||
# Type alias for callbacks set by pipeline
|
||||
@@ -30,6 +33,14 @@ CreateAnalystCallback = Callable[[str, str, Optional[AnalystConfig]], str]
|
||||
RemoveAnalystCallback = Callable[[str], str]
|
||||
|
||||
|
||||
def _to_tool_response(payload: Any) -> ToolResponse:
|
||||
if isinstance(payload, str):
|
||||
text = payload
|
||||
else:
|
||||
text = json.dumps(payload, ensure_ascii=False, indent=2, default=str)
|
||||
return ToolResponse(content=[TextBlock(type="text", text=text)])
|
||||
|
||||
|
||||
class DynamicTeamController:
|
||||
"""Controller for dynamic analyst team management.
|
||||
|
||||
@@ -296,6 +307,23 @@ class DynamicTeamController:
|
||||
Dict with analyst configuration and status
|
||||
"""
|
||||
config = self._instance_configs.get(agent_id)
|
||||
current_analysts = self._get_analysts_callback() if self._get_analysts_callback else []
|
||||
analyst_map = {
|
||||
(getattr(agent, "name", None) or getattr(agent, "agent_id", None)): agent
|
||||
for agent in current_analysts
|
||||
}
|
||||
if agent_id in analyst_map and not config:
|
||||
builtin_meta = AGENT_CONFIG.get(agent_id, {})
|
||||
return {
|
||||
"found": True,
|
||||
"agent_id": agent_id,
|
||||
"name": builtin_meta.get("name") or agent_id,
|
||||
"type": agent_id,
|
||||
"is_custom": False,
|
||||
"is_clone": False,
|
||||
"is_builtin": True,
|
||||
"message": f"Built-in analyst '{agent_id}' is active",
|
||||
}
|
||||
if not config:
|
||||
return {
|
||||
"found": False,
|
||||
@@ -310,6 +338,7 @@ class DynamicTeamController:
|
||||
"is_custom": config.persona is not None,
|
||||
"is_clone": config.parent_id is not None,
|
||||
"parent_id": config.parent_id,
|
||||
"is_builtin": False,
|
||||
}
|
||||
|
||||
def register_analyst_type(
|
||||
@@ -372,13 +401,26 @@ class DynamicTeamController:
|
||||
Dict with team composition information
|
||||
"""
|
||||
analysts = []
|
||||
for agent_id, config in self._instance_configs.items():
|
||||
current_analysts = self._get_analysts_callback() if self._get_analysts_callback else []
|
||||
instance_configs = self._instance_configs
|
||||
|
||||
for agent in current_analysts:
|
||||
agent_id = getattr(agent, "name", None) or getattr(agent, "agent_id", None)
|
||||
if not agent_id:
|
||||
continue
|
||||
config = instance_configs.get(agent_id)
|
||||
builtin_meta = AGENT_CONFIG.get(agent_id, {})
|
||||
analysts.append({
|
||||
"agent_id": agent_id,
|
||||
"name": config.persona.name if config.persona else agent_id,
|
||||
"type": config.analyst_type,
|
||||
"is_custom": config.persona is not None,
|
||||
"is_clone": config.parent_id is not None,
|
||||
"name": (
|
||||
config.persona.name
|
||||
if config and config.persona and config.persona.name
|
||||
else builtin_meta.get("name") or agent_id
|
||||
),
|
||||
"type": config.analyst_type if config else agent_id,
|
||||
"is_custom": bool(config and config.persona is not None),
|
||||
"is_clone": bool(config and config.parent_id is not None),
|
||||
"is_builtin": config is None,
|
||||
})
|
||||
|
||||
return {
|
||||
@@ -418,91 +460,95 @@ def get_controller() -> Optional[DynamicTeamController]:
|
||||
def create_analyst(
|
||||
agent_id: str,
|
||||
analyst_type: str,
|
||||
name: Optional[str] = None,
|
||||
focus: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
soul_md: Optional[str] = None,
|
||||
agents_md: Optional[str] = None,
|
||||
model_name: Optional[str] = None,
|
||||
) -> Dict[str, Any]:
|
||||
name: str = "",
|
||||
focus: str = "",
|
||||
description: str = "",
|
||||
soul_md: str = "",
|
||||
agents_md: str = "",
|
||||
model_name: str = "",
|
||||
) -> ToolResponse:
|
||||
"""Tool wrapper for create_analyst.
|
||||
|
||||
Note: focus parameter accepts comma-separated string for tool compatibility.
|
||||
"""
|
||||
controller = get_controller()
|
||||
if not controller:
|
||||
return {"success": False, "error": "Dynamic team controller not available"}
|
||||
return _to_tool_response({"success": False, "error": "Dynamic team controller not available"})
|
||||
|
||||
focus_list = [f.strip() for f in focus.split(",")] if focus else None
|
||||
return controller.create_analyst(
|
||||
agent_id=agent_id,
|
||||
analyst_type=analyst_type,
|
||||
name=name,
|
||||
focus=focus_list,
|
||||
description=description,
|
||||
soul_md=soul_md,
|
||||
agents_md=agents_md,
|
||||
model_name=model_name,
|
||||
return _to_tool_response(
|
||||
controller.create_analyst(
|
||||
agent_id=agent_id,
|
||||
analyst_type=analyst_type,
|
||||
name=name,
|
||||
focus=focus_list,
|
||||
description=description,
|
||||
soul_md=soul_md,
|
||||
agents_md=agents_md,
|
||||
model_name=model_name,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def clone_analyst(
|
||||
source_id: str,
|
||||
new_id: str,
|
||||
name: Optional[str] = None,
|
||||
focus_additions: Optional[str] = None,
|
||||
description_override: Optional[str] = None,
|
||||
model_name: Optional[str] = None,
|
||||
) -> Dict[str, Any]:
|
||||
name: str = "",
|
||||
focus_additions: str = "",
|
||||
description_override: str = "",
|
||||
model_name: str = "",
|
||||
) -> ToolResponse:
|
||||
"""Tool wrapper for clone_analyst.
|
||||
|
||||
Note: focus_additions accepts comma-separated string.
|
||||
"""
|
||||
controller = get_controller()
|
||||
if not controller:
|
||||
return {"success": False, "error": "Dynamic team controller not available"}
|
||||
return _to_tool_response({"success": False, "error": "Dynamic team controller not available"})
|
||||
|
||||
additions_list = [f.strip() for f in focus_additions.split(",")] if focus_additions else None
|
||||
return controller.clone_analyst(
|
||||
source_id=source_id,
|
||||
new_id=new_id,
|
||||
name=name,
|
||||
focus_additions=additions_list,
|
||||
description_override=description_override,
|
||||
model_name=model_name,
|
||||
return _to_tool_response(
|
||||
controller.clone_analyst(
|
||||
source_id=source_id,
|
||||
new_id=new_id,
|
||||
name=name,
|
||||
focus_additions=additions_list,
|
||||
description_override=description_override,
|
||||
model_name=model_name,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def remove_analyst(agent_id: str) -> Dict[str, Any]:
|
||||
def remove_analyst(agent_id: str) -> ToolResponse:
|
||||
"""Tool wrapper for remove_analyst."""
|
||||
controller = get_controller()
|
||||
if not controller:
|
||||
return {"success": False, "error": "Dynamic team controller not available"}
|
||||
return controller.remove_analyst(agent_id)
|
||||
return _to_tool_response({"success": False, "error": "Dynamic team controller not available"})
|
||||
return _to_tool_response(controller.remove_analyst(agent_id))
|
||||
|
||||
|
||||
def list_analyst_types() -> List[Dict[str, Any]]:
|
||||
def list_analyst_types() -> ToolResponse:
|
||||
"""Tool wrapper for list_analyst_types."""
|
||||
controller = get_controller()
|
||||
if not controller:
|
||||
return []
|
||||
return controller.list_analyst_types()
|
||||
return _to_tool_response([])
|
||||
return _to_tool_response(controller.list_analyst_types())
|
||||
|
||||
|
||||
def get_analyst_info(agent_id: str) -> Dict[str, Any]:
|
||||
def get_analyst_info(agent_id: str) -> ToolResponse:
|
||||
"""Tool wrapper for get_analyst_info."""
|
||||
controller = get_controller()
|
||||
if not controller:
|
||||
return {"found": False, "error": "Controller not available"}
|
||||
return controller.get_analyst_info(agent_id)
|
||||
return _to_tool_response({"found": False, "error": "Controller not available"})
|
||||
return _to_tool_response(controller.get_analyst_info(agent_id))
|
||||
|
||||
|
||||
def get_team_summary() -> Dict[str, Any]:
|
||||
def get_team_summary() -> ToolResponse:
|
||||
"""Tool wrapper for get_team_summary."""
|
||||
controller = get_controller()
|
||||
if not controller:
|
||||
return {"error": "Controller not available"}
|
||||
return controller.get_team_summary()
|
||||
return _to_tool_response({"error": "Controller not available"})
|
||||
return _to_tool_response(controller.get_team_summary())
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
||||
Reference in New Issue
Block a user