Skip to content

Commit 1489a34

Browse files
committed
Add sandbox agent tool routing and runner
1 parent fa1ddc9 commit 1489a34

10 files changed

Lines changed: 649 additions & 529 deletions

File tree

config.yaml.full

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,22 @@ volcengine:
3737
access_key:
3838
secret_key:
3939

40+
agentkit:
41+
# [optional] default AgentKit tool id fallback for all sandbox tools
42+
tool_id:
43+
# [optional] dedicated tool id for `run_code`
44+
tool_id_script:
45+
# [optional] dedicated tool id for `execute_skills`
46+
tool_id_skills:
47+
# [optional] dedicated tool id for `coding`
48+
tool_id_opencode:
49+
# [optional] AgentKit endpoint configs
50+
tool_host:
51+
tool_service_code: agentkit
52+
tool_region: cn-beijing
53+
tool_scheme: https
54+
top_scheme: https
55+
4056
tool:
4157
# [optional] https://console.volcengine.com/ask-echo/my-agent
4258
vesearch:

docs/docs/tools/builtin.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ VeADK 集成了以下火山引擎工具:
6767
| `image_edit` | [编辑图片](https://www.volcengine.com/docs/82379/1541523)(图生图)。 | `from veadk.tools.builtin_tools.image_edit import image_edit` |
6868
| `video_generate` | 根据文本描述[生成视频](https.www.volcengine.com/docs/82379/1520757)| `from veadk.tools.builtin_tools.video_generate import video_generate` |
6969
| `run_code` |[AgentKit 沙箱](https://console.volcengine.com/agentkit-ppe/region:agentkit-ppe+cn-beijing/builtintools)中执行代码。 | `from veadk.tools.builtin_tools.run_code import run_code` |
70+
| `execute_skills` | 在预制技能沙箱中远程执行 `agent.py` 工作流。 | `from veadk.tools.builtin_tools.execute_skills import execute_skills` |
71+
| `coding` | 在预制 OpenCode 沙箱中执行代码生成工作流。 | `from veadk.tools.builtin_tools.coding import coding` |
72+
| `run_sandbox_agent` | 指定任意 `tool_id` 在远端 AgentKit 沙箱中执行 `agent.py`| `from veadk.tools.builtin_tools.run_sandbox_agent import run_sandbox_agent` |
7073
| `lark` | 集成[飞书开放能力](https://open.larkoffice.com/document/uAjLw4CM/ukTMukTMukTM/mcp_integration/mcp_installation),实现文档处理、会话管理等。 | `from veadk.tools.builtin_tools.lark import lark` |
7174
| `las` | 基于[火山引擎 AI 多模态数据湖服务 LAS](https://www.volcengine.com/mcp-marketplace) 进行数据管理。 | `from veadk.tools.builtin_tools.las import las` |
7275
| `mobile_run` | 手机指令执行 | `from veadk.tools.builtin_tools.mobile_run import create_mobile_use_tool` |
@@ -183,7 +186,10 @@ VeADK 集成了以下火山引擎工具:
183186

184187
以下是必须在环境变量里面的配置项:
185188

186-
- `AGENTKIT_TOOL_ID`:用于调用火山引擎AgentKit Tools的沙箱环境Id
189+
- `AGENTKIT_TOOL_ID`:默认的 AgentKit 沙箱环境 Id,会作为所有沙箱工具的兜底配置
190+
- `AGENTKIT_TOOL_ID_SCRIPT`:`run_code` 专用沙箱环境 Id,未配置时回退到 `AGENTKIT_TOOL_ID`
191+
- `AGENTKIT_TOOL_ID_SKILLS`:`execute_skills` 专用沙箱环境 Id,未配置时回退到 `AGENTKIT_TOOL_ID`
192+
- `AGENTKIT_TOOL_ID_OPENCODE`:`coding` 专用沙箱环境 Id,未配置时回退到 `AGENTKIT_TOOL_ID`
187193
- `AGENTKIT_TOOL_HOST`:用于调用火山引擎AgentKit Tools的EndPoint
188194
- `AGENTKIT_TOOL_SERVICE_CODE`:用于调用AgentKit Tools的ServiceCode
189195
- `AGENTKIT_TOOL_SCHEME`:用于切换调用 AgentKit Tools 的协议,允许 `http`/`https`,默认 `https`
@@ -204,6 +210,11 @@ VeADK 集成了以下火山引擎工具:
204210
name: doubao-seed-1-6-250615
205211
api_base: https://ark.cn-beijing.volces.com/api/v3/
206212
api_key: your-api-key-here
213+
agentkit:
214+
tool_id: your-default-tool-id
215+
tool_id_script: your-script-tool-id
216+
tool_id_skills: your-skills-tool-id
217+
tool_id_opencode: your-opencode-tool-id
207218
volcengine:
208219
# [optional] for Viking DB and `web_search` tool
209220
access_key: you-access-key-here
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import importlib.util
2+
import os
3+
import sys
4+
import types
5+
import unittest
6+
from pathlib import Path
7+
from unittest.mock import patch
8+
9+
10+
def _load_agentkit_module():
11+
module_path = (
12+
Path(__file__).resolve().parents[3]
13+
/ "veadk"
14+
/ "tools"
15+
/ "builtin_tools"
16+
/ "_agentkit.py"
17+
)
18+
19+
fake_veadk = types.ModuleType("veadk")
20+
fake_veadk.__path__ = [] # type: ignore[attr-defined]
21+
fake_auth = types.ModuleType("veadk.auth")
22+
fake_auth.__path__ = [] # type: ignore[attr-defined]
23+
fake_veauth = types.ModuleType("veadk.auth.veauth")
24+
fake_veauth.__path__ = [] # type: ignore[attr-defined]
25+
fake_veauth_utils = types.ModuleType("veadk.auth.veauth.utils")
26+
fake_config = types.ModuleType("veadk.config")
27+
fake_utils = types.ModuleType("veadk.utils")
28+
fake_utils.__path__ = [] # type: ignore[attr-defined]
29+
fake_logger = types.ModuleType("veadk.utils.logger")
30+
fake_sign = types.ModuleType("veadk.utils.volcengine_sign")
31+
32+
def fake_getenv(env_name, default_value="", allow_false_values=False):
33+
value = os.getenv(env_name, default_value)
34+
if allow_false_values:
35+
return value
36+
if value:
37+
return value
38+
raise ValueError(
39+
f"The environment variable `{env_name}` not exists. Please set this in your environment variable or config.yaml."
40+
)
41+
42+
class _FakeCredential:
43+
access_key_id = "ak"
44+
secret_access_key = "sk"
45+
session_token = "token"
46+
47+
class _FakeLogger:
48+
def debug(self, *_args, **_kwargs):
49+
return None
50+
51+
def warning(self, *_args, **_kwargs):
52+
return None
53+
54+
def error(self, *_args, **_kwargs):
55+
return None
56+
57+
fake_veauth_utils.get_credential_from_vefaas_iam = lambda: _FakeCredential()
58+
fake_config.getenv = fake_getenv
59+
fake_logger.get_logger = lambda _name: _FakeLogger()
60+
fake_sign.ve_request = lambda **_kwargs: {"Result": {"AccountId": "test-account"}}
61+
62+
stub_modules = {
63+
"veadk": fake_veadk,
64+
"veadk.auth": fake_auth,
65+
"veadk.auth.veauth": fake_veauth,
66+
"veadk.auth.veauth.utils": fake_veauth_utils,
67+
"veadk.config": fake_config,
68+
"veadk.utils": fake_utils,
69+
"veadk.utils.logger": fake_logger,
70+
"veadk.utils.volcengine_sign": fake_sign,
71+
}
72+
73+
with patch.dict(sys.modules, stub_modules):
74+
spec = importlib.util.spec_from_file_location(
75+
"test_agentkit_module", module_path
76+
)
77+
module = importlib.util.module_from_spec(spec)
78+
assert spec is not None
79+
assert spec.loader is not None
80+
spec.loader.exec_module(module)
81+
return module
82+
83+
84+
class TestResolveAgentkitToolId(unittest.TestCase):
85+
@classmethod
86+
def setUpClass(cls):
87+
cls.agentkit_module = _load_agentkit_module()
88+
89+
def setUp(self):
90+
self.env_patcher = patch.dict(
91+
os.environ,
92+
{},
93+
clear=False,
94+
)
95+
self.env_patcher.start()
96+
for env_name in [
97+
"AGENTKIT_TOOL_ID",
98+
"AGENTKIT_TOOL_ID_SCRIPT",
99+
"AGENTKIT_TOOL_ID_SKILLS",
100+
"AGENTKIT_TOOL_ID_OPENCODE",
101+
]:
102+
os.environ.pop(env_name, None)
103+
104+
def tearDown(self):
105+
self.env_patcher.stop()
106+
107+
def test_resolve_prefers_script_tool_id(self):
108+
os.environ["AGENTKIT_TOOL_ID_SCRIPT"] = "script-tool"
109+
os.environ["AGENTKIT_TOOL_ID"] = "default-tool"
110+
111+
tool_id = self.agentkit_module.resolve_agentkit_tool_id(
112+
"AGENTKIT_TOOL_ID_SCRIPT"
113+
)
114+
115+
self.assertEqual(tool_id, "script-tool")
116+
117+
def test_resolve_prefers_skills_tool_id(self):
118+
os.environ["AGENTKIT_TOOL_ID_SKILLS"] = "skills-tool"
119+
os.environ["AGENTKIT_TOOL_ID"] = "default-tool"
120+
121+
tool_id = self.agentkit_module.resolve_agentkit_tool_id(
122+
"AGENTKIT_TOOL_ID_SKILLS"
123+
)
124+
125+
self.assertEqual(tool_id, "skills-tool")
126+
127+
def test_resolve_prefers_opencode_tool_id(self):
128+
os.environ["AGENTKIT_TOOL_ID_OPENCODE"] = "opencode-tool"
129+
os.environ["AGENTKIT_TOOL_ID"] = "default-tool"
130+
131+
tool_id = self.agentkit_module.resolve_agentkit_tool_id(
132+
"AGENTKIT_TOOL_ID_OPENCODE"
133+
)
134+
135+
self.assertEqual(tool_id, "opencode-tool")
136+
137+
def test_resolve_falls_back_to_default_tool_id(self):
138+
os.environ["AGENTKIT_TOOL_ID"] = "default-tool"
139+
140+
tool_id = self.agentkit_module.resolve_agentkit_tool_id()
141+
142+
self.assertEqual(tool_id, "default-tool")
143+
144+
def test_resolve_raises_when_all_tool_ids_missing(self):
145+
with self.assertRaisesRegex(ValueError, "AGENTKIT_TOOL_ID"):
146+
self.agentkit_module.resolve_agentkit_tool_id("AGENTKIT_TOOL_ID_SCRIPT")
147+
148+
149+
if __name__ == "__main__":
150+
unittest.main()

0 commit comments

Comments
 (0)