Skip to content

Commit 34f37f4

Browse files
authored
feat: deploy with web and studio (#29)
1 parent 1442cb5 commit 34f37f4

File tree

14 files changed

+134
-95
lines changed

14 files changed

+134
-95
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,4 @@ exclude = ["assets*", "ide*", "tests*"]
7070
include-package-data = true
7171

7272
[tool.setuptools.package-data]
73-
"veadk.cli.studio.web" = ["_next/**/*"]
73+
"veadk" = ["**/*"]

veadk/cli/main.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ def web(
129129
None,
130130
"--session_service_uri",
131131
),
132+
host: str = typer.Option(
133+
"127.0.0.1",
134+
"--host",
135+
),
132136
):
133137
from google.adk.memory import in_memory_memory_service
134138

@@ -144,7 +148,7 @@ def web(
144148
session_service_uri = ""
145149

146150
cli_tools_click.cli_web.main(
147-
args=[agents_dir, "--session_service_uri", session_service_uri]
151+
args=[agents_dir, "--session_service_uri", session_service_uri, "--host", host]
148152
)
149153

150154

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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.

veadk/cli/services/vefaas/template/deploy.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
USER_ID = "cloud_app_test_user"
2222

2323
USE_STUDIO = False
24+
USE_ADK_WEB = False
2425

2526

2627
async def main():
@@ -29,10 +30,11 @@ async def main():
2930
path=str(Path(__file__).parent / "src"),
3031
name="weather-reporter", # <--- set your application name
3132
use_studio=USE_STUDIO,
33+
use_adk_web=USE_ADK_WEB,
3234
# gateway_name="", # <--- set your gateway instance name if you have one
3335
)
3436

35-
if not USE_STUDIO:
37+
if not USE_STUDIO and not USE_ADK_WEB:
3638
response_message = await cloud_app.message_send(
3739
"How is the weather like in Beijing?", SESSION_ID, USER_ID
3840
)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
from . import agent # noqa F401

veadk/cli/services/vefaas/template/src/agent.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@
2121
short_term_memory: ShortTermMemory = (
2222
ShortTermMemory()
2323
) # <--- export your short term memory
24+
25+
root_agent = agent
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
veadk-python[eval] @ git+https://github.com/volcengine/veadk-python.git # extra eval for prompt optimization in veadk studio
2+
opensearch-py==2.8.0
23
agent-pilot-sdk>=0.0.9 # extra dep for prompt optimization in veadk studio
34
uvicorn[standard]
45
fastapi

veadk/cli/services/vefaas/template/src/run.sh

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,25 @@ python3 -m pip install uvicorn[standard]
3939
python3 -m pip install fastapi
4040

4141
USE_STUDIO=${USE_STUDIO:-False}
42+
USE_ADK_WEB=${USE_ADK_WEB:-False}
4243

4344
if [ "$USE_STUDIO" = "True" ]; then
4445
echo "USE_STUDIO is True, running veadk studio"
4546
# running veadk studio
4647
exec python3 -m uvicorn studio_app:app --host $HOST --port $PORT --timeout-graceful-shutdown $TIMEOUT --loop asyncio
4748
elif [ "$USE_STUDIO" = "False" ]; then
48-
echo "USE_STUDIO is False, running a2a server"
49-
50-
# running a2a server
51-
exec python3 -m uvicorn app:app --host $HOST --port $PORT --timeout-graceful-shutdown $TIMEOUT --loop asyncio
49+
echo "USE_STUDIO is False"
50+
51+
if [ "$USE_ADK_WEB" = "True" ]; then
52+
echo "USE_ADK_WEB is True, running veadk web"
53+
# running veadk web
54+
cd ../
55+
exec python3 -m veadk.cli.main web --host "0.0.0.0"
56+
else
57+
echo "USE_ADK_WEB is False, running a2a server"
58+
exec python3 -m uvicorn app:app --host $HOST --port $PORT --timeout-graceful-shutdown $TIMEOUT --loop asyncio
59+
fi
5260
else
53-
echo "USE_STUDIO is an invalid value: $USE_STUDIO, running a2a server."
54-
5561
# running a2a server
5662
exec python3 -m uvicorn app:app --host $HOST --port $PORT --timeout-graceful-shutdown $TIMEOUT --loop asyncio
57-
fi
58-
59-
63+
fi

