solace-agent-mesh 1.3.0__py3-none-any.whl → 1.3.2__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/setup.py +141 -34
- solace_agent_mesh/agent/protocol/event_handlers.py +91 -0
- solace_agent_mesh/agent/sac/app.py +3 -2
- 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.03d5dceb.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.4adc477a.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.cf0229ea.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-1757704179464.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1757704179464.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/client/webui/frontend/static/assets/{authCallback-vY5eu2lI.js → authCallback-CAX9u8a7.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-BeBkzgWW.js → client-DXU9SPI5.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{main-Bjys1KQs.js → main-DjoMeldu.js} +26 -26
- solace_agent_mesh/client/webui/frontend/static/assets/{vendor-CE0AeXyK.js → vendor-B0BEKoAR.js} +69 -74
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
- solace_agent_mesh/client/webui/frontend/static/index.html +3 -3
- solace_agent_mesh/common/a2a/__init__.py +4 -0
- solace_agent_mesh/common/a2a/protocol.py +20 -0
- solace_agent_mesh/common/sac/sam_component_base.py +29 -9
- solace_agent_mesh/common/sam_events/__init__.py +9 -0
- solace_agent_mesh/common/sam_events/event_service.py +207 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +1 -1
- solace_agent_mesh/gateway/http_sse/component.py +45 -35
- solace_agent_mesh/gateway/http_sse/dependencies.py +129 -66
- solace_agent_mesh/gateway/http_sse/main.py +22 -35
- solace_agent_mesh/gateway/http_sse/repository/__init__.py +37 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/message.py +41 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session.py +45 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session_history.py +16 -0
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +64 -0
- solace_agent_mesh/gateway/http_sse/repository/message_repository.py +78 -0
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/repository/models/base.py +7 -0
- solace_agent_mesh/gateway/http_sse/repository/models/message_model.py +27 -0
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +27 -0
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +139 -0
- solace_agent_mesh/gateway/http_sse/routers/{agents.py → agent_cards.py} +7 -7
- solace_agent_mesh/gateway/http_sse/routers/config.py +1 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +20 -0
- solace_agent_mesh/gateway/http_sse/{api → routers}/dto/requests/session_requests.py +1 -8
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/__init__.py +16 -0
- solace_agent_mesh/gateway/http_sse/{api → routers}/dto/responses/session_responses.py +3 -30
- solace_agent_mesh/gateway/http_sse/{api/controllers/session_controller.py → routers/sessions.py} +20 -77
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +42 -49
- solace_agent_mesh/gateway/http_sse/{api/controllers/user_controller.py → routers/users.py} +1 -1
- solace_agent_mesh/gateway/http_sse/services/{agent_service.py → agent_card_service.py} +19 -19
- solace_agent_mesh/gateway/http_sse/services/session_service.py +245 -0
- solace_agent_mesh/gateway/http_sse/session_manager.py +0 -3
- solace_agent_mesh/gateway/http_sse/shared/enums.py +0 -5
- {solace_agent_mesh-1.3.0.dist-info → solace_agent_mesh-1.3.2.dist-info}/METADATA +1 -1
- {solace_agent_mesh-1.3.0.dist-info → solace_agent_mesh-1.3.2.dist-info}/RECORD +109 -110
- 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.08d30374.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1757433031159.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1757433031159.json +0 -1
- solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +0 -676
- solace_agent_mesh/gateway/http_sse/api/__init__.py +0 -11
- solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +0 -9
- solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +0 -279
- solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +0 -37
- solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +0 -66
- solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +0 -43
- solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +0 -74
- solace_agent_mesh/gateway/http_sse/application/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/application/services/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/application/services/session_service.py +0 -135
- solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/domain/entities/session.py +0 -90
- solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +0 -54
- solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +0 -4
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +0 -123
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +0 -4
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +0 -16
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +0 -119
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +0 -31
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +0 -12
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +0 -174
- /solace_agent_mesh/assets/docs/assets/js/{main.08d30374.js.LICENSE.txt → main.4adc477a.js.LICENSE.txt} +0 -0
- /solace_agent_mesh/gateway/http_sse/{api → routers}/dto/__init__.py +0 -0
- {solace_agent_mesh-1.3.0.dist-info → solace_agent_mesh-1.3.2.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.3.0.dist-info → solace_agent_mesh-1.3.2.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.3.0.dist-info → solace_agent_mesh-1.3.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -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")
|
|
@@ -32,7 +32,9 @@ from ...common.a2a import (
|
|
|
32
32
|
get_client_response_topic,
|
|
33
33
|
get_agent_response_subscription_topic,
|
|
34
34
|
get_agent_status_subscription_topic,
|
|
35
|
+
get_sam_events_subscription_topic,
|
|
35
36
|
get_text_from_message,
|
|
37
|
+
topic_matches_subscription,
|
|
36
38
|
)
|
|
37
39
|
from ...agent.utils.artifact_helpers import (
|
|
38
40
|
generate_artifact_metadata_summary,
|
|
@@ -118,6 +120,7 @@ async def process_event(component, event: Event):
|
|
|
118
120
|
agent_status_sub_prefix = (
|
|
119
121
|
get_agent_status_subscription_topic(namespace, agent_name)[:-2] + "/"
|
|
120
122
|
)
|
|
123
|
+
sam_events_topic = get_sam_events_subscription_topic(namespace, "session")
|
|
121
124
|
if topic == agent_request_topic:
|
|
122
125
|
await handle_a2a_request(component, message)
|
|
123
126
|
elif topic == discovery_topic:
|
|
@@ -126,6 +129,8 @@ async def process_event(component, event: Event):
|
|
|
126
129
|
handle_agent_card_message(component, message)
|
|
127
130
|
else:
|
|
128
131
|
message.call_acknowledgements()
|
|
132
|
+
elif topic_matches_subscription(topic, sam_events_topic):
|
|
133
|
+
handle_sam_event(component, message, topic)
|
|
129
134
|
elif topic.startswith(agent_response_sub_prefix) or topic.startswith(
|
|
130
135
|
agent_status_sub_prefix
|
|
131
136
|
):
|
|
@@ -233,6 +238,8 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
233
238
|
payload_dict = message.get_payload()
|
|
234
239
|
if not isinstance(payload_dict, dict):
|
|
235
240
|
raise ValueError("Payload is not a dictionary.")
|
|
241
|
+
|
|
242
|
+
|
|
236
243
|
a2a_request: A2ARequest = A2ARequest.model_validate(payload_dict)
|
|
237
244
|
jsonrpc_request_id = a2a.get_request_id(a2a_request)
|
|
238
245
|
|
|
@@ -1539,3 +1546,87 @@ def publish_agent_card(component):
|
|
|
1539
1546
|
"%s Failed to publish Agent Card: %s", component.log_identifier, e
|
|
1540
1547
|
)
|
|
1541
1548
|
component.handle_error(e, None)
|
|
1549
|
+
|
|
1550
|
+
|
|
1551
|
+
def handle_sam_event(component, message, topic):
|
|
1552
|
+
"""Handle incoming SAM system events."""
|
|
1553
|
+
try:
|
|
1554
|
+
payload = message.get_payload()
|
|
1555
|
+
|
|
1556
|
+
if not isinstance(payload, dict):
|
|
1557
|
+
log.warning("Invalid SAM event payload - not a dict")
|
|
1558
|
+
message.call_acknowledgements()
|
|
1559
|
+
return
|
|
1560
|
+
|
|
1561
|
+
event_type = payload.get("event_type")
|
|
1562
|
+
if not event_type:
|
|
1563
|
+
log.warning("SAM event missing event_type field")
|
|
1564
|
+
message.call_acknowledgements()
|
|
1565
|
+
return
|
|
1566
|
+
|
|
1567
|
+
log.info("%s Received SAM event: %s", component.log_identifier, event_type)
|
|
1568
|
+
|
|
1569
|
+
if event_type == "session.deleted":
|
|
1570
|
+
data = payload.get("data", {})
|
|
1571
|
+
session_id = data.get("session_id")
|
|
1572
|
+
user_id = data.get("user_id")
|
|
1573
|
+
agent_id = data.get("agent_id")
|
|
1574
|
+
|
|
1575
|
+
if not all([session_id, user_id, agent_id]):
|
|
1576
|
+
log.warning("Missing required fields in session.deleted event")
|
|
1577
|
+
message.call_acknowledgements()
|
|
1578
|
+
return
|
|
1579
|
+
|
|
1580
|
+
current_agent = component.get_config("agent_name")
|
|
1581
|
+
|
|
1582
|
+
if agent_id == current_agent:
|
|
1583
|
+
log.info("%s Processing session.deleted event for session %s",
|
|
1584
|
+
component.log_identifier, session_id)
|
|
1585
|
+
asyncio.create_task(cleanup_agent_session(component, session_id, user_id))
|
|
1586
|
+
else:
|
|
1587
|
+
log.debug("Session deletion event for different agent: %s != %s", agent_id, current_agent)
|
|
1588
|
+
else:
|
|
1589
|
+
log.debug("Unhandled SAM event type: %s", event_type)
|
|
1590
|
+
|
|
1591
|
+
message.call_acknowledgements()
|
|
1592
|
+
|
|
1593
|
+
except Exception as e:
|
|
1594
|
+
log.error("Error handling SAM event %s: %s", topic, e)
|
|
1595
|
+
message.call_acknowledgements()
|
|
1596
|
+
|
|
1597
|
+
|
|
1598
|
+
|
|
1599
|
+
async def cleanup_agent_session(component, session_id: str, user_id: str):
|
|
1600
|
+
"""Clean up agent-side session data."""
|
|
1601
|
+
try:
|
|
1602
|
+
log.info("Starting cleanup for session %s, user %s", session_id, user_id)
|
|
1603
|
+
|
|
1604
|
+
if hasattr(component, 'session_service') and component.session_service:
|
|
1605
|
+
agent_name = component.get_config("agent_name")
|
|
1606
|
+
log.info("Deleting session %s from agent %s session service", session_id, agent_name)
|
|
1607
|
+
await component.session_service.delete_session(
|
|
1608
|
+
app_name=agent_name,
|
|
1609
|
+
user_id=user_id,
|
|
1610
|
+
session_id=session_id
|
|
1611
|
+
)
|
|
1612
|
+
log.info("Successfully deleted session %s from session service", session_id)
|
|
1613
|
+
else:
|
|
1614
|
+
log.info("No session service available for cleanup")
|
|
1615
|
+
|
|
1616
|
+
with component.active_tasks_lock:
|
|
1617
|
+
tasks_to_cancel = []
|
|
1618
|
+
for task_id, context in component.active_tasks.items():
|
|
1619
|
+
if (hasattr(context, 'a2a_context') and
|
|
1620
|
+
context.a2a_context.get('session_id') == session_id):
|
|
1621
|
+
tasks_to_cancel.append(task_id)
|
|
1622
|
+
|
|
1623
|
+
for task_id in tasks_to_cancel:
|
|
1624
|
+
context = component.active_tasks.get(task_id)
|
|
1625
|
+
if context:
|
|
1626
|
+
context.cancel()
|
|
1627
|
+
log.info("Cancelled task %s for deleted session %s", task_id, session_id)
|
|
1628
|
+
|
|
1629
|
+
log.info("Session cleanup completed for session %s", session_id)
|
|
1630
|
+
|
|
1631
|
+
except Exception as e:
|
|
1632
|
+
log.error("Error cleaning up session %s: %s", session_id, e)
|
|
@@ -14,13 +14,13 @@ patch_adk()
|
|
|
14
14
|
|
|
15
15
|
from typing import Any, Dict
|
|
16
16
|
from solace_ai_connector.flow.app import App
|
|
17
|
-
from solace_ai_connector.common.log import log
|
|
18
17
|
|
|
19
18
|
from ...common.a2a import (
|
|
20
19
|
get_agent_request_topic,
|
|
21
20
|
get_discovery_topic,
|
|
22
21
|
get_agent_response_subscription_topic,
|
|
23
22
|
get_agent_status_subscription_topic,
|
|
23
|
+
get_sam_events_subscription_topic,
|
|
24
24
|
)
|
|
25
25
|
from ...common.constants import DEFAULT_COMMUNICATION_TIMEOUT
|
|
26
26
|
from ...agent.sac.component import SamAgentComponent
|
|
@@ -680,6 +680,7 @@ class SamAgentApp(App):
|
|
|
680
680
|
get_discovery_topic(namespace),
|
|
681
681
|
get_agent_response_subscription_topic(namespace, agent_name),
|
|
682
682
|
get_agent_status_subscription_topic(namespace, agent_name),
|
|
683
|
+
get_sam_events_subscription_topic(namespace, "session"),
|
|
683
684
|
]
|
|
684
685
|
generated_subs = [{"topic": topic} for topic in required_topics]
|
|
685
686
|
log.info(
|
|
@@ -714,4 +715,4 @@ class SamAgentApp(App):
|
|
|
714
715
|
log.debug("Set broker_config.temporary_queue = True")
|
|
715
716
|
|
|
716
717
|
super().__init__(app_info, **kwargs)
|
|
717
|
-
log.debug("A2A_ADK_App initialization complete.")
|
|
718
|
+
log.debug("A2A_ADK_App initialization complete.")
|