solace-agent-mesh 1.1.0__py3-none-any.whl → 1.3.1__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.
Potentially problematic release.
This version of solace-agent-mesh might be problematic. Click here for more details.
- solace_agent_mesh/agent/adk/runner.py +18 -12
- solace_agent_mesh/agent/adk/services.py +3 -3
- solace_agent_mesh/agent/adk/setup.py +141 -34
- solace_agent_mesh/agent/protocol/event_handlers.py +27 -21
- solace_agent_mesh/agent/sac/app.py +0 -1
- solace_agent_mesh/agent/sac/component.py +0 -1
- solace_agent_mesh/agent/tools/__init__.py +1 -0
- solace_agent_mesh/agent/tools/dynamic_tool.py +362 -0
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.d97b8e94.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/483cef9a.4e972867.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55f47984.cf3781c4.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/664b740a.1b744a32.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/75384d09.c193a8f0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9a09e75d.d6607c56.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/aba87c2f.071e2d94.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.4d8dda10.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c835a94d.146e3186.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.7334119c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.1c79039d.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.858117b7.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +29 -0
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +25 -0
- solace_agent_mesh/assets/docs/docs/documentation/{migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html → Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html } +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/{migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html → Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html } +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +19 -27
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +5 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +63 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
- solace_agent_mesh/assets/docs/lunr-index-1757531604543.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1757531604543.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/assets/docs/sitemap.xml +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
- solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
- solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
- solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
- solace_agent_mesh/cli/commands/run_cmd.py +5 -3
- solace_agent_mesh/cli/utils.py +68 -12
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-CAX9u8a7.js +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/client-DXU9SPI5.js +25 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C1k9E0aC.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-B0BEKoAR.js +390 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
- solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
- solace_agent_mesh/config_portal/backend/common.py +2 -2
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
- solace_agent_mesh/evaluation/message_organizer.py +35 -56
- solace_agent_mesh/evaluation/run.py +26 -5
- solace_agent_mesh/evaluation/subscriber.py +35 -10
- solace_agent_mesh/evaluation/summary_builder.py +27 -34
- solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
- solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
- solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
- solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
- solace_agent_mesh/gateway/http_sse/app.py +31 -1
- solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
- solace_agent_mesh/gateway/http_sse/component.py +224 -62
- solace_agent_mesh/gateway/http_sse/dependencies.py +148 -45
- solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
- solace_agent_mesh/gateway/http_sse/main.py +291 -87
- solace_agent_mesh/gateway/http_sse/routers/{agents.py → agent_cards.py} +7 -7
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +121 -54
- solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +83 -2
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
- solace_agent_mesh/gateway/http_sse/services/{agent_service.py → agent_card_service.py} +19 -19
- solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
- solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
- solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
- solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
- solace_agent_mesh/templates/shared_config.yaml +4 -5
- solace_agent_mesh/templates/webui.yaml +8 -10
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/METADATA +5 -3
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/RECORD +150 -104
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.8ccb9901.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/55f47984.c484bf96.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6e0db977.39a79ca9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/75384d09.bf78fbdb.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/aba87c2f.76376d7c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.a75ecc0d.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1756992446316.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1756992446316.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
- solace_agent_mesh/client/webui/frontend/static/assets/main-C0jZjYa8.js +0 -699
- solace_agent_mesh/client/webui/frontend/static/assets/main-CCeG324-.css +0 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -85
- solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
- /solace_agent_mesh/assets/docs/assets/js/{main.a75ecc0d.js.LICENSE.txt → main.1c79039d.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -73,18 +73,21 @@ async def run_adk_async_task_thread_wrapper(
|
|
|
73
73
|
|
|
74
74
|
if adk_session and component.session_service:
|
|
75
75
|
context_setting_invocation_id = logical_task_id
|
|
76
|
-
|
|
77
|
-
invocation_id=context_setting_invocation_id,
|
|
78
|
-
author="A2A_Host_System",
|
|
79
|
-
content=adk_types.Content(
|
|
80
|
-
parts=[
|
|
81
|
-
adk_types.Part(text="Initializing A2A context for task run.")
|
|
82
|
-
]
|
|
83
|
-
),
|
|
84
|
-
actions=EventActions(state_delta={"a2a_context": a2a_context}),
|
|
85
|
-
branch=None,
|
|
86
|
-
)
|
|
76
|
+
original_message = a2a_context.pop("original_solace_message", None)
|
|
87
77
|
try:
|
|
78
|
+
context_setting_event = ADKEvent(
|
|
79
|
+
invocation_id=context_setting_invocation_id,
|
|
80
|
+
author="A2A_Host_System",
|
|
81
|
+
content=adk_types.Content(
|
|
82
|
+
parts=[
|
|
83
|
+
adk_types.Part(
|
|
84
|
+
text="Initializing A2A context for task run."
|
|
85
|
+
)
|
|
86
|
+
]
|
|
87
|
+
),
|
|
88
|
+
actions=EventActions(state_delta={"a2a_context": a2a_context}),
|
|
89
|
+
branch=None,
|
|
90
|
+
)
|
|
88
91
|
await component.session_service.append_event(
|
|
89
92
|
session=adk_session, event=context_setting_event
|
|
90
93
|
)
|
|
@@ -96,12 +99,15 @@ async def run_adk_async_task_thread_wrapper(
|
|
|
96
99
|
)
|
|
97
100
|
except Exception as e_append:
|
|
98
101
|
log.error(
|
|
99
|
-
"%s Failed to append context-setting event for task %s: %s.
|
|
102
|
+
"%s Failed to append context-setting event for task %s: %s.",
|
|
100
103
|
component.log_identifier,
|
|
101
104
|
logical_task_id,
|
|
102
105
|
e_append,
|
|
103
106
|
exc_info=True,
|
|
104
107
|
)
|
|
108
|
+
finally:
|
|
109
|
+
if original_message:
|
|
110
|
+
a2a_context["original_solace_message"] = original_message
|
|
105
111
|
else:
|
|
106
112
|
log.warning(
|
|
107
113
|
"%s Could not inject a2a_context into ADK session state via event for task %s (session or session_service invalid). Tool scope filtering might not work.",
|
|
@@ -174,11 +174,11 @@ def initialize_session_service(component) -> BaseSessionService:
|
|
|
174
174
|
|
|
175
175
|
if service_type == "memory":
|
|
176
176
|
return InMemorySessionService()
|
|
177
|
-
elif service_type == "
|
|
178
|
-
db_url = config.get("
|
|
177
|
+
elif service_type == "sql":
|
|
178
|
+
db_url = config.get("database_url")
|
|
179
179
|
if not db_url:
|
|
180
180
|
raise ValueError(
|
|
181
|
-
f"{component.log_identifier} '
|
|
181
|
+
f"{component.log_identifier} 'database_url' is required for sql session service."
|
|
182
182
|
)
|
|
183
183
|
try:
|
|
184
184
|
return DatabaseSessionService(db_url=db_url)
|
|
@@ -18,7 +18,6 @@ from google.adk import tools as adk_tools_module
|
|
|
18
18
|
from google.adk.agents.callback_context import CallbackContext
|
|
19
19
|
from google.adk.models.llm_request import LlmRequest
|
|
20
20
|
from google.adk.models.llm_response import LlmResponse
|
|
21
|
-
from google.adk.tools.mcp_tool import MCPToolset
|
|
22
21
|
from google.adk.tools.mcp_tool.mcp_session_manager import (
|
|
23
22
|
SseServerParams,
|
|
24
23
|
StdioConnectionParams,
|
|
@@ -28,12 +27,49 @@ from mcp import StdioServerParameters
|
|
|
28
27
|
|
|
29
28
|
from ..tools.registry import tool_registry
|
|
30
29
|
from ..tools.tool_definition import BuiltinTool
|
|
30
|
+
from ..tools.dynamic_tool import DynamicTool, DynamicToolProvider
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
from ...agent.adk import callbacks as adk_callbacks
|
|
34
34
|
from ...agent.adk.models.lite_llm import LiteLlm
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def _find_dynamic_tool_class(module) -> Optional[type]:
|
|
38
|
+
"""Finds a single non-abstract DynamicTool subclass in a module."""
|
|
39
|
+
found_classes = []
|
|
40
|
+
for name, obj in inspect.getmembers(module, inspect.isclass):
|
|
41
|
+
if (
|
|
42
|
+
issubclass(obj, DynamicTool)
|
|
43
|
+
and obj is not DynamicTool
|
|
44
|
+
and not inspect.isabstract(obj)
|
|
45
|
+
):
|
|
46
|
+
found_classes.append(obj)
|
|
47
|
+
if len(found_classes) > 1:
|
|
48
|
+
raise TypeError(
|
|
49
|
+
f"Module '{module.__name__}' contains multiple DynamicTool subclasses. "
|
|
50
|
+
"Please specify which one to use with 'class_name' in the config."
|
|
51
|
+
)
|
|
52
|
+
return found_classes[0] if found_classes else None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _find_dynamic_tool_provider_class(module) -> Optional[type]:
|
|
56
|
+
"""Finds a single non-abstract DynamicToolProvider subclass in a module."""
|
|
57
|
+
found_classes = []
|
|
58
|
+
for name, obj in inspect.getmembers(module, inspect.isclass):
|
|
59
|
+
if (
|
|
60
|
+
issubclass(obj, DynamicToolProvider)
|
|
61
|
+
and obj is not DynamicToolProvider
|
|
62
|
+
and not inspect.isabstract(obj)
|
|
63
|
+
):
|
|
64
|
+
found_classes.append(obj)
|
|
65
|
+
if len(found_classes) > 1:
|
|
66
|
+
raise TypeError(
|
|
67
|
+
f"Module '{module.__name__}' contains multiple DynamicToolProvider subclasses. "
|
|
68
|
+
"Only one is permitted per module."
|
|
69
|
+
)
|
|
70
|
+
return found_classes[0] if found_classes else None
|
|
71
|
+
|
|
72
|
+
|
|
37
73
|
async def load_adk_tools(
|
|
38
74
|
component,
|
|
39
75
|
) -> Tuple[List[Union[BaseTool, Callable]], List[BuiltinTool]]:
|
|
@@ -90,48 +126,119 @@ async def load_adk_tools(
|
|
|
90
126
|
try:
|
|
91
127
|
if tool_type == "python":
|
|
92
128
|
module_name = tool_config.get("component_module")
|
|
93
|
-
function_name = tool_config.get("function_name")
|
|
94
|
-
tool_name = tool_config.get("tool_name")
|
|
95
|
-
tool_description = tool_config.get("tool_description")
|
|
96
129
|
base_path = tool_config.get("component_base_path")
|
|
97
|
-
if not module_name
|
|
130
|
+
if not module_name:
|
|
98
131
|
raise ValueError(
|
|
99
|
-
"'component_module'
|
|
132
|
+
"'component_module' is required for python tools."
|
|
100
133
|
)
|
|
101
|
-
|
|
102
134
|
module = import_module(module_name, base_path=base_path)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
135
|
+
|
|
136
|
+
# Case 1: Simple function-based tool
|
|
137
|
+
if "function_name" in tool_config:
|
|
138
|
+
function_name = tool_config.get("function_name")
|
|
139
|
+
tool_name = tool_config.get("tool_name")
|
|
140
|
+
tool_description = tool_config.get("tool_description")
|
|
141
|
+
|
|
142
|
+
func = getattr(module, function_name)
|
|
143
|
+
if not callable(func):
|
|
144
|
+
raise TypeError(
|
|
145
|
+
f"'{function_name}' in module '{module_name}' is not callable."
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
specific_tool_config = tool_config.get("tool_config")
|
|
149
|
+
tool_callable = ADKToolWrapper(
|
|
150
|
+
func,
|
|
151
|
+
specific_tool_config,
|
|
152
|
+
function_name,
|
|
153
|
+
origin="python",
|
|
154
|
+
raw_string_args=tool_config.get("raw_string_args", []),
|
|
107
155
|
)
|
|
108
156
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
157
|
+
if tool_name:
|
|
158
|
+
function_name = tool_name
|
|
159
|
+
tool_callable.__name__ = tool_name
|
|
160
|
+
|
|
161
|
+
if tool_description:
|
|
162
|
+
tool_callable.__doc__ = tool_description
|
|
163
|
+
|
|
164
|
+
_check_and_register_tool_name(
|
|
165
|
+
function_name, f"python:{module_name}"
|
|
166
|
+
)
|
|
167
|
+
loaded_tools.append(tool_callable)
|
|
168
|
+
log.info(
|
|
169
|
+
"%s Loaded Python tool: %s from %s.",
|
|
170
|
+
component.log_identifier,
|
|
171
|
+
function_name,
|
|
172
|
+
module_name,
|
|
173
|
+
)
|
|
174
|
+
# Case 2: Advanced class-based dynamic tool or provider
|
|
175
|
+
else:
|
|
176
|
+
specific_tool_config = tool_config.get("tool_config")
|
|
177
|
+
dynamic_tools = []
|
|
117
178
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
179
|
+
# Determine the class to load
|
|
180
|
+
tool_class = None
|
|
181
|
+
class_name = tool_config.get("class_name")
|
|
182
|
+
if class_name:
|
|
183
|
+
tool_class = getattr(module, class_name)
|
|
184
|
+
else:
|
|
185
|
+
# Auto-discover: provider first, then single tool
|
|
186
|
+
tool_class = _find_dynamic_tool_provider_class(module)
|
|
187
|
+
if not tool_class:
|
|
188
|
+
tool_class = _find_dynamic_tool_class(module)
|
|
189
|
+
|
|
190
|
+
if not tool_class:
|
|
191
|
+
raise TypeError(
|
|
192
|
+
f"Module '{module_name}' does not contain a 'function_name' or 'class_name' to load, "
|
|
193
|
+
"and no DynamicTool or DynamicToolProvider subclass could be auto-discovered."
|
|
194
|
+
)
|
|
121
195
|
|
|
122
|
-
|
|
123
|
-
|
|
196
|
+
# Instantiate tools from the class
|
|
197
|
+
if issubclass(tool_class, DynamicToolProvider):
|
|
198
|
+
provider_instance = tool_class()
|
|
199
|
+
dynamic_tools = (
|
|
200
|
+
provider_instance.get_all_tools_for_framework(
|
|
201
|
+
tool_config=specific_tool_config
|
|
202
|
+
)
|
|
203
|
+
)
|
|
204
|
+
log.info(
|
|
205
|
+
"%s Loaded %d tools from DynamicToolProvider '%s' in %s",
|
|
206
|
+
component.log_identifier,
|
|
207
|
+
len(dynamic_tools),
|
|
208
|
+
tool_class.__name__,
|
|
209
|
+
module_name,
|
|
210
|
+
)
|
|
211
|
+
elif issubclass(tool_class, DynamicTool):
|
|
212
|
+
tool_instance = tool_class(tool_config=specific_tool_config)
|
|
213
|
+
dynamic_tools = [tool_instance]
|
|
214
|
+
else:
|
|
215
|
+
raise TypeError(
|
|
216
|
+
f"Class '{tool_class.__name__}' in module '{module_name}' is not a valid "
|
|
217
|
+
"DynamicTool or DynamicToolProvider subclass."
|
|
218
|
+
)
|
|
124
219
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
220
|
+
# Process all generated tools
|
|
221
|
+
for tool in dynamic_tools:
|
|
222
|
+
tool.origin = "dynamic"
|
|
223
|
+
declaration = tool._get_declaration()
|
|
224
|
+
if not declaration:
|
|
225
|
+
log.warning(
|
|
226
|
+
"Dynamic tool '%s' from module '%s' did not generate a valid declaration. Skipping.",
|
|
227
|
+
tool.__class__.__name__,
|
|
228
|
+
module_name,
|
|
229
|
+
)
|
|
230
|
+
continue
|
|
231
|
+
|
|
232
|
+
_check_and_register_tool_name(
|
|
233
|
+
declaration.name, f"dynamic:{module_name}"
|
|
234
|
+
)
|
|
235
|
+
loaded_tools.append(tool)
|
|
236
|
+
log.info(
|
|
237
|
+
"%s Loaded dynamic tool: %s from %s",
|
|
238
|
+
component.log_identifier,
|
|
239
|
+
declaration.name,
|
|
240
|
+
module_name,
|
|
241
|
+
)
|
|
135
242
|
|
|
136
243
|
elif tool_type == "builtin":
|
|
137
244
|
tool_name = tool_config.get("tool_name")
|
|
@@ -229,27 +229,6 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
229
229
|
component.log_identifier,
|
|
230
230
|
message.get_topic(),
|
|
231
231
|
)
|
|
232
|
-
a2a_context = {}
|
|
233
|
-
adk_session = None
|
|
234
|
-
jsonrpc_request_id = None
|
|
235
|
-
logical_task_id = None
|
|
236
|
-
client_id = message.get_user_properties().get("clientId", "default_client")
|
|
237
|
-
status_topic_from_peer = message.get_user_properties().get("a2aStatusTopic")
|
|
238
|
-
reply_topic_from_peer = message.get_user_properties().get("replyTo")
|
|
239
|
-
namespace = component.get_config("namespace")
|
|
240
|
-
a2a_user_config = message.get_user_properties().get("a2aUserConfig", {})
|
|
241
|
-
if not isinstance(a2a_user_config, dict):
|
|
242
|
-
log.warning(
|
|
243
|
-
"%s 'a2aUserConfig' user property is not a dictionary, received: %s. Defaulting to empty dict.",
|
|
244
|
-
component.log_identifier,
|
|
245
|
-
type(a2a_user_config),
|
|
246
|
-
)
|
|
247
|
-
a2a_user_config = {}
|
|
248
|
-
log.debug(
|
|
249
|
-
"%s Extracted 'a2aUserConfig': %s",
|
|
250
|
-
component.log_identifier,
|
|
251
|
-
a2a_user_config,
|
|
252
|
-
)
|
|
253
232
|
try:
|
|
254
233
|
payload_dict = message.get_payload()
|
|
255
234
|
if not isinstance(payload_dict, dict):
|
|
@@ -257,6 +236,16 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
257
236
|
a2a_request: A2ARequest = A2ARequest.model_validate(payload_dict)
|
|
258
237
|
jsonrpc_request_id = a2a.get_request_id(a2a_request)
|
|
259
238
|
|
|
239
|
+
# Extract properties from message user properties
|
|
240
|
+
client_id = message.get_user_properties().get("clientId", "default_client")
|
|
241
|
+
status_topic_from_peer = message.get_user_properties().get("a2aStatusTopic")
|
|
242
|
+
reply_topic_from_peer = message.get_user_properties().get("replyTo")
|
|
243
|
+
namespace = component.get_config("namespace")
|
|
244
|
+
a2a_user_config = message.get_user_properties().get("a2aUserConfig", {})
|
|
245
|
+
if not isinstance(a2a_user_config, dict):
|
|
246
|
+
log.warning("a2aUserConfig is not a dict, using empty dict instead")
|
|
247
|
+
a2a_user_config = {}
|
|
248
|
+
|
|
260
249
|
# The concept of logical_task_id changes. For Cancel, it's in params.id.
|
|
261
250
|
# For Send, we will generate it.
|
|
262
251
|
logical_task_id = None
|
|
@@ -411,6 +400,20 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
411
400
|
effective_session_id = original_session_id
|
|
412
401
|
is_run_based_session = False
|
|
413
402
|
temporary_run_session_id_for_cleanup = None
|
|
403
|
+
|
|
404
|
+
session_id_from_data = None
|
|
405
|
+
if a2a_message and a2a_message.parts:
|
|
406
|
+
for part in a2a_message.parts:
|
|
407
|
+
if isinstance(part, DataPart) and "session_id" in part.data:
|
|
408
|
+
session_id_from_data = part.data["session_id"]
|
|
409
|
+
log.info(
|
|
410
|
+
f"Extracted session_id '{session_id_from_data}' from DataPart."
|
|
411
|
+
)
|
|
412
|
+
break
|
|
413
|
+
|
|
414
|
+
if session_id_from_data:
|
|
415
|
+
original_session_id = session_id_from_data
|
|
416
|
+
|
|
414
417
|
if session_behavior == "RUN_BASED":
|
|
415
418
|
is_run_based_session = True
|
|
416
419
|
effective_session_id = f"{original_session_id}:{logical_task_id}:run"
|
|
@@ -432,6 +435,7 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
432
435
|
effective_session_id,
|
|
433
436
|
logical_task_id,
|
|
434
437
|
)
|
|
438
|
+
|
|
435
439
|
adk_session_for_run = await component.session_service.get_session(
|
|
436
440
|
app_name=agent_name, user_id=user_id, session_id=effective_session_id
|
|
437
441
|
)
|
|
@@ -447,6 +451,7 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
447
451
|
effective_session_id,
|
|
448
452
|
logical_task_id,
|
|
449
453
|
)
|
|
454
|
+
|
|
450
455
|
else:
|
|
451
456
|
log.info(
|
|
452
457
|
"%s Reusing existing ADK session '%s' for task '%s'.",
|
|
@@ -454,6 +459,7 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
454
459
|
effective_session_id,
|
|
455
460
|
logical_task_id,
|
|
456
461
|
)
|
|
462
|
+
|
|
457
463
|
if is_run_based_session:
|
|
458
464
|
try:
|
|
459
465
|
original_adk_session_data = (
|