veadk/cli/services/vefaas/vefaas.py

Lines changed: 42 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
TagForCreateFunctionInput,
2727
)
2828

29+
import veadk.config
2930
from veadk.cli.services.veapig.apig import APIGateway
3031
from veadk.utils.logger import get_logger
3132
from veadk.utils.misc import formatted_timestamp
@@ -58,27 +59,16 @@ def __init__(self, access_key: str, secret_key: str, region: str = "cn-beijing")
5859

5960
self.template_id = "6874f3360bdbc40008ecf8c7"
6061

61-
def _create_function(self, name: str, path: str):
62-
function_name = f"{name}-fn-{formatted_timestamp()}"
63-
64-
# 1. Create a function instance in cloud
65-
typer.echo(
66-
typer.style("Runtime: native-python3.10/v1", fg=typer.colors.BRIGHT_BLACK)
67-
)
68-
62+
def _create_function(self, function_name: str, path: str):
63+
# 1. Read envs
6964
envs = []
70-
71-
import veadk.config
72-
7365
for key, value in veadk.config.veadk_environments.items():
7466
envs.append(EnvForCreateFunctionInput(key=key, value=value))
75-
typer.echo(
76-
typer.style(
77-
f"Fetch {len(envs)} environment variables.",
78-
fg=typer.colors.BRIGHT_BLACK,
79-
)
67+
logger.info(
68+
f"Fetch {len(envs)} environment variables.",
8069
)
8170

71+
# 2. Create function
8272
res = self.client.create_function(
8373
volcenginesdkvefaas.CreateFunctionRequest(
8474
command="./run.sh",
@@ -88,21 +78,17 @@ def _create_function(self, name: str, path: str):
8878
runtime="native-python3.10/v1",
8979
request_timeout=1800,
9080
envs=envs,
91-
# tls_config=TlsConfigForCreateFunctionInput(enable_log=True),
9281
)
9382
)
9483
function_id = res.id
9584

96-
# 2. Get a temp bucket to store code
97-
# proj_path = get_project_path()
85+
# 3. Get a temp bucket to store code
9886
code_zip_data, code_zip_size, error = zip_and_encode_folder(path)
99-
typer.echo(
100-
typer.style(
101-
f"Zipped project size: {code_zip_size / 1024 / 1024:.2f} MB",
102-
fg=typer.colors.BRIGHT_BLACK,
103-
)
87+
logger.info(
88+
f"Zipped project size: {code_zip_size / 1024 / 1024:.2f} MB",
10489
)
10590

91+
# 4. Upload code to VeFaaS temp bucket
10692
req = volcenginesdkvefaas.GetCodeUploadAddressRequest(
10793
function_id=function_id, content_length=code_zip_size
10894
)
@@ -113,28 +99,18 @@ def _create_function(self, name: str, path: str):
11399
"Content-Type": "application/zip",
114100
}
115101
response = requests.put(url=upload_url, data=code_zip_data, headers=headers)
116-
if 200 <= response.status_code < 300:
117-
# print(f"Upload successful! Size: {code_zip_size / 1024 / 1024:.2f} MB")
118-
pass
119-
else:
102+
if not (200 <= response.status_code < 300):
120103
error_message = f"Upload failed to {upload_url} with status code {response.status_code}: {response.text}"
121104
raise ValueError(error_message)
122105

123-
# 3. Mount the TOS bucket to function instance
106+
# 5. Mount the TOS bucket to function instance
124107
res = signed_request(
125108
ak=self.ak,
126109
sk=self.sk,
127110
target="CodeUploadCallback",
128111
body={"FunctionId": function_id},
129112
)
130113

131-
typer.echo(
132-
typer.style(
133-
f"Function ID on VeFaaS service: {function_id}",
134-
fg=typer.colors.BRIGHT_BLACK,
135-
)
136-
)
137-
138114
return function_name, function_id
139115

140116
def _create_application(
@@ -183,23 +159,21 @@ def _release_application(self, app_id: str):
183159
host="open.volcengineapi.com",
184160
)
185161

162+
logger.info(f"Start to release VeFaaS application {app_id}.")
186163
status, full_response = self._get_application_status(app_id)
187164
while status not in ["deploy_success", "deploy_fail"]:
188165
time.sleep(10)
189-
typer.echo(
190-
typer.style(
191-
f"Current status: {status}",
192-
fg=typer.colors.BRIGHT_BLACK,
193-
)
194-
)
195166
status, full_response = self._get_application_status(app_id)
196167

197168
assert status == "deploy_success", (
198169
f"Release application failed. Response: {full_response}"
199170
)
171+
200172
cloud_resource = full_response["Result"]["CloudResource"]
201173
cloud_resource = json.loads(cloud_resource)
174+
202175
url = cloud_resource["framework"]["url"]["system_url"]
176+
203177
return url
204178

205179
def _get_application_status(self, app_id: str):
@@ -257,15 +231,29 @@ def delete(self, app_id: str):
257231

258232
def deploy(
259233
self,
260-
name: str, # application name
234+
name: str,
261235
path: str,
262236
gateway_name: str = "",
263237
gateway_service_name: str = "",
264238
gateway_upstream_name: str = "",
265239
) -> tuple[str, str, str]:
240+
"""Deploy an agent project to VeFaaS service.
241+
242+
Args:
243+
name (str): Application name (warning: not function name).
244+
path (str): Project path.
245+
gateway_name (str, optional): Gateway name. Defaults to "".
246+
gateway_service_name (str, optional): Gateway service name. Defaults to "".
247+
gateway_upstream_name (str, optional): Gateway upstream name. Defaults to "".
248+
249+
Returns:
250+
tuple[str, str, str]: (url, app_id, function_id)
251+
"""
252+
# Naming check
266253
if "_" in name:
267254
raise ValueError("Function or Application name cannot contain '_'.")
268255

256+
# Give default names
269257
if not gateway_name:
270258
gateway_name = f"{name}-gw-{formatted_timestamp()}"
271259

@@ -286,14 +274,15 @@ def deploy(
286274
if not gateway_upstream_name:
287275
gateway_upstream_name = f"{name}-gw-us-{formatted_timestamp()}"
288276

289-
typer.echo(
290-
typer.style("[1/3] ", fg=typer.colors.GREEN)
291-
+ "Create VeFaaS service on cloud."
277+
function_name = f"{name}-fn"
278+
279+
logger.info(
280+
f"Start to create VeFaaS function {function_name} with path {path}. Gateway: {gateway_name}, Gateway Service: {gateway_service_name}, Gateway Upstream: {gateway_upstream_name}."
292281
)
293-
typer.echo(typer.style(f"Project path: {path}", fg=typer.colors.BRIGHT_BLACK))
294-
function_name, function_id = self._create_function(name, path)
282+
function_name, function_id = self._create_function(function_name, path)
283+
logger.info(f"VeFaaS function {function_name} with ID {function_id} created.")
295284

296-
typer.echo(typer.style("[2/3] ", fg=typer.colors.GREEN) + "Create application.")
285+
logger.info(f"Start to create VeFaaS application {name}.")
297286
app_id = self._create_application(
298287
name,
299288
function_name,
@@ -302,13 +291,11 @@ def deploy(
302291
gateway_service_name,
303292
)
304293

305-
typer.echo(
306-
typer.style("[3/3] ", fg=typer.colors.GREEN) + "Release application."
307-
)
294+
logger.info(f"VeFaaS application {name} with ID {app_id} created.")
295+
logger.info(f"Start to release VeFaaS application {app_id}.")
308296
url = self._release_application(app_id)
297+
logger.info(f"VeFaaS application {name} with ID {app_id} released.")
309298

310-
typer.echo(
311-
typer.style(f"\nSuccessfully deployed on:\n\n{url}", fg=typer.colors.BLUE)
312-
)
299+
logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.")
313300

314301
return url, app_id, function_id

veadk/cli/studio/studio_processor.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ async def evaluate(self):
9494
metrics = [
9595
GEval(
9696
name="Correctness&MatchDegree",
97+
model=self.evaluator.judge_model,
9798
criteria="Judge the correctness and match degree of the model output with the expected output.",
9899
evaluation_params=[
99100
LLMTestCaseParams.INPUT,

0 commit comments

Comments
 (0)