solace-agent-mesh 1.0.7__py3-none-any.whl → 1.1.0__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/adk_llm.txt +182 -42
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +171 -0
- solace_agent_mesh/agent/adk/callbacks.py +165 -104
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +0 -18
- solace_agent_mesh/agent/adk/models/models_llm.txt +104 -55
- solace_agent_mesh/agent/adk/runner.py +7 -5
- solace_agent_mesh/agent/adk/services.py +9 -1
- solace_agent_mesh/agent/adk/setup.py +11 -0
- solace_agent_mesh/agent/adk/stream_parser.py +8 -1
- solace_agent_mesh/agent/adk/tool_wrapper.py +10 -3
- solace_agent_mesh/agent/agent_llm.txt +355 -18
- solace_agent_mesh/agent/protocol/event_handlers.py +433 -296
- solace_agent_mesh/agent/protocol/protocol_llm.txt +54 -7
- solace_agent_mesh/agent/sac/app.py +1 -1
- solace_agent_mesh/agent/sac/component.py +212 -517
- solace_agent_mesh/agent/sac/sac_llm.txt +133 -63
- solace_agent_mesh/agent/testing/testing_llm.txt +25 -58
- solace_agent_mesh/agent/tools/peer_agent_tool.py +15 -11
- solace_agent_mesh/agent/tools/tools_llm.txt +234 -69
- solace_agent_mesh/agent/utils/artifact_helpers.py +35 -1
- solace_agent_mesh/agent/utils/utils_llm.txt +90 -105
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/{3d406171.7d02a73b.js → 3d406171.0b9eeed1.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/6e0db977.39a79ca9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{75384d09.ccd480c4.js → 75384d09.bf78fbdb.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.a75ecc0d.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +4 -4
- 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/migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +105 -0
- solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html +53 -0
- 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 +8 -8
- 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 +4 -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-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-1756992446316.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1756992446316.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/web_add_agent_step.py +12 -3
- solace_agent_mesh/cli/commands/add_cmd/web_add_gateway_step.py +10 -14
- solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +2 -15
- solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +6 -2
- solace_agent_mesh/cli/utils.py +15 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-DvlO62me.js → authCallback-BmF2l6vg.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-bp6u3qVZ.js → client-D881Dttc.js} +4 -4
- solace_agent_mesh/client/webui/frontend/static/assets/main-C0jZjYa8.js +699 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-CCeG324-.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +2 -2
- solace_agent_mesh/client/webui/frontend/static/index.html +3 -3
- solace_agent_mesh/common/a2a/__init__.py +213 -0
- solace_agent_mesh/common/a2a/a2a_llm.txt +182 -0
- solace_agent_mesh/common/a2a/artifact.py +328 -0
- solace_agent_mesh/common/a2a/events.py +183 -0
- solace_agent_mesh/common/a2a/message.py +307 -0
- solace_agent_mesh/common/a2a/protocol.py +513 -0
- solace_agent_mesh/common/a2a/task.py +127 -0
- solace_agent_mesh/common/a2a/translation.py +653 -0
- solace_agent_mesh/common/a2a/types.py +54 -0
- solace_agent_mesh/common/a2a_spec/a2a.json +2576 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +407 -0
- solace_agent_mesh/common/a2a_spec/schemas/agent_progress_update.json +18 -0
- solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +31 -0
- solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +18 -0
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +235 -0
- solace_agent_mesh/common/a2a_spec/schemas/tool_invocation_start.json +26 -0
- solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +25 -0
- solace_agent_mesh/common/agent_registry.py +1 -1
- solace_agent_mesh/common/common_llm.txt +192 -70
- solace_agent_mesh/common/data_parts.py +99 -0
- solace_agent_mesh/common/middleware/middleware_llm.txt +17 -17
- solace_agent_mesh/common/sac/__init__.py +0 -0
- solace_agent_mesh/common/sac/sac_llm.txt +71 -0
- solace_agent_mesh/common/sac/sam_component_base.py +252 -0
- solace_agent_mesh/common/services/providers/providers_llm.txt +51 -84
- solace_agent_mesh/common/services/services_llm.txt +206 -26
- solace_agent_mesh/common/utils/artifact_utils.py +29 -0
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +176 -80
- solace_agent_mesh/common/utils/utils_llm.txt +323 -42
- solace_agent_mesh/config_portal/backend/common.py +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/{_index-MqsrTd6g.js → _index-Bym6YkMd.js} +74 -24
- solace_agent_mesh/config_portal/frontend/static/client/assets/{components-B7lKcHVY.js → components-Rk0n-9cK.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-CEumGClk.js → entry.client-mvZjNKiz.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/{index-DSo1AH_7.js → index-DzNKzXrc.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-d845808d.js +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{root-C4XmHinv.js → root-BWvk5-gF.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
- solace_agent_mesh/core_a2a/core_a2a_llm.txt +10 -8
- solace_agent_mesh/core_a2a/service.py +20 -44
- solace_agent_mesh/gateway/base/app.py +27 -1
- solace_agent_mesh/gateway/base/base_llm.txt +177 -72
- solace_agent_mesh/gateway/base/component.py +294 -523
- solace_agent_mesh/gateway/gateway_llm.txt +299 -58
- solace_agent_mesh/gateway/http_sse/component.py +156 -183
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +29 -29
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +272 -36
- solace_agent_mesh/gateway/http_sse/main.py +8 -10
- solace_agent_mesh/gateway/http_sse/routers/agents.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +18 -4
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +231 -5
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +12 -7
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +116 -169
- solace_agent_mesh/gateway/http_sse/services/agent_service.py +1 -1
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +89 -135
- solace_agent_mesh/gateway/http_sse/services/task_service.py +2 -5
- solace_agent_mesh/solace_agent_mesh_llm.txt +362 -0
- solace_agent_mesh/templates/gateway_component_template.py +149 -98
- {solace_agent_mesh-1.0.7.dist-info → solace_agent_mesh-1.1.0.dist-info}/METADATA +5 -4
- {solace_agent_mesh-1.0.7.dist-info → solace_agent_mesh-1.1.0.dist-info}/RECORD +144 -127
- solace_agent_mesh/assets/docs/assets/js/f284c35a.731836ad.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.d79f063b.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.6415ad00.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1756146501924.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1756146501924.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-BCpII1-0.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-BucUdn9m.js +0 -673
- solace_agent_mesh/common/a2a_protocol.py +0 -564
- solace_agent_mesh/common/client/__init__.py +0 -4
- solace_agent_mesh/common/client/card_resolver.py +0 -21
- solace_agent_mesh/common/client/client.py +0 -85
- solace_agent_mesh/common/client/client_llm.txt +0 -133
- solace_agent_mesh/common/server/__init__.py +0 -4
- solace_agent_mesh/common/server/server.py +0 -122
- solace_agent_mesh/common/server/server_llm.txt +0 -169
- solace_agent_mesh/common/server/task_manager.py +0 -291
- solace_agent_mesh/common/server/utils.py +0 -28
- solace_agent_mesh/common/types.py +0 -411
- solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-28271392.js +0 -1
- /solace_agent_mesh/assets/docs/assets/js/{main.d79f063b.js.LICENSE.txt → main.a75ecc0d.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.0.7.dist-info → solace_agent_mesh-1.1.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.0.7.dist-info → solace_agent_mesh-1.1.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.0.7.dist-info → solace_agent_mesh-1.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -16,9 +16,6 @@ from google.adk.artifacts import BaseArtifactService
|
|
|
16
16
|
from google.adk.agents.callback_context import CallbackContext
|
|
17
17
|
from google.adk.models.llm_request import LlmRequest
|
|
18
18
|
from google.adk.models.llm_response import LlmResponse
|
|
19
|
-
from ...common.a2a_protocol import (
|
|
20
|
-
A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY,
|
|
21
|
-
)
|
|
22
19
|
from google.genai import types as adk_types
|
|
23
20
|
from google.adk.tools.mcp_tool import MCPTool
|
|
24
21
|
from solace_ai_connector.common.log import log
|
|
@@ -48,14 +45,14 @@ from ...common.utils.embeds import (
|
|
|
48
45
|
|
|
49
46
|
from ...common.utils.embeds.modifiers import MODIFIER_IMPLEMENTATIONS
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
from ...common import a2a
|
|
49
|
+
from ...common.a2a.types import ContentPart
|
|
50
|
+
from ...common.data_parts import (
|
|
51
|
+
AgentProgressUpdateData,
|
|
52
|
+
ArtifactCreationProgressData,
|
|
53
|
+
LlmInvocationData,
|
|
54
|
+
ToolInvocationStartData,
|
|
55
|
+
ToolResultData,
|
|
59
56
|
)
|
|
60
57
|
|
|
61
58
|
from ...agent.utils.artifact_helpers import (
|
|
@@ -68,6 +65,7 @@ from ..tools.builtin_artifact_tools import _internal_create_artifact
|
|
|
68
65
|
from ...agent.adk.tool_wrapper import ADKToolWrapper
|
|
69
66
|
|
|
70
67
|
# Import the new parser and its events
|
|
68
|
+
from pydantic import BaseModel
|
|
71
69
|
from ...agent.adk.stream_parser import (
|
|
72
70
|
FencedBlockStreamParser,
|
|
73
71
|
BlockStartedEvent,
|
|
@@ -78,6 +76,44 @@ from ...agent.adk.stream_parser import (
|
|
|
78
76
|
ARTIFACT_BLOCK_DELIMITER_CLOSE,
|
|
79
77
|
)
|
|
80
78
|
|
|
79
|
+
A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY = "temp:llm_stream_chunks_processed"
|
|
80
|
+
|
|
81
|
+
if TYPE_CHECKING:
|
|
82
|
+
from ..sac.component import SamAgentComponent
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
async def _publish_data_part_status_update(
|
|
86
|
+
host_component: "SamAgentComponent",
|
|
87
|
+
a2a_context: Dict[str, Any],
|
|
88
|
+
data_part_model: BaseModel,
|
|
89
|
+
):
|
|
90
|
+
"""Helper to construct and publish a TaskStatusUpdateEvent with a DataPart."""
|
|
91
|
+
logical_task_id = a2a_context.get("logical_task_id")
|
|
92
|
+
context_id = a2a_context.get("contextId")
|
|
93
|
+
|
|
94
|
+
status_update_event = a2a.create_data_signal_event(
|
|
95
|
+
task_id=logical_task_id,
|
|
96
|
+
context_id=context_id,
|
|
97
|
+
signal_data=data_part_model,
|
|
98
|
+
agent_name=host_component.agent_name,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
loop = host_component.get_async_loop()
|
|
102
|
+
if loop and loop.is_running():
|
|
103
|
+
asyncio.run_coroutine_threadsafe(
|
|
104
|
+
host_component._publish_status_update_with_buffer_flush(
|
|
105
|
+
status_update_event,
|
|
106
|
+
a2a_context,
|
|
107
|
+
skip_buffer_flush=False,
|
|
108
|
+
),
|
|
109
|
+
loop,
|
|
110
|
+
)
|
|
111
|
+
else:
|
|
112
|
+
log.error(
|
|
113
|
+
"%s Async loop not available. Cannot publish status update.",
|
|
114
|
+
host_component.log_identifier,
|
|
115
|
+
)
|
|
116
|
+
|
|
81
117
|
|
|
82
118
|
async def process_artifact_blocks_callback(
|
|
83
119
|
callback_context: CallbackContext,
|
|
@@ -132,8 +168,11 @@ async def process_artifact_blocks_callback(
|
|
|
132
168
|
)
|
|
133
169
|
filename = event.params.get("filename", "unknown_artifact")
|
|
134
170
|
if a2a_context:
|
|
135
|
-
|
|
136
|
-
f"Receiving artifact `{filename}`..."
|
|
171
|
+
progress_data = AgentProgressUpdateData(
|
|
172
|
+
status_text=f"Receiving artifact `{filename}`..."
|
|
173
|
+
)
|
|
174
|
+
await _publish_data_part_status_update(
|
|
175
|
+
host_component, a2a_context, progress_data
|
|
137
176
|
)
|
|
138
177
|
params_str = " ".join(
|
|
139
178
|
[f'{k}="{v}"' for k, v in event.params.items()]
|
|
@@ -149,10 +188,14 @@ async def process_artifact_blocks_callback(
|
|
|
149
188
|
)
|
|
150
189
|
params = parser._block_params
|
|
151
190
|
filename = params.get("filename", "unknown_artifact")
|
|
152
|
-
status_message = f"Creating artifact `{filename}` ({event.buffered_size}B saved)..."
|
|
153
191
|
if a2a_context:
|
|
154
|
-
|
|
155
|
-
|
|
192
|
+
progress_data = ArtifactCreationProgressData(
|
|
193
|
+
filename=filename,
|
|
194
|
+
bytes_saved=event.buffered_size,
|
|
195
|
+
artifact_chunk=event.chunk,
|
|
196
|
+
)
|
|
197
|
+
await _publish_data_part_status_update(
|
|
198
|
+
host_component, a2a_context, progress_data
|
|
156
199
|
)
|
|
157
200
|
|
|
158
201
|
elif isinstance(event, BlockCompletedEvent):
|
|
@@ -217,6 +260,7 @@ async def process_artifact_blocks_callback(
|
|
|
217
260
|
tool_config=None, # No specific config for this internal tool
|
|
218
261
|
tool_name="_internal_create_artifact",
|
|
219
262
|
origin="internal",
|
|
263
|
+
resolution_type="early",
|
|
220
264
|
)
|
|
221
265
|
save_result = await wrapped_creator(**kwargs_for_call)
|
|
222
266
|
|
|
@@ -694,8 +738,7 @@ async def manage_large_mcp_tool_responses_callback(
|
|
|
694
738
|
|
|
695
739
|
if needs_saving_as_artifact and (
|
|
696
740
|
save_result
|
|
697
|
-
and save_result.status
|
|
698
|
-
in [McpSaveStatus.SUCCESS, McpSaveStatus.PARTIAL_SUCCESS]
|
|
741
|
+
and save_result.status in [McpSaveStatus.SUCCESS, McpSaveStatus.PARTIAL_SUCCESS]
|
|
699
742
|
):
|
|
700
743
|
if needs_truncation_for_llm:
|
|
701
744
|
final_llm_response_dict["status"] = "processed_saved_and_truncated"
|
|
@@ -1345,20 +1388,10 @@ def solace_llm_invocation_callback(
|
|
|
1345
1388
|
)
|
|
1346
1389
|
return None
|
|
1347
1390
|
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
log.debug(
|
|
1353
|
-
"%s Reset %s to False.", log_identifier, A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY
|
|
1354
|
-
)
|
|
1355
|
-
except Exception as e_flag_reset:
|
|
1356
|
-
log.error(
|
|
1357
|
-
"%s Error resetting %s: %s",
|
|
1358
|
-
log_identifier,
|
|
1359
|
-
A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY,
|
|
1360
|
-
e_flag_reset,
|
|
1361
|
-
)
|
|
1391
|
+
callback_context.state[A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY] = False
|
|
1392
|
+
log.debug(
|
|
1393
|
+
"%s Reset %s to False.", log_identifier, A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY
|
|
1394
|
+
)
|
|
1362
1395
|
|
|
1363
1396
|
try:
|
|
1364
1397
|
a2a_context = callback_context.state.get("a2a_context")
|
|
@@ -1369,28 +1402,15 @@ def solace_llm_invocation_callback(
|
|
|
1369
1402
|
)
|
|
1370
1403
|
return None
|
|
1371
1404
|
|
|
1372
|
-
agent_name = host_component.get_config("agent_name", "unknown_agent")
|
|
1373
1405
|
logical_task_id = a2a_context.get("logical_task_id")
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
metadata=llm_invocation_metadata,
|
|
1383
|
-
)
|
|
1384
|
-
task_status = TaskStatus(
|
|
1385
|
-
state=TaskState.WORKING,
|
|
1386
|
-
message=a2a_message,
|
|
1387
|
-
timestamp=datetime.now(timezone.utc),
|
|
1388
|
-
)
|
|
1389
|
-
status_update_event = TaskStatusUpdateEvent(
|
|
1390
|
-
id=logical_task_id,
|
|
1391
|
-
status=task_status,
|
|
1392
|
-
final=False,
|
|
1393
|
-
metadata={"agent_name": agent_name},
|
|
1406
|
+
context_id = a2a_context.get("contextId")
|
|
1407
|
+
|
|
1408
|
+
llm_data = LlmInvocationData(request=llm_request.model_dump(exclude_none=True))
|
|
1409
|
+
status_update_event = a2a.create_data_signal_event(
|
|
1410
|
+
task_id=logical_task_id,
|
|
1411
|
+
context_id=context_id,
|
|
1412
|
+
signal_data=llm_data,
|
|
1413
|
+
agent_name=host_component.agent_name,
|
|
1394
1414
|
)
|
|
1395
1415
|
|
|
1396
1416
|
loop = host_component.get_async_loop()
|
|
@@ -1454,20 +1474,23 @@ def solace_llm_response_callback(
|
|
|
1454
1474
|
agent_name = host_component.get_config("agent_name", "unknown_agent")
|
|
1455
1475
|
logical_task_id = a2a_context.get("logical_task_id")
|
|
1456
1476
|
|
|
1457
|
-
|
|
1477
|
+
llm_response_data = {
|
|
1458
1478
|
"type": "llm_response",
|
|
1459
1479
|
"data": llm_response.model_dump(exclude_none=True),
|
|
1460
1480
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1481
|
+
# This signal doesn't have a dedicated Pydantic model, so we create the
|
|
1482
|
+
# DataPart directly and use the lower-level helpers.
|
|
1483
|
+
data_part = a2a.create_data_part(data=llm_response_data)
|
|
1484
|
+
a2a_message = a2a.create_agent_parts_message(
|
|
1485
|
+
parts=[data_part],
|
|
1486
|
+
task_id=logical_task_id,
|
|
1487
|
+
context_id=a2a_context.get("contextId"),
|
|
1466
1488
|
)
|
|
1467
|
-
status_update_event =
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1489
|
+
status_update_event = a2a.create_status_update(
|
|
1490
|
+
task_id=logical_task_id,
|
|
1491
|
+
context_id=a2a_context.get("contextId"),
|
|
1492
|
+
message=a2a_message,
|
|
1493
|
+
is_final=False,
|
|
1471
1494
|
metadata={"agent_name": agent_name},
|
|
1472
1495
|
)
|
|
1473
1496
|
loop = host_component.get_async_loop()
|
|
@@ -1529,8 +1552,6 @@ def notify_tool_invocation_start_callback(
|
|
|
1529
1552
|
)
|
|
1530
1553
|
return
|
|
1531
1554
|
|
|
1532
|
-
logical_task_id = a2a_context.get("logical_task_id")
|
|
1533
|
-
|
|
1534
1555
|
try:
|
|
1535
1556
|
serializable_args = {}
|
|
1536
1557
|
for k, v in args.items():
|
|
@@ -1540,57 +1561,97 @@ def notify_tool_invocation_start_callback(
|
|
|
1540
1561
|
except TypeError:
|
|
1541
1562
|
serializable_args[k] = str(v)
|
|
1542
1563
|
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1564
|
+
tool_data = ToolInvocationStartData(
|
|
1565
|
+
tool_name=tool.name,
|
|
1566
|
+
tool_args=serializable_args,
|
|
1567
|
+
function_call_id=tool_context.function_call_id,
|
|
1568
|
+
)
|
|
1569
|
+
asyncio.run_coroutine_threadsafe(
|
|
1570
|
+
_publish_data_part_status_update(host_component, a2a_context, tool_data),
|
|
1571
|
+
host_component.get_async_loop(),
|
|
1572
|
+
)
|
|
1573
|
+
log.debug(
|
|
1574
|
+
"%s Scheduled tool_invocation_start notification.",
|
|
1575
|
+
log_identifier,
|
|
1576
|
+
)
|
|
1552
1577
|
|
|
1553
|
-
|
|
1554
|
-
|
|
1578
|
+
except Exception as e:
|
|
1579
|
+
log.exception(
|
|
1580
|
+
"%s Error publishing tool_invocation_start status update: %s",
|
|
1581
|
+
log_identifier,
|
|
1582
|
+
e,
|
|
1555
1583
|
)
|
|
1556
1584
|
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1585
|
+
return None
|
|
1586
|
+
|
|
1587
|
+
|
|
1588
|
+
def notify_tool_execution_result_callback(
|
|
1589
|
+
tool: BaseTool,
|
|
1590
|
+
args: Dict[str, Any],
|
|
1591
|
+
tool_context: ToolContext,
|
|
1592
|
+
tool_response: Any,
|
|
1593
|
+
host_component: "SamAgentComponent",
|
|
1594
|
+
) -> None:
|
|
1595
|
+
"""
|
|
1596
|
+
ADK after_tool_callback to send an A2A status message with the result
|
|
1597
|
+
of a tool's execution.
|
|
1598
|
+
"""
|
|
1599
|
+
log_identifier = f"[Callback:NotifyToolResult:{tool.name}]"
|
|
1600
|
+
log.debug("%s Triggered for tool '%s'", log_identifier, tool.name)
|
|
1601
|
+
|
|
1602
|
+
if not host_component:
|
|
1603
|
+
log.error(
|
|
1604
|
+
"%s Host component instance not provided. Cannot send notification.",
|
|
1605
|
+
log_identifier,
|
|
1561
1606
|
)
|
|
1607
|
+
return
|
|
1562
1608
|
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1609
|
+
a2a_context = tool_context.state.get("a2a_context")
|
|
1610
|
+
if not a2a_context:
|
|
1611
|
+
log.error(
|
|
1612
|
+
"%s a2a_context not found in tool_context.state. Cannot send notification.",
|
|
1613
|
+
log_identifier,
|
|
1568
1614
|
)
|
|
1615
|
+
return
|
|
1569
1616
|
|
|
1570
|
-
|
|
1571
|
-
|
|
1617
|
+
if tool.is_long_running and not tool_response:
|
|
1618
|
+
log.debug(
|
|
1619
|
+
"%s Tool is long-running and is not yet complete. Don't notify its completion",
|
|
1620
|
+
log_identifier,
|
|
1621
|
+
)
|
|
1622
|
+
return
|
|
1572
1623
|
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
),
|
|
1579
|
-
loop,
|
|
1580
|
-
)
|
|
1581
|
-
log.debug(
|
|
1582
|
-
"%s Scheduled tool_invocation_start notification with buffer flush.",
|
|
1583
|
-
log_identifier,
|
|
1584
|
-
)
|
|
1624
|
+
try:
|
|
1625
|
+
# Attempt to make the response JSON serializable
|
|
1626
|
+
serializable_response = tool_response
|
|
1627
|
+
if hasattr(tool_response, "model_dump"):
|
|
1628
|
+
serializable_response = tool_response.model_dump(exclude_none=True)
|
|
1585
1629
|
else:
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1630
|
+
try:
|
|
1631
|
+
# A simple check to see if it can be dumped.
|
|
1632
|
+
# This isn't perfect but catches many non-serializable types.
|
|
1633
|
+
json.dumps(tool_response)
|
|
1634
|
+
except (TypeError, OverflowError):
|
|
1635
|
+
serializable_response = str(tool_response)
|
|
1636
|
+
|
|
1637
|
+
tool_data = ToolResultData(
|
|
1638
|
+
tool_name=tool.name,
|
|
1639
|
+
result_data=serializable_response,
|
|
1640
|
+
function_call_id=tool_context.function_call_id,
|
|
1641
|
+
)
|
|
1642
|
+
asyncio.run_coroutine_threadsafe(
|
|
1643
|
+
_publish_data_part_status_update(host_component, a2a_context, tool_data),
|
|
1644
|
+
host_component.get_async_loop(),
|
|
1645
|
+
)
|
|
1646
|
+
log.debug(
|
|
1647
|
+
"%s Scheduled tool_result notification for function call ID %s.",
|
|
1648
|
+
log_identifier,
|
|
1649
|
+
tool_context.function_call_id,
|
|
1650
|
+
)
|
|
1590
1651
|
|
|
1591
1652
|
except Exception as e:
|
|
1592
1653
|
log.exception(
|
|
1593
|
-
"%s Error publishing
|
|
1654
|
+
"%s Error publishing tool_result status update: %s",
|
|
1594
1655
|
log_identifier,
|
|
1595
1656
|
e,
|
|
1596
1657
|
)
|
|
@@ -40,11 +40,6 @@ class EmbedResolvingMCPTool(MCPTool):
|
|
|
40
40
|
self._original_mcp_tool = original_mcp_tool
|
|
41
41
|
self._tool_config = tool_config or {}
|
|
42
42
|
|
|
43
|
-
log.info(
|
|
44
|
-
"Created EmbedResolvingMCPTool for '%s' with embed resolution capabilities",
|
|
45
|
-
self.name,
|
|
46
|
-
)
|
|
47
|
-
|
|
48
43
|
async def _resolve_embeds_recursively(
|
|
49
44
|
self,
|
|
50
45
|
data: Any,
|
|
@@ -287,10 +282,6 @@ class EmbedResolvingMCPToolset(MCPToolset):
|
|
|
287
282
|
|
|
288
283
|
# Wrap each tool with embed resolution capability
|
|
289
284
|
embed_resolving_tools = []
|
|
290
|
-
log.info(
|
|
291
|
-
"EmbedResolvingMCPToolset: Wrapping %d MCP tools with embed resolution",
|
|
292
|
-
len(original_tools),
|
|
293
|
-
)
|
|
294
285
|
|
|
295
286
|
for tool in original_tools:
|
|
296
287
|
# Get tool-specific config
|
|
@@ -304,13 +295,4 @@ class EmbedResolvingMCPToolset(MCPToolset):
|
|
|
304
295
|
)
|
|
305
296
|
embed_resolving_tools.append(embed_resolving_tool)
|
|
306
297
|
|
|
307
|
-
log.info(
|
|
308
|
-
"EmbedResolvingMCPToolset: Successfully wrapped MCP tool '%s'",
|
|
309
|
-
tool.name,
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
log.info(
|
|
313
|
-
"EmbedResolvingMCPToolset: Completed wrapping %d MCP tools",
|
|
314
|
-
len(embed_resolving_tools),
|
|
315
|
-
)
|
|
316
298
|
return embed_resolving_tools
|
|
@@ -1,94 +1,143 @@
|
|
|
1
|
-
|
|
1
|
+
# DEVELOPER GUIDE for models directory
|
|
2
2
|
|
|
3
3
|
## Quick Summary
|
|
4
|
-
This directory contains concrete implementations of the `BaseLlm` interface,
|
|
4
|
+
This directory contains concrete implementations of the `BaseLlm` interface, providing wrappers for various Large Language Model APIs. These classes translate the ADK's standard `LlmRequest` into provider-specific formats and parse responses back into standard `LlmResponse` objects.
|
|
5
5
|
|
|
6
6
|
## Files Overview
|
|
7
|
-
- `lite_llm.py
|
|
7
|
+
- `lite_llm.py` - LLM client using the `litellm` library to support hundreds of models from different providers
|
|
8
|
+
- `models_llm.txt` - Documentation file containing developer guide content
|
|
8
9
|
|
|
9
10
|
## Developer API Reference
|
|
10
11
|
|
|
11
12
|
### lite_llm.py
|
|
12
|
-
**Purpose:** Provides the `LiteLlm` class, a `BaseLlm` implementation that interfaces with hundreds of LLM models through the `litellm` library.
|
|
13
|
+
**Purpose:** Provides the `LiteLlm` class, a `BaseLlm` implementation that interfaces with hundreds of LLM models through the `litellm` library. Supports models from OpenAI, Anthropic, Vertex AI, and many other providers by simply changing the model string.
|
|
13
14
|
|
|
14
|
-
**Import:** `from
|
|
15
|
+
**Import:** `from solace_agent_mesh.agent.adk.models.lite_llm import LiteLlm`
|
|
15
16
|
|
|
16
17
|
**Classes:**
|
|
17
|
-
- `LiteLlm(model: str, **kwargs)` - Wrapper around `litellm`
|
|
18
|
-
- `
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- `
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- `
|
|
18
|
+
- `LiteLlm(model: str, **kwargs)` - Wrapper around `litellm` supporting any model it recognizes
|
|
19
|
+
- `generate_content_async(llm_request: LlmRequest, stream: bool = False) -> AsyncGenerator[LlmResponse, None]` - Generates content asynchronously with optional streaming
|
|
20
|
+
- `supported_models() -> list[str]` - Returns list of supported models (empty for LiteLlm due to dynamic model support)
|
|
21
|
+
- `model: str` - The name of the LiteLlm model
|
|
22
|
+
- `llm_client: LiteLLMClient` - The LLM client instance used for API calls
|
|
23
|
+
|
|
24
|
+
- `LiteLLMClient()` - Internal client providing completion methods for better testability
|
|
25
|
+
- `acompletion(model, messages, tools, **kwargs) -> Union[ModelResponse, CustomStreamWrapper]` - Asynchronous completion call
|
|
26
|
+
- `completion(model, messages, tools, stream=False, **kwargs) -> Union[ModelResponse, CustomStreamWrapper]` - Synchronous completion call
|
|
27
|
+
|
|
28
|
+
- `FunctionChunk(BaseModel)` - Represents a function call chunk in streaming responses
|
|
29
|
+
- `id: Optional[str]` - Function call ID
|
|
30
|
+
- `name: Optional[str]` - Function name
|
|
31
|
+
- `args: Optional[str]` - Function arguments as JSON string
|
|
32
|
+
- `index: Optional[int]` - Index of the function call
|
|
33
|
+
|
|
34
|
+
- `TextChunk(BaseModel)` - Represents a text chunk in streaming responses
|
|
35
|
+
- `text: str` - The text content
|
|
36
|
+
|
|
37
|
+
- `UsageMetadataChunk(BaseModel)` - Represents token usage information
|
|
38
|
+
- `prompt_tokens: int` - Number of tokens in the prompt
|
|
39
|
+
- `completion_tokens: int` - Number of tokens in the completion
|
|
40
|
+
- `total_tokens: int` - Total number of tokens used
|
|
41
|
+
|
|
42
|
+
**Functions:**
|
|
43
|
+
- `_content_to_message_param(content: types.Content) -> Union[Message, list[Message]]` - Converts ADK Content to litellm Message format
|
|
44
|
+
- `_get_content(parts: Iterable[types.Part]) -> Union[OpenAIMessageContent, str]` - Converts parts to litellm content format
|
|
45
|
+
- `_function_declaration_to_tool_param(function_declaration: types.FunctionDeclaration) -> dict` - Converts function declarations to OpenAPI spec format
|
|
46
|
+
- `_model_response_to_generate_content_response(response: ModelResponse) -> LlmResponse` - Converts litellm response to LlmResponse
|
|
26
47
|
|
|
27
48
|
**Usage Examples:**
|
|
28
49
|
```python
|
|
29
50
|
import asyncio
|
|
30
51
|
import os
|
|
31
|
-
from
|
|
32
|
-
from
|
|
33
|
-
from google.
|
|
34
|
-
|
|
35
|
-
# Example using a Vertex AI model via litellm.
|
|
36
|
-
# Set environment variables required by the provider.
|
|
37
|
-
# os.environ["VERTEXAI_PROJECT"] = "your-gcp-project-id"
|
|
38
|
-
# os.environ["VERTEXAI_LOCATION"] = "your-gcp-location"
|
|
52
|
+
from solace_agent_mesh.agent.adk.models.lite_llm import LiteLlm
|
|
53
|
+
from solace_agent_mesh.agent.adk.models.llm_request import LlmRequest, LlmConfig
|
|
54
|
+
from google.genai.types import Content, Part
|
|
39
55
|
|
|
40
|
-
#
|
|
41
|
-
#
|
|
56
|
+
# Set environment variables for your chosen provider
|
|
57
|
+
# For OpenAI:
|
|
58
|
+
# os.environ["OPENAI_API_KEY"] = "your-api-key"
|
|
59
|
+
# For Vertex AI:
|
|
60
|
+
# os.environ["VERTEXAI_PROJECT"] = "your-project-id"
|
|
61
|
+
# os.environ["VERTEXAI_LOCATION"] = "your-location"
|
|
42
62
|
|
|
43
63
|
async def main():
|
|
44
|
-
#
|
|
45
|
-
# Any additional kwargs are passed to litellm's completion call.
|
|
64
|
+
# Initialize LiteLlm with a specific model
|
|
46
65
|
llm = LiteLlm(
|
|
47
66
|
model="gpt-4-turbo",
|
|
48
|
-
temperature=0.
|
|
49
|
-
|
|
67
|
+
temperature=0.7,
|
|
68
|
+
max_completion_tokens=150
|
|
50
69
|
)
|
|
51
|
-
|
|
52
|
-
#
|
|
70
|
+
|
|
71
|
+
# Create a request
|
|
53
72
|
request = LlmRequest(
|
|
54
73
|
contents=[
|
|
55
74
|
Content(
|
|
56
75
|
role="user",
|
|
57
|
-
parts=[Part.from_text("
|
|
76
|
+
parts=[Part.from_text("Explain quantum computing in simple terms")]
|
|
58
77
|
)
|
|
59
78
|
],
|
|
60
79
|
config=LlmConfig(
|
|
61
|
-
|
|
62
|
-
|
|
80
|
+
temperature=0.5,
|
|
81
|
+
max_output_tokens=200
|
|
63
82
|
)
|
|
64
83
|
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
84
|
+
|
|
85
|
+
# Non-streaming generation
|
|
86
|
+
print("=== Non-streaming ===")
|
|
68
87
|
async for response in llm.generate_content_async(request, stream=False):
|
|
69
|
-
|
|
70
|
-
print(response.text)
|
|
88
|
+
print(f"Response: {response.text}")
|
|
71
89
|
if response.usage_metadata:
|
|
72
|
-
print(f"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
full_response_text = ""
|
|
90
|
+
print(f"Tokens used: {response.usage_metadata.total_token_count}")
|
|
91
|
+
|
|
92
|
+
# Streaming generation
|
|
93
|
+
print("\n=== Streaming ===")
|
|
77
94
|
async for response in llm.generate_content_async(request, stream=True):
|
|
78
95
|
if response.text:
|
|
79
96
|
print(response.text, end="", flush=True)
|
|
80
|
-
full_response_text += response.text
|
|
81
97
|
if response.usage_metadata:
|
|
82
|
-
|
|
83
|
-
|
|
98
|
+
print(f"\nTotal tokens: {response.usage_metadata.total_token_count}")
|
|
99
|
+
|
|
100
|
+
# Example with function calling
|
|
101
|
+
async def function_calling_example():
|
|
102
|
+
from google.genai.types import FunctionDeclaration, Schema, Type, Tool
|
|
103
|
+
|
|
104
|
+
# Define a function for the LLM to call
|
|
105
|
+
get_weather_func = FunctionDeclaration(
|
|
106
|
+
name="get_weather",
|
|
107
|
+
description="Get current weather for a location",
|
|
108
|
+
parameters=Schema(
|
|
109
|
+
type=Type.OBJECT,
|
|
110
|
+
properties={
|
|
111
|
+
"location": Schema(type=Type.STRING, description="City name"),
|
|
112
|
+
"unit": Schema(type=Type.STRING, description="Temperature unit")
|
|
113
|
+
},
|
|
114
|
+
required=["location"]
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
llm = LiteLlm(model="gpt-4-turbo")
|
|
119
|
+
|
|
120
|
+
request = LlmRequest(
|
|
121
|
+
contents=[
|
|
122
|
+
Content(
|
|
123
|
+
role="user",
|
|
124
|
+
parts=[Part.from_text("What's the weather like in Tokyo?")]
|
|
125
|
+
)
|
|
126
|
+
],
|
|
127
|
+
config=LlmConfig(
|
|
128
|
+
tools=[Tool(function_declarations=[get_weather_func])]
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
async for response in llm.generate_content_async(request):
|
|
133
|
+
if response.function_calls:
|
|
134
|
+
for func_call in response.function_calls:
|
|
135
|
+
print(f"Function called: {func_call.name}")
|
|
136
|
+
print(f"Arguments: {func_call.args}")
|
|
84
137
|
|
|
85
138
|
if __name__ == "__main__":
|
|
86
|
-
|
|
87
|
-
#
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
# Since this is an async function, we run it with asyncio.
|
|
92
|
-
# asyncio.run(main())
|
|
93
|
-
pass
|
|
94
|
-
```
|
|
139
|
+
asyncio.run(main())
|
|
140
|
+
# asyncio.run(function_calling_example())
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
# content_hash: 12789ad2e16cd9ea5a81abdd68258d9ef30520bed5c51ba8d00ea66014191964
|
|
@@ -3,6 +3,7 @@ Manages the asynchronous execution of the ADK Runner.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
|
+
import uuid
|
|
6
7
|
from google.adk.agents.invocation_context import LlmCallsLimitExceededError
|
|
7
8
|
|
|
8
9
|
|
|
@@ -22,7 +23,7 @@ from google.genai import types as adk_types
|
|
|
22
23
|
from google.adk.events import Event as ADKEvent
|
|
23
24
|
from google.adk.events.event_actions import EventActions
|
|
24
25
|
|
|
25
|
-
from ...common
|
|
26
|
+
from ...common import a2a
|
|
26
27
|
|
|
27
28
|
if TYPE_CHECKING:
|
|
28
29
|
from ..sac.component import SamAgentComponent
|
|
@@ -87,7 +88,7 @@ async def run_adk_async_task_thread_wrapper(
|
|
|
87
88
|
await component.session_service.append_event(
|
|
88
89
|
session=adk_session, event=context_setting_event
|
|
89
90
|
)
|
|
90
|
-
log.
|
|
91
|
+
log.debug(
|
|
91
92
|
"%s Appended context-setting event to ADK session %s (via component.session_service) for task %s.",
|
|
92
93
|
component.log_identifier,
|
|
93
94
|
adk_session.id,
|
|
@@ -156,13 +157,14 @@ async def run_adk_async_task_thread_wrapper(
|
|
|
156
157
|
task_id_for_peer = sub_task_id.replace(
|
|
157
158
|
component.CORRELATION_DATA_PREFIX, "", 1
|
|
158
159
|
)
|
|
159
|
-
|
|
160
|
-
|
|
160
|
+
peer_cancel_request = a2a.create_cancel_task_request(
|
|
161
|
+
task_id=task_id_for_peer
|
|
162
|
+
)
|
|
161
163
|
peer_cancel_user_props = {"clientId": component.agent_name}
|
|
162
164
|
peer_request_topic = component._get_agent_request_topic(
|
|
163
165
|
target_peer_agent_name
|
|
164
166
|
)
|
|
165
|
-
component.
|
|
167
|
+
component.publish_a2a_message(
|
|
166
168
|
payload=peer_cancel_request.model_dump(exclude_none=True),
|
|
167
169
|
topic=peer_request_topic,
|
|
168
170
|
user_properties=peer_cancel_user_props,
|