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
veadk/__init__.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
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 typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
from veadk.version import VERSION
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from veadk.agent import Agent
|
|
21
|
+
from veadk.runner import Runner
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Lazy loading for `Agent` class
|
|
25
|
+
def __getattr__(name):
|
|
26
|
+
if name == "Agent":
|
|
27
|
+
from veadk.agent import Agent
|
|
28
|
+
|
|
29
|
+
return Agent
|
|
30
|
+
if name == "Runner":
|
|
31
|
+
from veadk.runner import Runner
|
|
32
|
+
|
|
33
|
+
return Runner
|
|
34
|
+
raise AttributeError(f"module 'veadk' has no attribute '{name}'")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__all__ = ["Agent", "Runner", "VERSION"]
|
veadk/a2a/__init__.py
ADDED
|
@@ -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/a2a/agent_card.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
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 a2a.types import AgentCapabilities, AgentCard, AgentProvider, AgentSkill
|
|
16
|
+
|
|
17
|
+
from veadk import Agent
|
|
18
|
+
from veadk.version import VERSION
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_agent_card(
|
|
22
|
+
agent: Agent, url: str, version: str = VERSION, provider: str = "veadk"
|
|
23
|
+
) -> AgentCard:
|
|
24
|
+
agent_provider = AgentProvider(organization=provider, url="")
|
|
25
|
+
agent_capabilities = AgentCapabilities()
|
|
26
|
+
agent_skills = [
|
|
27
|
+
AgentSkill(
|
|
28
|
+
id="0",
|
|
29
|
+
name="chat",
|
|
30
|
+
description="Basically chat with user.",
|
|
31
|
+
tags=["chat", "talk"],
|
|
32
|
+
)
|
|
33
|
+
]
|
|
34
|
+
agent_card = AgentCard(
|
|
35
|
+
capabilities=agent_capabilities,
|
|
36
|
+
description=agent.description,
|
|
37
|
+
name=agent.name,
|
|
38
|
+
defaultInputModes=["text"],
|
|
39
|
+
defaultOutputModes=["text"],
|
|
40
|
+
provider=agent_provider,
|
|
41
|
+
skills=agent_skills,
|
|
42
|
+
url=url,
|
|
43
|
+
version=version,
|
|
44
|
+
)
|
|
45
|
+
return agent_card
|
|
@@ -0,0 +1,390 @@
|
|
|
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 functools
|
|
17
|
+
from typing import AsyncGenerator, Literal, Optional
|
|
18
|
+
|
|
19
|
+
from a2a.client.base_client import BaseClient
|
|
20
|
+
import httpx
|
|
21
|
+
import requests
|
|
22
|
+
from a2a.types import AgentCard
|
|
23
|
+
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
|
|
24
|
+
|
|
25
|
+
from veadk.integrations.ve_identity.utils import generate_headers
|
|
26
|
+
from veadk.utils.auth import VE_TIP_TOKEN_CREDENTIAL_KEY, VE_TIP_TOKEN_HEADER
|
|
27
|
+
from veadk.utils.logger import get_logger
|
|
28
|
+
from google.adk.utils.context_utils import Aclosing
|
|
29
|
+
from google.adk.events.event import Event
|
|
30
|
+
from google.adk.agents.invocation_context import InvocationContext
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
logger = get_logger(__name__)
|
|
34
|
+
|
|
35
|
+
AGENT_CARD_WELL_KNOWN_PATH = "/.well-known/agent-card.json"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _convert_agent_card_dict_to_obj(agent_card_dict: dict) -> AgentCard:
|
|
39
|
+
agent_card_json_str = json.dumps(agent_card_dict, ensure_ascii=False, indent=2)
|
|
40
|
+
agent_card_object = AgentCard.model_validate_json(str(agent_card_json_str))
|
|
41
|
+
return agent_card_object
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class RemoteVeAgent(RemoteA2aAgent):
|
|
45
|
+
"""Connect to a remote agent on the VeFaaS platform.
|
|
46
|
+
|
|
47
|
+
This class provides an interface to remotely connect with an agent deployed on the
|
|
48
|
+
VeFaaS platform. It automatically fetches the agent card (metadata) and configures
|
|
49
|
+
an HTTP client for secure communication.
|
|
50
|
+
|
|
51
|
+
The class extends `RemoteA2aAgent` to provide compatibility with the A2A
|
|
52
|
+
(Agent-to-Agent) communication layer.
|
|
53
|
+
|
|
54
|
+
This constructor handles agent discovery and HTTP client setup. It determines the
|
|
55
|
+
agent's URL, fetches its metadata (`agent_card`), and prepares an
|
|
56
|
+
`httpx.AsyncClient` for subsequent communication. You can either provide a URL
|
|
57
|
+
directly, or pass a pre-configured `httpx.AsyncClient` with a `base_url`.
|
|
58
|
+
|
|
59
|
+
Authentication can be handled via a bearer token in the HTTP header or via a
|
|
60
|
+
query string parameter. If a custom `httpx_client` is provided, authentication
|
|
61
|
+
details will be added to it.
|
|
62
|
+
|
|
63
|
+
Attributes:
|
|
64
|
+
name (str):
|
|
65
|
+
A unique name identifying this remote agent instance.
|
|
66
|
+
url (Optional[str]):
|
|
67
|
+
The base URL of the remote agent. This is optional if an `httpx_client`
|
|
68
|
+
with a configured `base_url` is provided. If both are given, they must
|
|
69
|
+
not conflict.
|
|
70
|
+
auth_token (Optional[str]):
|
|
71
|
+
Optional authentication token used for secure access during initialization.
|
|
72
|
+
If not provided, the agent will be accessed without authentication.
|
|
73
|
+
Note: For runtime authentication, use the credential service in InvocationContext.
|
|
74
|
+
auth_method (Literal["header", "querystring"] | None):
|
|
75
|
+
The method of attaching the authentication token at runtime.
|
|
76
|
+
- `"header"`: Token is retrieved from credential service and passed via HTTP `Authorization` header.
|
|
77
|
+
- `"querystring"`: Token is retrieved from credential service and passed as a query parameter.
|
|
78
|
+
- `None`: No runtime authentication injection (default).
|
|
79
|
+
The credential is loaded from `InvocationContext.credential_service` using the
|
|
80
|
+
app_name and user_id from the context.
|
|
81
|
+
httpx_client (Optional[httpx.AsyncClient]):
|
|
82
|
+
An optional, pre-configured `httpx.AsyncClient` to use for communication.
|
|
83
|
+
This allows for client sharing and advanced configurations (e.g., proxies).
|
|
84
|
+
If its `base_url` is set, it will be used as the agent's location.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
ValueError:
|
|
88
|
+
- If `url` and `httpx_client.base_url` are both provided and conflict.
|
|
89
|
+
- If neither `url` nor an `httpx_client` with a `base_url` is provided.
|
|
90
|
+
- If an unsupported `auth_method` is provided when `auth_token` is set.
|
|
91
|
+
requests.RequestException:
|
|
92
|
+
If fetching the agent card from the remote URL fails.
|
|
93
|
+
|
|
94
|
+
Examples:
|
|
95
|
+
```python
|
|
96
|
+
# Example 1: Connect using a URL (no authentication)
|
|
97
|
+
agent = RemoteVeAgent(
|
|
98
|
+
name="public_agent",
|
|
99
|
+
url="https://vefaas.example.com/agents/public"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Example 2: Using static Bearer token in header for initialization
|
|
103
|
+
agent = RemoteVeAgent(
|
|
104
|
+
name="secured_agent",
|
|
105
|
+
url="https://vefaas.example.com/agents/secure",
|
|
106
|
+
auth_token="my_secret_token",
|
|
107
|
+
auth_method="header"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Example 3: Using runtime authentication with credential service
|
|
111
|
+
# The auth token will be automatically injected from InvocationContext.credential_service
|
|
112
|
+
agent = RemoteVeAgent(
|
|
113
|
+
name="dynamic_auth_agent",
|
|
114
|
+
url="https://vefaas.example.com/agents/secure",
|
|
115
|
+
auth_method="header" # Will load credential at runtime
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Example 4: Using a pre-configured httpx_client
|
|
119
|
+
import httpx
|
|
120
|
+
client = httpx.AsyncClient(
|
|
121
|
+
base_url="https://vefaas.example.com/agents/query",
|
|
122
|
+
timeout=600
|
|
123
|
+
)
|
|
124
|
+
agent = RemoteVeAgent(
|
|
125
|
+
name="query_agent",
|
|
126
|
+
auth_method="querystring", # Will load credential at runtime
|
|
127
|
+
httpx_client=client
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
auth_method: Literal["header", "querystring"] | None = None
|
|
133
|
+
|
|
134
|
+
def __init__(
|
|
135
|
+
self,
|
|
136
|
+
name: str,
|
|
137
|
+
url: Optional[str] = None,
|
|
138
|
+
auth_token: Optional[str] = None,
|
|
139
|
+
auth_method: Literal["header", "querystring"] | None = None,
|
|
140
|
+
httpx_client: Optional[httpx.AsyncClient] = None,
|
|
141
|
+
):
|
|
142
|
+
# Determine the effective URL for the agent and handle conflicts.
|
|
143
|
+
effective_url = url
|
|
144
|
+
if httpx_client and httpx_client.base_url:
|
|
145
|
+
client_url_str = str(httpx_client.base_url).rstrip("/")
|
|
146
|
+
if url and url.rstrip("/") != client_url_str:
|
|
147
|
+
raise ValueError(
|
|
148
|
+
f"The `url` parameter ('{url}') conflicts with the `base_url` of the provided "
|
|
149
|
+
f"httpx_client ('{client_url_str}'). Please provide only one or ensure they match."
|
|
150
|
+
)
|
|
151
|
+
effective_url = client_url_str
|
|
152
|
+
|
|
153
|
+
if not effective_url:
|
|
154
|
+
raise ValueError(
|
|
155
|
+
"Could not determine agent URL. Please provide the `url` parameter or an `httpx_client` with a configured `base_url`."
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
req_headers = {}
|
|
159
|
+
req_params = {}
|
|
160
|
+
|
|
161
|
+
if auth_token:
|
|
162
|
+
if auth_method == "header":
|
|
163
|
+
req_headers = {"Authorization": f"Bearer {auth_token}"}
|
|
164
|
+
elif auth_method == "querystring":
|
|
165
|
+
req_params = {"token": auth_token}
|
|
166
|
+
elif auth_method:
|
|
167
|
+
raise ValueError(
|
|
168
|
+
f"Unsupported auth method {auth_method}, use `header` or `querystring` instead."
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
agent_card_dict = requests.get(
|
|
172
|
+
effective_url + AGENT_CARD_WELL_KNOWN_PATH,
|
|
173
|
+
headers=req_headers,
|
|
174
|
+
params=req_params,
|
|
175
|
+
).json()
|
|
176
|
+
# replace agent_card_url with actual host
|
|
177
|
+
agent_card_dict["url"] = effective_url
|
|
178
|
+
|
|
179
|
+
agent_card_object = _convert_agent_card_dict_to_obj(agent_card_dict)
|
|
180
|
+
|
|
181
|
+
logger.debug(f"Agent card of {name}: {agent_card_object}")
|
|
182
|
+
|
|
183
|
+
client_was_provided = httpx_client is not None
|
|
184
|
+
client_to_use = httpx_client
|
|
185
|
+
|
|
186
|
+
if client_was_provided:
|
|
187
|
+
# If a client was provided, update it with auth info
|
|
188
|
+
if auth_token:
|
|
189
|
+
if auth_method == "header":
|
|
190
|
+
client_to_use.headers.update(req_headers)
|
|
191
|
+
elif auth_method == "querystring":
|
|
192
|
+
new_params = dict(client_to_use.params)
|
|
193
|
+
new_params.update(req_params)
|
|
194
|
+
client_to_use.params = new_params
|
|
195
|
+
else:
|
|
196
|
+
# If no client was provided, create a new one with auth info
|
|
197
|
+
if auth_token:
|
|
198
|
+
if auth_method == "header":
|
|
199
|
+
client_to_use = httpx.AsyncClient(
|
|
200
|
+
base_url=effective_url, headers=req_headers, timeout=600
|
|
201
|
+
)
|
|
202
|
+
elif auth_method == "querystring":
|
|
203
|
+
client_to_use = httpx.AsyncClient(
|
|
204
|
+
base_url=effective_url, params=req_params, timeout=600
|
|
205
|
+
)
|
|
206
|
+
else: # No auth, no client provided
|
|
207
|
+
client_to_use = httpx.AsyncClient(base_url=effective_url, timeout=600)
|
|
208
|
+
|
|
209
|
+
super().__init__(
|
|
210
|
+
name=name, agent_card=agent_card_object, httpx_client=client_to_use
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# The parent class sets _httpx_client_needs_cleanup based on whether
|
|
214
|
+
# the httpx_client it received was None. Since we always pass a
|
|
215
|
+
# client (either the user's or one we create), it will always set
|
|
216
|
+
# it to False. We must override this to ensure clients we create
|
|
217
|
+
# are properly cleaned up.
|
|
218
|
+
if not client_was_provided:
|
|
219
|
+
self._httpx_client_needs_cleanup = True
|
|
220
|
+
|
|
221
|
+
# Set auth_method if provided
|
|
222
|
+
if auth_method:
|
|
223
|
+
self.auth_method = auth_method
|
|
224
|
+
|
|
225
|
+
# Wrap _run_async_impl with pre-run hook to ensure initialization
|
|
226
|
+
# and authentication logic always executes, even if users override _run_async_impl
|
|
227
|
+
self._wrap_run_async_impl()
|
|
228
|
+
|
|
229
|
+
def _wrap_run_async_impl(self) -> None:
|
|
230
|
+
"""Wrap _run_async_impl with a decorator that ensures pre-run logic executes.
|
|
231
|
+
|
|
232
|
+
This method wraps the _run_async_impl method with a decorator that:
|
|
233
|
+
1. Executes _pre_run before the actual implementation
|
|
234
|
+
2. Handles errors from _pre_run and yields error events
|
|
235
|
+
3. Ensures the wrapper works even if users override _run_async_impl
|
|
236
|
+
|
|
237
|
+
The wrapper is applied by replacing the bound method on the instance.
|
|
238
|
+
"""
|
|
239
|
+
# Store the original _run_async_impl method
|
|
240
|
+
original_run_async_impl = self._run_async_impl
|
|
241
|
+
|
|
242
|
+
@functools.wraps(original_run_async_impl)
|
|
243
|
+
async def wrapped_run_async_impl(
|
|
244
|
+
ctx: InvocationContext,
|
|
245
|
+
) -> AsyncGenerator[Event, None]:
|
|
246
|
+
"""Wrapped version of _run_async_impl with pre-run hook."""
|
|
247
|
+
# Execute pre-run initialization
|
|
248
|
+
try:
|
|
249
|
+
await self._pre_run(ctx)
|
|
250
|
+
except Exception as e:
|
|
251
|
+
yield Event(
|
|
252
|
+
author=self.name,
|
|
253
|
+
error_message=f"Failed to initialize remote A2A agent: {e}",
|
|
254
|
+
invocation_id=ctx.invocation_id,
|
|
255
|
+
branch=ctx.branch,
|
|
256
|
+
)
|
|
257
|
+
return
|
|
258
|
+
|
|
259
|
+
# Call the original (or overridden) _run_async_impl
|
|
260
|
+
async with Aclosing(original_run_async_impl(ctx)) as agen:
|
|
261
|
+
async for event in agen:
|
|
262
|
+
yield event
|
|
263
|
+
|
|
264
|
+
# Replace the instance method with the wrapped version
|
|
265
|
+
self._run_async_impl = wrapped_run_async_impl
|
|
266
|
+
|
|
267
|
+
async def _pre_run(self, ctx: InvocationContext) -> None:
|
|
268
|
+
"""Pre-run initialization and authentication setup.
|
|
269
|
+
|
|
270
|
+
This method is called before the actual agent execution to:
|
|
271
|
+
1. Ensure the agent is resolved (agent card fetched, client initialized)
|
|
272
|
+
2. Inject authentication token from credential service if available
|
|
273
|
+
|
|
274
|
+
This method is separated from _run_async_impl to ensure these critical
|
|
275
|
+
initialization steps are always executed, even if users override _run_async_impl.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
ctx: Invocation context containing session and user information
|
|
279
|
+
|
|
280
|
+
Raises:
|
|
281
|
+
Exception: If agent initialization fails
|
|
282
|
+
"""
|
|
283
|
+
# Ensure agent is resolved
|
|
284
|
+
await self._ensure_resolved()
|
|
285
|
+
|
|
286
|
+
# Inject auth token if credential service is available
|
|
287
|
+
await self._inject_auth_token(ctx)
|
|
288
|
+
|
|
289
|
+
async def _inject_auth_token(self, ctx: InvocationContext) -> None:
|
|
290
|
+
"""Inject authentication token from credential service into the HTTP client.
|
|
291
|
+
|
|
292
|
+
This method retrieves the authentication token from the credential service
|
|
293
|
+
in the InvocationContext and updates the HTTP client headers or query params
|
|
294
|
+
based on the configured auth_method.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
ctx: Invocation context containing credential service and user information
|
|
298
|
+
"""
|
|
299
|
+
# Skip if no credential service in context
|
|
300
|
+
if not ctx.credential_service:
|
|
301
|
+
logger.debug(
|
|
302
|
+
"No credential service in InvocationContext, skipping auth token injection"
|
|
303
|
+
)
|
|
304
|
+
return
|
|
305
|
+
|
|
306
|
+
# Skip if client is not initialized or not a BaseClient
|
|
307
|
+
if not hasattr(self, "_a2a_client") or not isinstance(
|
|
308
|
+
self._a2a_client, BaseClient
|
|
309
|
+
):
|
|
310
|
+
logger.debug(
|
|
311
|
+
"A2A client not initialized or not a BaseClient, skipping auth token injection"
|
|
312
|
+
)
|
|
313
|
+
return
|
|
314
|
+
|
|
315
|
+
# Skip if transport is not available
|
|
316
|
+
if not hasattr(self._a2a_client, "_transport"):
|
|
317
|
+
logger.debug(
|
|
318
|
+
"A2A client transport not available, skipping auth token injection"
|
|
319
|
+
)
|
|
320
|
+
return
|
|
321
|
+
|
|
322
|
+
# Skip if httpx_client is not available
|
|
323
|
+
if not hasattr(self._a2a_client._transport, "httpx_client"):
|
|
324
|
+
logger.debug(
|
|
325
|
+
"A2A client httpx_client not available, skipping auth token injection"
|
|
326
|
+
)
|
|
327
|
+
return
|
|
328
|
+
|
|
329
|
+
try:
|
|
330
|
+
from veadk.utils.auth import build_auth_config
|
|
331
|
+
from google.adk.agents.callback_context import CallbackContext
|
|
332
|
+
|
|
333
|
+
# Inject TIP token via header
|
|
334
|
+
workload_auth_config = build_auth_config(
|
|
335
|
+
auth_method="apikey",
|
|
336
|
+
credential_key=VE_TIP_TOKEN_CREDENTIAL_KEY,
|
|
337
|
+
header_name=VE_TIP_TOKEN_HEADER,
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
tip_credential = await ctx.credential_service.load_credential(
|
|
341
|
+
auth_config=workload_auth_config,
|
|
342
|
+
callback_context=CallbackContext(ctx),
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
if tip_credential:
|
|
346
|
+
self._a2a_client._transport.httpx_client.headers.update(
|
|
347
|
+
{VE_TIP_TOKEN_HEADER: tip_credential.api_key}
|
|
348
|
+
)
|
|
349
|
+
logger.debug(
|
|
350
|
+
f"Injected TIP token via header for app={ctx.app_name}, user={ctx.user_id}"
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
# Build auth config based on auth_method
|
|
354
|
+
auth_config = build_auth_config(
|
|
355
|
+
credential_key="inbound_auth",
|
|
356
|
+
auth_method=self.auth_method or "header",
|
|
357
|
+
header_scheme="bearer",
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
# Load credential from credential service
|
|
361
|
+
credential = await ctx.credential_service.load_credential(
|
|
362
|
+
auth_config=auth_config,
|
|
363
|
+
callback_context=CallbackContext(ctx),
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
if not credential:
|
|
367
|
+
logger.debug(
|
|
368
|
+
f"No credential loaded, skipping auth token injection for app={ctx.app_name}, user={ctx.user_id}"
|
|
369
|
+
)
|
|
370
|
+
return
|
|
371
|
+
|
|
372
|
+
# Inject credential based on auth_method
|
|
373
|
+
if self.auth_method == "querystring":
|
|
374
|
+
# Extract API key
|
|
375
|
+
api_key = credential.api_key
|
|
376
|
+
new_params = dict(self._a2a_client._transport.httpx_client.params)
|
|
377
|
+
new_params.update({"token": api_key})
|
|
378
|
+
self._a2a_client._transport.httpx_client.params = new_params
|
|
379
|
+
logger.debug(
|
|
380
|
+
f"Injected auth token via querystring for app={ctx.app_name}, user={ctx.user_id}"
|
|
381
|
+
)
|
|
382
|
+
else:
|
|
383
|
+
if headers := generate_headers(credential):
|
|
384
|
+
self._a2a_client._transport.httpx_client.headers.update(headers)
|
|
385
|
+
logger.debug(
|
|
386
|
+
f"Injected auth token via header for app={ctx.app_name}, user={ctx.user_id}"
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
except Exception as e:
|
|
390
|
+
logger.warning(f"Failed to inject auth token: {e}", exc_info=True)
|
|
@@ -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.
|
|
@@ -0,0 +1,170 @@
|
|
|
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
|
+
from typing import Literal, Optional, Union
|
|
17
|
+
|
|
18
|
+
from a2a.types import AgentCard
|
|
19
|
+
from google.adk.agents import BaseAgent
|
|
20
|
+
from starlette.applications import Starlette
|
|
21
|
+
from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService
|
|
22
|
+
from google.adk.sessions.in_memory_session_service import InMemorySessionService
|
|
23
|
+
from google.adk.memory.in_memory_memory_service import InMemoryMemoryService
|
|
24
|
+
from google.adk.a2a.utils.agent_to_a2a import to_a2a as google_adk_to_a2a
|
|
25
|
+
from veadk import Runner
|
|
26
|
+
from veadk.a2a.ve_middlewares import build_a2a_auth_middleware
|
|
27
|
+
from veadk.auth.ve_credential_service import VeCredentialService
|
|
28
|
+
from veadk.consts import DEFAULT_AGENT_NAME
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def to_a2a(
|
|
32
|
+
agent: BaseAgent,
|
|
33
|
+
*,
|
|
34
|
+
host: str = "localhost",
|
|
35
|
+
port: int = 8000,
|
|
36
|
+
protocol: str = "http",
|
|
37
|
+
agent_card: Optional[Union[AgentCard, str]] = None,
|
|
38
|
+
runner: Optional[Runner] = None,
|
|
39
|
+
enable_auth: bool = False,
|
|
40
|
+
auth_method: Literal["header", "querystring"] = "header",
|
|
41
|
+
) -> Starlette:
|
|
42
|
+
"""Convert an ADK agent to a A2A Starlette application with optional VeADK enhancements.
|
|
43
|
+
|
|
44
|
+
This function wraps Google ADK's to_a2a utility and optionally adds:
|
|
45
|
+
- VeCredentialService for authentication management
|
|
46
|
+
- A2A authentication middleware for token validation
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
agent: The ADK agent to convert to A2A server
|
|
50
|
+
host: The host for the A2A RPC URL (default: "localhost")
|
|
51
|
+
port: The port for the A2A RPC URL (default: 8000)
|
|
52
|
+
protocol: The protocol for the A2A RPC URL (default: "http")
|
|
53
|
+
agent_card: Optional pre-built AgentCard object or path to agent card
|
|
54
|
+
JSON. If not provided, will be built automatically from the
|
|
55
|
+
agent.
|
|
56
|
+
runner: Optional pre-built Runner object. If not provided, a default
|
|
57
|
+
runner will be created using in-memory services.
|
|
58
|
+
When enable_auth=True:
|
|
59
|
+
- If runner is provided and has a credential_service, it must be
|
|
60
|
+
a VeCredentialService instance (raises TypeError otherwise)
|
|
61
|
+
- If runner is provided without credential_service, a new
|
|
62
|
+
VeCredentialService will be created and set
|
|
63
|
+
- If runner is not provided, a new runner with VeCredentialService
|
|
64
|
+
will be created
|
|
65
|
+
auth_method: Authentication method for A2A requests (only used when
|
|
66
|
+
enable_auth=True). Options:
|
|
67
|
+
- "header": Extract token from Authorization header (default)
|
|
68
|
+
- "querystring": Extract token from query parameter
|
|
69
|
+
enable_auth: Whether to enable VeADK authentication features.
|
|
70
|
+
When True, enables credential service and auth middleware.
|
|
71
|
+
When False, uses standard Google ADK behavior.
|
|
72
|
+
Default: False
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
A Starlette application that can be run with uvicorn
|
|
76
|
+
|
|
77
|
+
Raises:
|
|
78
|
+
TypeError: If enable_auth=True and runner has a credential_service
|
|
79
|
+
that is not a VeCredentialService instance
|
|
80
|
+
|
|
81
|
+
Example:
|
|
82
|
+
Basic usage (without VeADK auth):
|
|
83
|
+
```python
|
|
84
|
+
from veadk import Agent
|
|
85
|
+
from veadk.a2a.utils.agent_to_a2a import to_a2a
|
|
86
|
+
|
|
87
|
+
agent = Agent(name="my_agent", tools=[...])
|
|
88
|
+
app = to_a2a(agent, host="localhost", port=8000)
|
|
89
|
+
# Run with: uvicorn module:app --host localhost --port 8000
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
With VeADK authentication enabled:
|
|
93
|
+
```python
|
|
94
|
+
app = to_a2a(agent, enable_auth=True)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
With custom runner and VeADK auth:
|
|
98
|
+
```python
|
|
99
|
+
from veadk import Agent, Runner
|
|
100
|
+
from veadk.memory.short_term_memory import ShortTermMemory
|
|
101
|
+
from veadk.auth.ve_credential_service import VeCredentialService
|
|
102
|
+
|
|
103
|
+
agent = Agent(name="my_agent")
|
|
104
|
+
runner = Runner(
|
|
105
|
+
agent=agent,
|
|
106
|
+
short_term_memory=ShortTermMemory(),
|
|
107
|
+
app_name="my_app",
|
|
108
|
+
credential_service=VeCredentialService() # Optional
|
|
109
|
+
)
|
|
110
|
+
app = to_a2a(agent, runner=runner, enable_auth=True)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
With querystring authentication:
|
|
114
|
+
```python
|
|
115
|
+
app = to_a2a(agent, enable_auth=True, auth_method="querystring")
|
|
116
|
+
```
|
|
117
|
+
"""
|
|
118
|
+
app_name = agent.name or DEFAULT_AGENT_NAME
|
|
119
|
+
middleware = None # May need support multiple middlewares in the future
|
|
120
|
+
|
|
121
|
+
# Handle VeADK authentication setup
|
|
122
|
+
if enable_auth:
|
|
123
|
+
# Create credential service if not provided
|
|
124
|
+
credential_service = VeCredentialService()
|
|
125
|
+
if runner is not None:
|
|
126
|
+
# Check if runner has credential_service
|
|
127
|
+
if runner.credential_service is not None:
|
|
128
|
+
# Validate that it's a VeCredentialService
|
|
129
|
+
if not isinstance(runner.credential_service, VeCredentialService):
|
|
130
|
+
raise TypeError(
|
|
131
|
+
f"When enable_auth=True, runner.credential_service must be "
|
|
132
|
+
f"a VeCredentialService instance, got {type(runner.credential_service).__name__}"
|
|
133
|
+
)
|
|
134
|
+
# Use existing credential service
|
|
135
|
+
credential_service = runner.credential_service
|
|
136
|
+
else:
|
|
137
|
+
# Add credential_service to runner
|
|
138
|
+
runner.credential_service = credential_service
|
|
139
|
+
else:
|
|
140
|
+
# Create runner with credential_service
|
|
141
|
+
runner = Runner(
|
|
142
|
+
app_name=app_name,
|
|
143
|
+
agent=agent,
|
|
144
|
+
artifact_service=InMemoryArtifactService(),
|
|
145
|
+
session_service=InMemorySessionService(),
|
|
146
|
+
memory_service=InMemoryMemoryService(),
|
|
147
|
+
credential_service=credential_service,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
middleware = build_a2a_auth_middleware(
|
|
151
|
+
app_name=app_name,
|
|
152
|
+
credential_service=credential_service,
|
|
153
|
+
auth_method=auth_method,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Convert agent to A2A Starlette app using Google ADK utility
|
|
157
|
+
app: Starlette = google_adk_to_a2a(
|
|
158
|
+
agent=agent,
|
|
159
|
+
host=host,
|
|
160
|
+
port=port,
|
|
161
|
+
protocol=protocol,
|
|
162
|
+
agent_card=agent_card,
|
|
163
|
+
runner=runner,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# Add VeADK authentication middleware only if enabled
|
|
167
|
+
if middleware:
|
|
168
|
+
app.add_middleware(middleware)
|
|
169
|
+
|
|
170
|
+
return app
|