Skip to content

Commit 9766c84

Browse files
authored
feat: support 3 modes to execute skills (#451)
1 parent a5dc929 commit 9766c84

File tree

5 files changed

+127
-25
lines changed

5 files changed

+127
-25
lines changed

veadk/agent.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from __future__ import annotations
1616

1717
import os
18-
from typing import Dict, Optional, Union
18+
from typing import Dict, Optional, Union, Literal
1919

2020
# If user didn't set LITELLM_LOCAL_MODEL_COST_MAP, set it to True
2121
# to enable local model cost map.
@@ -146,6 +146,8 @@ class Agent(LlmAgent):
146146

147147
skills: list[str] = Field(default_factory=list)
148148

149+
skills_mode: Literal["skills_sandbox", "aio_sandbox", "local"] = "skills_sandbox"
150+
149151
example_store: Optional[BaseExampleProvider] = None
150152

151153
def model_post_init(self, __context: Any) -> None:
@@ -309,14 +311,7 @@ def load_skills(self):
309311
load_skills_from_cloud,
310312
load_skills_from_directory,
311313
)
312-
from veadk.tools.skills_tools import (
313-
SkillsTool,
314-
bash_tool,
315-
edit_file_tool,
316-
read_file_tool,
317-
write_file_tool,
318-
register_skills_tool,
319-
)
314+
from veadk.tools.skills_tools.skills_toolset import SkillsToolset
320315

321316
skills: Dict[str, Skill] = {}
322317

@@ -338,12 +333,14 @@ def load_skills(self):
338333
f"- name: {skill.name}\n- description: {skill.description}\n\n"
339334
)
340335

341-
self.tools.append(SkillsTool(skills))
342-
self.tools.append(read_file_tool)
343-
self.tools.append(write_file_tool)
344-
self.tools.append(edit_file_tool)
345-
self.tools.append(bash_tool)
346-
self.tools.append(register_skills_tool)
336+
if self.skills_mode not in ["skills_sandbox", "aio_sandbox", "local"]:
337+
raise ValueError(
338+
f"Unsupported skill mode {self.skills_mode}, use `skills_sandbox`, `aio_sandbox` or `local` instead."
339+
)
340+
341+
self.tools.append(SkillsToolset(skills, self.skills_mode))
342+
else:
343+
logger.warning("No skills loaded.")
347344

348345
def _prepare_tracers(self):
349346
enable_apmplus_tracer = os.getenv("ENABLE_APMPLUS", "false").lower() == "true"

veadk/tools/builtin_tools/execute_skills.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ def execute_skills(
7070
workflow_prompt: str,
7171
tool_context: ToolContext = None,
7272
) -> str:
73-
"""execute skills in a code sandbox and return the output.
74-
For C++ code, don't execute it directly, compile and execute via Python; write sources and object files to /tmp.
73+
"""Execute skills in a sandbox and return the output.
74+
75+
Execute skills in a remote sandbox amining to provide isolation and security.
7576
7677
Args:
7778
workflow_prompt (str): instruction of workflow

