veadk-python 0.2.27__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- veadk/__init__.py +37 -0
- veadk/a2a/__init__.py +13 -0
- veadk/a2a/agent_card.py +45 -0
- veadk/a2a/remote_ve_agent.py +390 -0
- veadk/a2a/utils/__init__.py +13 -0
- veadk/a2a/utils/agent_to_a2a.py +170 -0
- veadk/a2a/ve_a2a_server.py +93 -0
- veadk/a2a/ve_agent_executor.py +78 -0
- veadk/a2a/ve_middlewares.py +313 -0
- veadk/a2a/ve_task_store.py +37 -0
- veadk/agent.py +402 -0
- veadk/agent_builder.py +93 -0
- veadk/agents/loop_agent.py +68 -0
- veadk/agents/parallel_agent.py +72 -0
- veadk/agents/sequential_agent.py +64 -0
- veadk/auth/__init__.py +13 -0
- veadk/auth/base_auth.py +22 -0
- veadk/auth/ve_credential_service.py +203 -0
- veadk/auth/veauth/__init__.py +13 -0
- veadk/auth/veauth/apmplus_veauth.py +58 -0
- veadk/auth/veauth/ark_veauth.py +75 -0
- veadk/auth/veauth/base_veauth.py +50 -0
- veadk/auth/veauth/cozeloop_veauth.py +13 -0
- veadk/auth/veauth/opensearch_veauth.py +75 -0
- veadk/auth/veauth/postgresql_veauth.py +75 -0
- veadk/auth/veauth/prompt_pilot_veauth.py +60 -0
- veadk/auth/veauth/speech_veauth.py +54 -0
- veadk/auth/veauth/utils.py +69 -0
- veadk/auth/veauth/vesearch_veauth.py +62 -0
- veadk/auth/veauth/viking_mem0_veauth.py +91 -0
- veadk/cli/__init__.py +13 -0
- veadk/cli/cli.py +58 -0
- veadk/cli/cli_clean.py +87 -0
- veadk/cli/cli_create.py +163 -0
- veadk/cli/cli_deploy.py +233 -0
- veadk/cli/cli_eval.py +215 -0
- veadk/cli/cli_init.py +214 -0
- veadk/cli/cli_kb.py +110 -0
- veadk/cli/cli_pipeline.py +285 -0
- veadk/cli/cli_prompt.py +86 -0
- veadk/cli/cli_update.py +106 -0
- veadk/cli/cli_uploadevalset.py +139 -0
- veadk/cli/cli_web.py +143 -0
- veadk/cloud/__init__.py +13 -0
- veadk/cloud/cloud_agent_engine.py +485 -0
- veadk/cloud/cloud_app.py +475 -0
- veadk/config.py +115 -0
- veadk/configs/__init__.py +13 -0
- veadk/configs/auth_configs.py +133 -0
- veadk/configs/database_configs.py +132 -0
- veadk/configs/model_configs.py +78 -0
- veadk/configs/tool_configs.py +54 -0
- veadk/configs/tracing_configs.py +110 -0
- veadk/consts.py +74 -0
- veadk/evaluation/__init__.py +17 -0
- veadk/evaluation/adk_evaluator/__init__.py +17 -0
- veadk/evaluation/adk_evaluator/adk_evaluator.py +302 -0
- veadk/evaluation/base_evaluator.py +642 -0
- veadk/evaluation/deepeval_evaluator/__init__.py +17 -0
- veadk/evaluation/deepeval_evaluator/deepeval_evaluator.py +339 -0
- veadk/evaluation/eval_set_file_loader.py +48 -0
- veadk/evaluation/eval_set_recorder.py +146 -0
- veadk/evaluation/types.py +65 -0
- veadk/evaluation/utils/prometheus.py +196 -0
- veadk/integrations/__init__.py +13 -0
- veadk/integrations/ve_apig/__init__.py +13 -0
- veadk/integrations/ve_apig/ve_apig.py +349 -0
- veadk/integrations/ve_apig/ve_apig_utils.py +332 -0
- veadk/integrations/ve_code_pipeline/__init__.py +13 -0
- veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +431 -0
- veadk/integrations/ve_cozeloop/__init__.py +13 -0
- veadk/integrations/ve_cozeloop/ve_cozeloop.py +96 -0
- veadk/integrations/ve_cr/__init__.py +13 -0
- veadk/integrations/ve_cr/ve_cr.py +220 -0
- veadk/integrations/ve_faas/__init__.py +13 -0
- veadk/integrations/ve_faas/template/cookiecutter.json +15 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/config.yaml.example +6 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/deploy.py +106 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/__init__.py +13 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/agent.py +25 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +202 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +49 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/__init__.py +14 -0
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{ cookiecutter.app_name }}/agent.py +27 -0
- veadk/integrations/ve_faas/ve_faas.py +754 -0
- veadk/integrations/ve_faas/ve_faas_utils.py +408 -0
- veadk/integrations/ve_faas/web_template/cookiecutter.json +20 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +44 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
- veadk/integrations/ve_identity/__init__.py +110 -0
- veadk/integrations/ve_identity/auth_config.py +261 -0
- veadk/integrations/ve_identity/auth_mixins.py +650 -0
- veadk/integrations/ve_identity/auth_processor.py +385 -0
- veadk/integrations/ve_identity/function_tool.py +158 -0
- veadk/integrations/ve_identity/identity_client.py +864 -0
- veadk/integrations/ve_identity/mcp_tool.py +181 -0
- veadk/integrations/ve_identity/mcp_toolset.py +431 -0
- veadk/integrations/ve_identity/models.py +228 -0
- veadk/integrations/ve_identity/token_manager.py +188 -0
- veadk/integrations/ve_identity/utils.py +151 -0
- veadk/integrations/ve_prompt_pilot/__init__.py +13 -0
- veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +85 -0
- veadk/integrations/ve_tls/__init__.py +13 -0
- veadk/integrations/ve_tls/utils.py +116 -0
- veadk/integrations/ve_tls/ve_tls.py +212 -0
- veadk/integrations/ve_tos/ve_tos.py +710 -0
- veadk/integrations/ve_viking_db_memory/__init__.py +13 -0
- veadk/integrations/ve_viking_db_memory/ve_viking_db_memory.py +308 -0
- veadk/knowledgebase/__init__.py +17 -0
- veadk/knowledgebase/backends/__init__.py +13 -0
- veadk/knowledgebase/backends/base_backend.py +72 -0
- veadk/knowledgebase/backends/in_memory_backend.py +91 -0
- veadk/knowledgebase/backends/opensearch_backend.py +162 -0
- veadk/knowledgebase/backends/redis_backend.py +172 -0
- veadk/knowledgebase/backends/utils.py +92 -0
- veadk/knowledgebase/backends/vikingdb_knowledge_backend.py +608 -0
- veadk/knowledgebase/entry.py +25 -0
- veadk/knowledgebase/knowledgebase.py +307 -0
- veadk/memory/__init__.py +35 -0
- veadk/memory/long_term_memory.py +365 -0
- veadk/memory/long_term_memory_backends/__init__.py +13 -0
- veadk/memory/long_term_memory_backends/base_backend.py +35 -0
- veadk/memory/long_term_memory_backends/in_memory_backend.py +67 -0
- veadk/memory/long_term_memory_backends/mem0_backend.py +155 -0
- veadk/memory/long_term_memory_backends/opensearch_backend.py +124 -0
- veadk/memory/long_term_memory_backends/redis_backend.py +140 -0
- veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py +189 -0
- veadk/memory/short_term_memory.py +252 -0
- veadk/memory/short_term_memory_backends/__init__.py +13 -0
- veadk/memory/short_term_memory_backends/base_backend.py +31 -0
- veadk/memory/short_term_memory_backends/mysql_backend.py +49 -0
- veadk/memory/short_term_memory_backends/postgresql_backend.py +49 -0
- veadk/memory/short_term_memory_backends/sqlite_backend.py +55 -0
- veadk/memory/short_term_memory_processor.py +100 -0
- veadk/processors/__init__.py +26 -0
- veadk/processors/base_run_processor.py +120 -0
- veadk/prompts/__init__.py +13 -0
- veadk/prompts/agent_default_prompt.py +30 -0
- veadk/prompts/prompt_evaluator.py +20 -0
- veadk/prompts/prompt_memory_processor.py +55 -0
- veadk/prompts/prompt_optimization.py +150 -0
- veadk/runner.py +732 -0
- veadk/tools/__init__.py +13 -0
- veadk/tools/builtin_tools/__init__.py +13 -0
- veadk/tools/builtin_tools/agent_authorization.py +94 -0
- veadk/tools/builtin_tools/generate_image.py +23 -0
- veadk/tools/builtin_tools/image_edit.py +300 -0
- veadk/tools/builtin_tools/image_generate.py +446 -0
- veadk/tools/builtin_tools/lark.py +67 -0
- veadk/tools/builtin_tools/las.py +24 -0
- veadk/tools/builtin_tools/link_reader.py +66 -0
- veadk/tools/builtin_tools/llm_shield.py +381 -0
- veadk/tools/builtin_tools/load_knowledgebase.py +97 -0
- veadk/tools/builtin_tools/mcp_router.py +29 -0
- veadk/tools/builtin_tools/run_code.py +113 -0
- veadk/tools/builtin_tools/tts.py +253 -0
- veadk/tools/builtin_tools/vesearch.py +49 -0
- veadk/tools/builtin_tools/video_generate.py +363 -0
- veadk/tools/builtin_tools/web_scraper.py +76 -0
- veadk/tools/builtin_tools/web_search.py +83 -0
- veadk/tools/demo_tools.py +58 -0
- veadk/tools/load_knowledgebase_tool.py +149 -0
- veadk/tools/sandbox/__init__.py +13 -0
- veadk/tools/sandbox/browser_sandbox.py +37 -0
- veadk/tools/sandbox/code_sandbox.py +40 -0
- veadk/tools/sandbox/computer_sandbox.py +34 -0
- veadk/tracing/__init__.py +13 -0
- veadk/tracing/base_tracer.py +58 -0
- veadk/tracing/telemetry/__init__.py +13 -0
- veadk/tracing/telemetry/attributes/attributes.py +29 -0
- veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +180 -0
- veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +858 -0
- veadk/tracing/telemetry/attributes/extractors/tool_attributes_extractors.py +152 -0
- veadk/tracing/telemetry/attributes/extractors/types.py +164 -0
- veadk/tracing/telemetry/exporters/__init__.py +13 -0
- veadk/tracing/telemetry/exporters/apmplus_exporter.py +558 -0
- veadk/tracing/telemetry/exporters/base_exporter.py +39 -0
- veadk/tracing/telemetry/exporters/cozeloop_exporter.py +129 -0
- veadk/tracing/telemetry/exporters/inmemory_exporter.py +248 -0
- veadk/tracing/telemetry/exporters/tls_exporter.py +139 -0
- veadk/tracing/telemetry/opentelemetry_tracer.py +320 -0
- veadk/tracing/telemetry/telemetry.py +411 -0
- veadk/types.py +47 -0
- veadk/utils/__init__.py +13 -0
- veadk/utils/audio_manager.py +95 -0
- veadk/utils/auth.py +294 -0
- veadk/utils/logger.py +59 -0
- veadk/utils/mcp_utils.py +44 -0
- veadk/utils/misc.py +184 -0
- veadk/utils/patches.py +101 -0
- veadk/utils/volcengine_sign.py +205 -0
- veadk/version.py +15 -0
- veadk_python-0.2.27.dist-info/METADATA +373 -0
- veadk_python-0.2.27.dist-info/RECORD +218 -0
- veadk_python-0.2.27.dist-info/WHEEL +5 -0
- veadk_python-0.2.27.dist-info/entry_points.txt +2 -0
- veadk_python-0.2.27.dist-info/licenses/LICENSE +201 -0
- veadk_python-0.2.27.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,485 @@
|
|
|
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
|
+
import json
|
|
16
|
+
import os
|
|
17
|
+
import socket
|
|
18
|
+
import subprocess
|
|
19
|
+
import time
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
from pydantic import BaseModel
|
|
24
|
+
|
|
25
|
+
from veadk.cloud.cloud_app import CloudApp
|
|
26
|
+
from veadk.config import getenv, veadk_environments
|
|
27
|
+
from veadk.integrations.ve_apig.ve_apig import APIGateway
|
|
28
|
+
from veadk.integrations.ve_faas.ve_faas import VeFaaS
|
|
29
|
+
from veadk.integrations.ve_identity.identity_client import IdentityClient
|
|
30
|
+
from veadk.utils.logger import get_logger
|
|
31
|
+
from veadk.utils.misc import formatted_timestamp
|
|
32
|
+
|
|
33
|
+
logger = get_logger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class CloudAgentEngine(BaseModel):
|
|
37
|
+
"""Manages cloud agent deployment and operations on Volcengine FaaS platform.
|
|
38
|
+
|
|
39
|
+
This class handles authentication with Volcengine, deploys local projects to FaaS,
|
|
40
|
+
updates function code, removes applications, and supports local testing.
|
|
41
|
+
|
|
42
|
+
Attributes:
|
|
43
|
+
volcengine_access_key (str): Access key for Volcengine authentication.
|
|
44
|
+
Defaults to VOLCENGINE_ACCESS_KEY environment variable.
|
|
45
|
+
volcengine_secret_key (str): Secret key for Volcengine authentication.
|
|
46
|
+
Defaults to VOLCENGINE_SECRET_KEY environment variable.
|
|
47
|
+
region (str): Region for Volcengine services. Defaults to "cn-beijing".
|
|
48
|
+
_vefaas_service (VeFaaS): Internal VeFaaS client instance, initialized post-creation.
|
|
49
|
+
_veapig_service (APIGateway): Internal VeAPIG client instance, initialized post-creation.
|
|
50
|
+
_veidentity_service (IdentityClient): Internal Identity client instance, initialized post-creation.
|
|
51
|
+
|
|
52
|
+
Note:
|
|
53
|
+
Credentials must be set via environment variables for default behavior.
|
|
54
|
+
This class performs interactive confirmations for destructive operations like removal.
|
|
55
|
+
|
|
56
|
+
Examples:
|
|
57
|
+
```python
|
|
58
|
+
from veadk.cloud.cloud_agent_engine import CloudAgentEngine
|
|
59
|
+
engine = CloudAgentEngine()
|
|
60
|
+
app = engine.deploy("test-app", "/path/to/local/project")
|
|
61
|
+
print(app.vefaas_endpoint)
|
|
62
|
+
```
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
volcengine_access_key: str = getenv(
|
|
66
|
+
"VOLCENGINE_ACCESS_KEY", "", allow_false_values=True
|
|
67
|
+
)
|
|
68
|
+
volcengine_secret_key: str = getenv(
|
|
69
|
+
"VOLCENGINE_SECRET_KEY", "", allow_false_values=True
|
|
70
|
+
)
|
|
71
|
+
region: str = "cn-beijing"
|
|
72
|
+
|
|
73
|
+
def model_post_init(self, context: Any, /) -> None:
|
|
74
|
+
"""Initializes the internal VeFaaS service after Pydantic model validation.
|
|
75
|
+
|
|
76
|
+
Creates a VeFaaS instance using the configured access key, secret key, and region.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
self: The CloudAgentEngine instance.
|
|
80
|
+
context: Pydantic post-init context parameter (not used).
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
None
|
|
84
|
+
|
|
85
|
+
Note:
|
|
86
|
+
This is a Pydantic lifecycle method, ensuring service readiness after init.
|
|
87
|
+
"""
|
|
88
|
+
self._vefaas_service = VeFaaS(
|
|
89
|
+
access_key=self.volcengine_access_key,
|
|
90
|
+
secret_key=self.volcengine_secret_key,
|
|
91
|
+
region=self.region,
|
|
92
|
+
)
|
|
93
|
+
self._veapig_service = APIGateway(
|
|
94
|
+
access_key=self.volcengine_access_key,
|
|
95
|
+
secret_key=self.volcengine_secret_key,
|
|
96
|
+
region=self.region,
|
|
97
|
+
)
|
|
98
|
+
self._veidentity_service = IdentityClient(
|
|
99
|
+
access_key=self.volcengine_access_key,
|
|
100
|
+
secret_key=self.volcengine_secret_key,
|
|
101
|
+
region=self.region,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def _prepare(self, path: str, name: str):
|
|
105
|
+
"""Prepares the local project for deployment by validating path and name.
|
|
106
|
+
|
|
107
|
+
Checks if the path exists and is a directory, validates application name format.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
path (str): Full or relative path to the local agent project directory.
|
|
111
|
+
name (str): Intended VeFaaS application name.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
None
|
|
115
|
+
|
|
116
|
+
Raises:
|
|
117
|
+
AssertionError: If path does not exist or is not a directory.
|
|
118
|
+
ValueError: If name contains invalid characters like underscores.
|
|
119
|
+
|
|
120
|
+
Note:
|
|
121
|
+
Includes commented code for handling requirements.txt; not executed currently.
|
|
122
|
+
Called internally by deploy and update methods.
|
|
123
|
+
"""
|
|
124
|
+
# basic check
|
|
125
|
+
assert os.path.exists(path), f"Local agent project path `{path}` not exists."
|
|
126
|
+
assert os.path.isdir(path), (
|
|
127
|
+
f"Local agent project path `{path}` is not a directory."
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# VeFaaS application/function name check
|
|
131
|
+
if "_" in name:
|
|
132
|
+
raise ValueError(
|
|
133
|
+
f"Invalid Volcengine FaaS function name `{name}`, please use lowercase letters and numbers, or replace it with a `-` char."
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# # copy user's requirements.txt
|
|
137
|
+
# module = load_module_from_file(
|
|
138
|
+
# module_name="agent_source", file_path=f"{path}/agent.py"
|
|
139
|
+
# )
|
|
140
|
+
|
|
141
|
+
# requirement_file_path = module.agent_run_config.requirement_file_path
|
|
142
|
+
# if Path(requirement_file_path).exists():
|
|
143
|
+
# shutil.copy(requirement_file_path, os.path.join(path, "requirements.txt"))
|
|
144
|
+
|
|
145
|
+
# logger.info(
|
|
146
|
+
# f"Copy requirement file: from {requirement_file_path} to {path}/requirements.txt"
|
|
147
|
+
# )
|
|
148
|
+
# else:
|
|
149
|
+
# logger.warning(
|
|
150
|
+
# f"Requirement file: {requirement_file_path} not found or you have no requirement file in your project. Use a default one."
|
|
151
|
+
# )
|
|
152
|
+
|
|
153
|
+
def _try_launch_fastapi_server(self, path: str):
|
|
154
|
+
"""Tries to start a FastAPI server locally for testing deployment readiness.
|
|
155
|
+
|
|
156
|
+
Runs the project's run.sh script and checks connectivity on port 8000.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
path (str): Path to the local project containing run.sh.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
None
|
|
163
|
+
|
|
164
|
+
Raises:
|
|
165
|
+
RuntimeError: If server startup times out after 30 seconds.
|
|
166
|
+
|
|
167
|
+
Note:
|
|
168
|
+
Sets _FAAS_FUNC_TIMEOUT environment to 900 seconds.
|
|
169
|
+
Streams output to console and terminates process after successful check.
|
|
170
|
+
Assumes run.sh launches server on 0.0.0.0:8000.
|
|
171
|
+
"""
|
|
172
|
+
RUN_SH = f"{path}/run.sh"
|
|
173
|
+
|
|
174
|
+
HOST = "0.0.0.0"
|
|
175
|
+
PORT = 8000
|
|
176
|
+
|
|
177
|
+
# Prepare environment variables
|
|
178
|
+
os.environ["_FAAS_FUNC_TIMEOUT"] = "900"
|
|
179
|
+
env = os.environ.copy()
|
|
180
|
+
|
|
181
|
+
process = subprocess.Popen(
|
|
182
|
+
["bash", RUN_SH],
|
|
183
|
+
stdout=subprocess.PIPE,
|
|
184
|
+
stderr=subprocess.STDOUT,
|
|
185
|
+
text=True,
|
|
186
|
+
env=env,
|
|
187
|
+
bufsize=1,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
timeout = 30
|
|
191
|
+
start_time = time.time()
|
|
192
|
+
|
|
193
|
+
for line in process.stdout: # type: ignore
|
|
194
|
+
print(line, end="")
|
|
195
|
+
|
|
196
|
+
if time.time() - start_time > timeout:
|
|
197
|
+
process.terminate()
|
|
198
|
+
raise RuntimeError(f"FastAPI server failed to start on {HOST}:{PORT}")
|
|
199
|
+
try:
|
|
200
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
201
|
+
s.settimeout(0.1)
|
|
202
|
+
s.connect(("127.0.0.1", PORT))
|
|
203
|
+
logger.info(f"FastAPI server is listening on {HOST}:{PORT}")
|
|
204
|
+
logger.info("Local deplyment test successfully.")
|
|
205
|
+
break
|
|
206
|
+
except (ConnectionRefusedError, socket.timeout):
|
|
207
|
+
continue
|
|
208
|
+
|
|
209
|
+
process.terminate()
|
|
210
|
+
process.wait()
|
|
211
|
+
|
|
212
|
+
def deploy(
|
|
213
|
+
self,
|
|
214
|
+
application_name: str,
|
|
215
|
+
path: str,
|
|
216
|
+
gateway_name: str = "",
|
|
217
|
+
gateway_service_name: str = "",
|
|
218
|
+
gateway_upstream_name: str = "",
|
|
219
|
+
use_adk_web: bool = False,
|
|
220
|
+
auth_method: str = "none",
|
|
221
|
+
identity_user_pool_name: str = "",
|
|
222
|
+
identity_client_name: str = "",
|
|
223
|
+
local_test: bool = False,
|
|
224
|
+
) -> CloudApp:
|
|
225
|
+
"""Deploys a local agent project to Volcengine FaaS, creating necessary resources.
|
|
226
|
+
|
|
227
|
+
Prepares project, optionally tests locally, deploys via VeFaaS, and returns app instance.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
application_name (str): Unique name for the VeFaaS application.
|
|
231
|
+
path (str): Local directory path of the agent project.
|
|
232
|
+
gateway_name (str, optional): Custom gateway resource name. Defaults to timestamped.
|
|
233
|
+
gateway_service_name (str, optional): Custom service name. Defaults to timestamped.
|
|
234
|
+
gateway_upstream_name (str, optional): Custom upstream name. Defaults to timestamped.
|
|
235
|
+
use_adk_web (bool): Enable ADK Web configuration. Defaults to False.
|
|
236
|
+
auth_method (str, optional): Authentication for the agent. Defaults to none.
|
|
237
|
+
identity_user_pool_name (str, optional): Custom user pool name. Defaults to timestamped.
|
|
238
|
+
identity_client_name (str, optional): Custom client name. Defaults to timestamped.
|
|
239
|
+
local_test (bool): Perform FastAPI server test before deploy. Defaults to False.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
CloudApp: Deployed application with endpoint, name, and ID.
|
|
243
|
+
|
|
244
|
+
Raises:
|
|
245
|
+
ValueError: On deployment failure, such as invalid config or VeFaaS errors.
|
|
246
|
+
|
|
247
|
+
Note:
|
|
248
|
+
Converts path to absolute; sets telemetry opt-out and ADK Web env vars.
|
|
249
|
+
Generates default gateway names if not specified.
|
|
250
|
+
|
|
251
|
+
Examples:
|
|
252
|
+
```python
|
|
253
|
+
app = engine.deploy("my-agent", "./agent-project", local_test=True)
|
|
254
|
+
print(f"Deployed at: {app.vefaas_endpoint}")
|
|
255
|
+
```
|
|
256
|
+
"""
|
|
257
|
+
# prevent deepeval writing operations
|
|
258
|
+
veadk_environments["DEEPEVAL_TELEMETRY_OPT_OUT"] = "YES"
|
|
259
|
+
|
|
260
|
+
enable_key_auth = False
|
|
261
|
+
if auth_method == "api-key":
|
|
262
|
+
enable_key_auth = True
|
|
263
|
+
|
|
264
|
+
if use_adk_web:
|
|
265
|
+
veadk_environments["USE_ADK_WEB"] = "True"
|
|
266
|
+
else:
|
|
267
|
+
veadk_environments["USE_ADK_WEB"] = "False"
|
|
268
|
+
|
|
269
|
+
# convert `path` to absolute path
|
|
270
|
+
path = str(Path(path).resolve())
|
|
271
|
+
self._prepare(path, application_name)
|
|
272
|
+
|
|
273
|
+
if local_test:
|
|
274
|
+
self._try_launch_fastapi_server(path)
|
|
275
|
+
|
|
276
|
+
if not gateway_name:
|
|
277
|
+
gateway_name = f"{application_name}-gw-{formatted_timestamp()}"
|
|
278
|
+
if not gateway_service_name:
|
|
279
|
+
gateway_service_name = f"{application_name}-gw-svr-{formatted_timestamp()}"
|
|
280
|
+
if not gateway_upstream_name:
|
|
281
|
+
gateway_upstream_name = f"{application_name}-gw-us-{formatted_timestamp()}"
|
|
282
|
+
if not identity_user_pool_name:
|
|
283
|
+
identity_user_pool_name = (
|
|
284
|
+
f"{application_name}-id-up-{formatted_timestamp()}"
|
|
285
|
+
)
|
|
286
|
+
if not identity_client_name:
|
|
287
|
+
identity_client_name = f"{application_name}-id-cli-{formatted_timestamp()}"
|
|
288
|
+
|
|
289
|
+
try:
|
|
290
|
+
vefaas_application_url, app_id, function_id = self._vefaas_service.deploy(
|
|
291
|
+
path=path,
|
|
292
|
+
name=application_name,
|
|
293
|
+
gateway_name=gateway_name,
|
|
294
|
+
gateway_service_name=gateway_service_name,
|
|
295
|
+
gateway_upstream_name=gateway_upstream_name,
|
|
296
|
+
enable_key_auth=enable_key_auth,
|
|
297
|
+
)
|
|
298
|
+
_ = function_id # for future use
|
|
299
|
+
|
|
300
|
+
veapig_gateway_id, _, veapig_route_id = (
|
|
301
|
+
self._vefaas_service.get_application_route(app_id=app_id)
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
if auth_method == "oauth2":
|
|
305
|
+
# Get or create the Identity user pool.
|
|
306
|
+
identity_user_pool_id = self._veidentity_service.get_user_pool(
|
|
307
|
+
name=identity_user_pool_name,
|
|
308
|
+
)
|
|
309
|
+
if not identity_user_pool_id:
|
|
310
|
+
identity_user_pool_id = self._veidentity_service.create_user_pool(
|
|
311
|
+
name=identity_user_pool_name,
|
|
312
|
+
)
|
|
313
|
+
issuer = f"https://auth.id.{self.region}.volces.com/userpool/{identity_user_pool_id}"
|
|
314
|
+
|
|
315
|
+
# Create APIG upstream for Identity.
|
|
316
|
+
identity_domain = f"auth.id.{self.region}.volces.com"
|
|
317
|
+
veapig_identity_upstream_id = (
|
|
318
|
+
self._veapig_service.check_domain_upstream_exist(
|
|
319
|
+
domain=identity_domain,
|
|
320
|
+
port=443,
|
|
321
|
+
gateway_id=veapig_gateway_id,
|
|
322
|
+
)
|
|
323
|
+
)
|
|
324
|
+
if not veapig_identity_upstream_id:
|
|
325
|
+
veapig_identity_upstream_id = (
|
|
326
|
+
self._veapig_service.create_domain_upstream(
|
|
327
|
+
domain=f"auth.id.{self.region}.volces.com",
|
|
328
|
+
port=443,
|
|
329
|
+
is_https=True,
|
|
330
|
+
gateway_id=veapig_gateway_id,
|
|
331
|
+
upstream_name=f"id-{formatted_timestamp()}",
|
|
332
|
+
)
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
# Create plugin binding.
|
|
336
|
+
plugin_name = ""
|
|
337
|
+
plugin_config = {}
|
|
338
|
+
if use_adk_web:
|
|
339
|
+
# Get or create the Identity client.
|
|
340
|
+
identity_client_id = ""
|
|
341
|
+
identity_client_secret = ""
|
|
342
|
+
identity_client = self._veidentity_service.get_user_pool_client(
|
|
343
|
+
user_pool_uid=identity_user_pool_id,
|
|
344
|
+
name=identity_client_name,
|
|
345
|
+
)
|
|
346
|
+
if identity_client:
|
|
347
|
+
identity_client_id = identity_client[0]
|
|
348
|
+
identity_client_secret = identity_client[1]
|
|
349
|
+
else:
|
|
350
|
+
identity_client_id, identity_client_secret = (
|
|
351
|
+
self._veidentity_service.create_user_pool_client(
|
|
352
|
+
user_pool_uid=identity_user_pool_id,
|
|
353
|
+
name=identity_client_name,
|
|
354
|
+
client_type="WEB_APPLICATION",
|
|
355
|
+
)
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
self._veidentity_service.register_callback_for_user_pool_client(
|
|
359
|
+
user_pool_uid=identity_user_pool_id,
|
|
360
|
+
client_uid=identity_client_id,
|
|
361
|
+
callback_url=f"{vefaas_application_url}/callback",
|
|
362
|
+
web_origin=vefaas_application_url,
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
plugin_name = "wasm-oauth2-sso"
|
|
366
|
+
plugin_config = {
|
|
367
|
+
"AuthorizationUrl": f"{issuer}/authorize",
|
|
368
|
+
"UpstreamId": veapig_identity_upstream_id,
|
|
369
|
+
"TokenUrl": f"{issuer}/oauth/token",
|
|
370
|
+
"RedirectPath": "/callback",
|
|
371
|
+
"SignoutPath": "/signout",
|
|
372
|
+
"ClientId": identity_client_id,
|
|
373
|
+
"ClientSecret": identity_client_secret,
|
|
374
|
+
}
|
|
375
|
+
else:
|
|
376
|
+
plugin_name = "wasm-jwt-auth"
|
|
377
|
+
plugin_config = {
|
|
378
|
+
"RemoteJwks": {
|
|
379
|
+
"UpstreamId": veapig_identity_upstream_id,
|
|
380
|
+
"Url": f"{issuer}/keys",
|
|
381
|
+
},
|
|
382
|
+
"Issuer": issuer,
|
|
383
|
+
"ValidateConsumer": False,
|
|
384
|
+
}
|
|
385
|
+
self._vefaas_service.apig_client.create_plugin_binding(
|
|
386
|
+
scope="ROUTE",
|
|
387
|
+
target=veapig_route_id,
|
|
388
|
+
plugin_name=plugin_name,
|
|
389
|
+
plugin_config=json.dumps(plugin_config),
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
return CloudApp(
|
|
393
|
+
vefaas_application_name=application_name,
|
|
394
|
+
vefaas_endpoint=vefaas_application_url,
|
|
395
|
+
vefaas_application_id=app_id,
|
|
396
|
+
)
|
|
397
|
+
except Exception as e:
|
|
398
|
+
raise ValueError(
|
|
399
|
+
f"Failed to deploy local agent project to Volcengine FaaS platform. Error: {e}"
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
def remove(self, app_name: str):
|
|
403
|
+
"""Deletes a deployed cloud application after user confirmation.
|
|
404
|
+
|
|
405
|
+
Locates app by name, confirms, and issues delete via VeFaaS.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
app_name (str): Name of the application to remove.
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
None
|
|
412
|
+
|
|
413
|
+
Raises:
|
|
414
|
+
ValueError: If application not found by name.
|
|
415
|
+
|
|
416
|
+
Note:
|
|
417
|
+
Interactive prompt required; cancels on non-'y' input.
|
|
418
|
+
Deletion is processed asynchronously by VeFaaS.
|
|
419
|
+
|
|
420
|
+
Examples:
|
|
421
|
+
```python
|
|
422
|
+
engine.remove("my-agent")
|
|
423
|
+
```
|
|
424
|
+
"""
|
|
425
|
+
confirm = input(f"Confirm delete cloud app {app_name}? (y/N): ")
|
|
426
|
+
if confirm.lower() != "y":
|
|
427
|
+
print("Delete cancelled.")
|
|
428
|
+
return
|
|
429
|
+
else:
|
|
430
|
+
app_id = self._vefaas_service.find_app_id_by_name(app_name)
|
|
431
|
+
if not app_id:
|
|
432
|
+
raise ValueError(
|
|
433
|
+
f"Cloud app {app_name} not found, cannot delete it. Please check the app name."
|
|
434
|
+
)
|
|
435
|
+
self._vefaas_service.delete(app_id)
|
|
436
|
+
|
|
437
|
+
def update_function_code(
|
|
438
|
+
self,
|
|
439
|
+
application_name: str,
|
|
440
|
+
path: str,
|
|
441
|
+
) -> CloudApp:
|
|
442
|
+
"""Updates the code in an existing VeFaaS application without changing endpoint.
|
|
443
|
+
|
|
444
|
+
Prepares new code from local path and updates function via VeFaaS.
|
|
445
|
+
|
|
446
|
+
Args:
|
|
447
|
+
application_name (str): Name of the existing application to update.
|
|
448
|
+
path (str): Local path containing updated project files.
|
|
449
|
+
|
|
450
|
+
Returns:
|
|
451
|
+
CloudApp: Updated application instance with same endpoint.
|
|
452
|
+
|
|
453
|
+
Raises:
|
|
454
|
+
ValueError: If update fails due to preparation or VeFaaS issues.
|
|
455
|
+
|
|
456
|
+
Note:
|
|
457
|
+
Preserves gateway and other resources; only function code is updated.
|
|
458
|
+
Path is resolved to absolute before processing.
|
|
459
|
+
|
|
460
|
+
Examples:
|
|
461
|
+
```python
|
|
462
|
+
updated_app = engine.update_function_code("my-agent", "./updated-project")
|
|
463
|
+
```
|
|
464
|
+
"""
|
|
465
|
+
# convert `path` to absolute path
|
|
466
|
+
path = str(Path(path).resolve())
|
|
467
|
+
self._prepare(path, application_name)
|
|
468
|
+
|
|
469
|
+
try:
|
|
470
|
+
vefaas_application_url, app_id, function_id = (
|
|
471
|
+
self._vefaas_service._update_function_code(
|
|
472
|
+
application_name=application_name,
|
|
473
|
+
path=path,
|
|
474
|
+
)
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
return CloudApp(
|
|
478
|
+
vefaas_application_name=application_name,
|
|
479
|
+
vefaas_endpoint=vefaas_application_url,
|
|
480
|
+
vefaas_application_id=app_id,
|
|
481
|
+
)
|
|
482
|
+
except Exception as e:
|
|
483
|
+
raise ValueError(
|
|
484
|
+
f"Failed to update agent project on Volcengine FaaS platform. Error: {e}"
|
|
485
|
+
)
|