Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
16 changes: 16 additions & 0 deletions aworld/config/task_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,11 @@ async def _load_skill_agent(
f"missing agent {agent_id}: failed to load skill content for '{skill_name}' "
f"from {skills_path}: {e}"
)

runtime_skill_config = registry.build_skill_config(
descriptor.skill_id,
active_override=True,
)

# Build Agent from skill (consistent with skill_service logic)
agent_config_dict = agent_def.get("config", {})
Expand All @@ -345,6 +350,17 @@ async def _load_skill_agent(
agent_def.get("mcp_config")
)
)

# Preserve framework-loaded skill metadata for downstream runtime features
# such as remote sandbox execution-asset staging without re-enabling the
# legacy skill tool path on these agentic skills.
merged_skill_configs = dict(agent.conf.skill_configs or {})
merged_skill_configs[skill_name] = runtime_skill_config

agent.conf.skill_configs = merged_skill_configs
agent.skill_configs = merged_skill_configs
if agent.sandbox is not None:
agent.sandbox.skill_configs = merged_skill_configs

return agent

Expand Down
2 changes: 1 addition & 1 deletion aworld/sandbox/builtin/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
FILESYSTEM_TOOL_MAPPING = {
"read_file": "read_file",
"write_file": "write_file",
"write_file_base64": "write_file_base64",
"edit_file": "replace_in_file",
"replace_in_file": "replace_in_file",
"edit_file_range": "edit_file_range",
Expand Down Expand Up @@ -88,4 +89,3 @@ def decorator(func: Callable) -> Callable:
func._fallback = fallback_to_builtin
return func
return decorator

11 changes: 11 additions & 0 deletions aworld/sandbox/implementations/sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ def __init__(
self._initialized = False
self._file_namespace = None
self._terminal_namespace = None
self._remote_skill_execution_roots: dict[tuple[str, str], str] = {}
self._remote_skill_execution_base_dir: str | None = None

user_mcp_config = copy.deepcopy(mcp_config) if mcp_config else {}
user_mcp_servers = mcp_servers or []
Expand Down Expand Up @@ -1315,5 +1317,14 @@ def get_skill_list(self) -> Optional[Any]:
return None
return self._skill_configs

async def ensure_skill_execution_assets_ready(
self,
skill_name: str,
skill_config: Dict[str, Any],
) -> str:
from aworld.sandbox.skill_sync import ensure_remote_skill_assets_ready

return await ensure_remote_skill_assets_ready(self, skill_name, skill_config)

def __del__(self):
super().__del__()
37 changes: 37 additions & 0 deletions aworld/sandbox/namespaces/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ def resolve_service_name(sandbox: Any, logical_name: str) -> str:
(comma-separated) contains logical_name. Fallback: return logical_name.
"""
mcp_config = getattr(sandbox, "mcp_config", None) or getattr(sandbox, "_mcp_config", None)
return resolve_service_name_from_config(mcp_config, logical_name)


def resolve_service_name_from_config(mcp_config: Any, logical_name: str) -> str:
"""Resolve a logical service name against an MCP config dict."""
if not mcp_config:
return logical_name
servers = mcp_config.get("mcpServers") or {}
Expand All @@ -48,9 +53,41 @@ def resolve_service_name(sandbox: Any, logical_name: str) -> str:
names = [n.strip() for n in mcp_servers_header.split(",") if n.strip()]
if logical_name in names:
return key
server_suffix_alias = f"{logical_name}-server"
if server_suffix_alias in servers:
return server_suffix_alias
for key in servers:
if str(key).strip().lower().endswith(f"-{server_suffix_alias}"):
return key
return logical_name


def service_matches_logical_name(
mcp_config: Any,
server_name: str,
logical_name: str,
) -> bool:
"""Return whether a concrete server name should be treated as a logical service."""
if not server_name:
return False
normalized_server_name = str(server_name).strip()
if normalized_server_name == logical_name:
return True

servers = (mcp_config or {}).get("mcpServers") or {}
server_config = servers.get(normalized_server_name, {})
headers = server_config.get("headers") or {}
mcp_servers_header = (headers.get("MCP_SERVERS") or "").strip()
if mcp_servers_header:
names = [n.strip() for n in mcp_servers_header.split(",") if n.strip()]
if logical_name in names:
return True

server_suffix_alias = f"{logical_name}-server"
normalized_lower = normalized_server_name.lower()
return normalized_lower == server_suffix_alias or normalized_lower.endswith(f"-{server_suffix_alias}")


def _parse_action_results(results: List[Any]) -> Dict[str, Any]:
"""Parse List[ActionResult] from call_tool into normalized dict."""
if not results:
Expand Down
4 changes: 4 additions & 0 deletions aworld/sandbox/namespaces/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ async def write_file(self, path: str, content: str) -> Dict[str, Any]:
"""Write content to file."""
return await self._call_tool("write_file", path=path, content=content)

async def write_file_base64(self, path: str, content_base64: str) -> Dict[str, Any]:
"""Write base64-decoded binary content to file."""
return await self._call_tool("write_file_base64", path=path, content_base64=content_base64)

async def edit_file(
self,
path: str,
Expand Down
Loading
Loading