veadk/tools/skills_tools/register_skills_tool.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,13 @@ def register_skills_tool(
8080
try:
8181
from veadk.auth.veauth.utils import get_credential_from_vefaas_iam
8282

83-
service = os.getenv("AGENTKIT_TOOL_SERVICE_CODE", "agentkit")
83+
agentkit_tool_service = os.getenv("AGENTKIT_TOOL_SERVICE_CODE", "agentkit")
84+
agentkit_skill_host = os.getenv("AGENTKIT_SKILL_HOST", "open.volcengineapi.com")
8485
region = os.getenv("AGENTKIT_TOOL_REGION", "cn-beijing")
85-
host = os.getenv("AGENTKIT_SKILL_HOST", "open.volcengineapi.com")
8686

8787
access_key = os.getenv("VOLCENGINE_ACCESS_KEY")
8888
secret_key = os.getenv("VOLCENGINE_SECRET_KEY")
8989
session_token = ""
90-
region = os.getenv("AGENTKIT_TOOL_REGION", "cn-beijing")
9190

9291
if not (access_key and secret_key):
9392
cred = get_credential_from_vefaas_iam()
@@ -149,10 +148,10 @@ def register_skills_tool(
149148
action="CreateSkill",
150149
ak=access_key,
151150
sk=secret_key,
152-
service=service,
151+
service=agentkit_tool_service,
153152
version="2025-10-30",
154153
region=region,
155-
host=host,
154+
host=agentkit_skill_host,
156155
header={"X-Security-Token": session_token},
157156
)
158157

veadk/tools/skills_tools/skills_tool.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ def __init__(self, skills: Dict[str, Skill]):
3939
self.skills = skills
4040

4141
# Generate description with available skills embedded
42-
description = self._generate_description_with_skills()
42+
description = self._generate_description()
4343

4444
super().__init__(
45-
name="skills",
45+
name="skills_tool",
4646
description=description,
4747
)
4848

49-
def _generate_description_with_skills(self) -> str:
49+
def _generate_description(self) -> str:
5050
"""Generate tool description with available skills embedded."""
5151
base_description = (
5252
"Execute a skill within the main conversation\n\n"
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from __future__ import annotations
16+
17+
from typing import Dict, List, Optional
18+
19+
try:
20+
from typing_extensions import override
21+
except ImportError:
22+
from typing import override
23+
24+
from google.adk.agents.readonly_context import ReadonlyContext
25+
from google.adk.tools import BaseTool, FunctionTool
26+
from google.adk.tools.base_toolset import BaseToolset
27+
28+
from veadk.skills.skill import Skill
29+
from veadk.tools.skills_tools import (
30+
SkillsTool,
31+
read_file_tool,
32+
write_file_tool,
33+
edit_file_tool,
34+
bash_tool,
35+
register_skills_tool,
36+
)
37+
from veadk.utils.logger import get_logger
38+
39+
logger = get_logger(__name__)
40+
41+
42+
class SkillsToolset(BaseToolset):
43+
"""Toolset that provides Skills functionality for domain expertise execution.
44+
45+
This toolset provides skills access through specialized tools:
46+
1. SkillsTool - Discover and load skill instructions
47+
2. ReadFileTool - Read files with line numbers
48+
3. WriteFileTool - Write/create files
49+
4. EditFileTool - Edit files with precise replacements
50+
5. BashTool - Execute shell commands
51+
6. RegisterSkillsTool - Register new skills into the remote skill space
52+
53+
Skills provide specialized domain knowledge and scripts that the agent can use
54+
to solve complex tasks. The toolset enables discovery of available skills,
55+
file manipulation, and command execution.
56+
"""
57+
58+
def __init__(self, skills: Dict[str, Skill], skills_mode: str) -> None:
59+
"""Initialize the skills toolset.
60+
61+
Args:
62+
skills: A dictionary of skill.
63+
skills_mode: The mode of skills operation, e.g., "skills_sandbox".
64+
"""
65+
super().__init__()
66+
67+
self.skills_mode = skills_mode
68+
69+
self._tools = {
70+
"skills": SkillsTool(skills),
71+
"read_file": FunctionTool(read_file_tool),
72+
"write_file": FunctionTool(write_file_tool),
73+
"edit_file": FunctionTool(edit_file_tool),
74+
"bash": FunctionTool(bash_tool),
75+
"register_skills": FunctionTool(register_skills_tool),
76+
}
77+
78+
@override
79+
async def get_tools(
80+
self, readonly_context: Optional[ReadonlyContext] = None
81+
) -> List[BaseTool]:
82+
"""Return tools according to selected skills_mode."""
83+
84+
match self.skills_mode:
85+
case "local":
86+
logger.info(
87+
"Skills mode=local, adding skills_tool, read_file_tool, write_file_tool, edit_file_tool, bash_tool and register_skills_tool to the agent."
88+
)
89+
return list(self._tools.values())
90+
91+
case "skills_sandbox":
92+
logger.info(
93+
"Skills mode=skills_sandbox, no skills tools are added to the agent."
94+
)
95+
return []
96+
97+
case "aio_sandbox":
98+
logger.info("Skills mode=aio_sandbox: not implemented yet")
99+
return []
100+
101+
case _:
102+
logger.warning(
103+
f"Unknown skills_mode: {self.skills_mode}, returning empty tool list."
104+
)
105+
return []

0 commit comments

Comments
 (0)