solace-agent-mesh 1.6.1__py3-none-any.whl → 1.6.3__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/app_llm_agent.py +26 -0
- solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +1 -1
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +135 -31
- solace_agent_mesh/agent/adk/models/lite_llm.py +5 -0
- solace_agent_mesh/agent/adk/runner.py +10 -12
- solace_agent_mesh/agent/adk/services.py +53 -17
- solace_agent_mesh/agent/adk/setup.py +66 -38
- solace_agent_mesh/agent/protocol/event_handlers.py +243 -122
- solace_agent_mesh/agent/proxies/a2a/app.py +3 -2
- solace_agent_mesh/agent/proxies/base/app.py +3 -2
- solace_agent_mesh/agent/sac/app.py +43 -2
- solace_agent_mesh/agent/sac/component.py +200 -72
- solace_agent_mesh/agent/sac/task_execution_context.py +35 -4
- solace_agent_mesh/agent/tools/tool_config_types.py +3 -0
- solace_agent_mesh/agent/utils/artifact_helpers.py +1 -1
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/240a0364.c39f8388.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/631738c7.7c4594c9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/66d4869e.830d443f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/71da7b71.ddbdfbe2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/94e8668d.3b883666.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e92d0134.4f395c6b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.720d2ef2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.ed05b14d.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.a8a75e0b.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/components/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +4 -25
- solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +76 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +5 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +23 -28
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +3 -6
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +3 -3
- solace_agent_mesh/assets/docs/lunr-index-1761744323675.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1761744323675.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-BTf6dqwp.js → authCallback-D4_RMYRh.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-CaY59VuC.js → client-UZ3qU6Bq.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main--3yJYl7S.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-DojKHS49.js +342 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{vendor-BEmvJSYz.js → vendor-DSqhjwq_.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
- solace_agent_mesh/common/a2a/events.py +2 -1
- solace_agent_mesh/common/sac/sam_component_base.py +24 -18
- solace_agent_mesh/common/utils/pydantic_utils.py +90 -3
- solace_agent_mesh/gateway/base/component.py +12 -8
- solace_agent_mesh/gateway/http_sse/app.py +26 -0
- solace_agent_mesh/gateway/http_sse/component.py +158 -79
- solace_agent_mesh/gateway/http_sse/dependencies.py +83 -59
- solace_agent_mesh/gateway/http_sse/main.py +35 -11
- solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/auth.py +103 -6
- solace_agent_mesh/gateway/http_sse/routers/config.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/sse.py +15 -5
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +3 -3
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +90 -8
- solace_agent_mesh/gateway/http_sse/services/session_service.py +1 -1
- solace_agent_mesh/gateway/http_sse/session_manager.py +15 -15
- solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +16 -1
- solace_agent_mesh/gateway/http_sse/sse_manager.py +15 -6
- solace_agent_mesh/templates/logging_config_template.ini +2 -2
- {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.6.3.dist-info}/METADATA +2 -2
- {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.6.3.dist-info}/RECORD +112 -110
- solace_agent_mesh/assets/docs/assets/js/240a0364.7eac6021.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/631738c7.a8b1ef8b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/71da7b71.38583438.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/94e8668d.b5ddb7a1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e92d0134.cf6d6522.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.42f59cdd.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.b12eac43.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.e268214e.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1761248203150.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1761248203150.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-B32noGmR.js +0 -342
- solace_agent_mesh/client/webui/frontend/static/assets/main-DHJKSW1S.css +0 -1
- /solace_agent_mesh/assets/docs/assets/js/{main.b12eac43.js.LICENSE.txt → main.ed05b14d.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.6.3.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.6.3.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.6.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,52 +2,105 @@
|
|
|
2
2
|
Contains event handling logic for the A2A_ADK_HostComponent.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import logging
|
|
6
|
-
import json
|
|
7
5
|
import asyncio
|
|
8
|
-
from typing import TYPE_CHECKING, Dict, Any
|
|
9
6
|
import fnmatch
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
from
|
|
13
|
-
|
|
14
|
-
from solace_ai_connector.common.event import Event, EventType
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Dict
|
|
10
|
+
|
|
15
11
|
from a2a.types import (
|
|
16
12
|
A2ARequest,
|
|
17
|
-
AgentCard,
|
|
18
13
|
AgentCapabilities,
|
|
14
|
+
AgentCard,
|
|
19
15
|
AgentExtension,
|
|
20
16
|
DataPart,
|
|
21
17
|
JSONRPCResponse,
|
|
22
18
|
Task,
|
|
23
19
|
TaskArtifactUpdateEvent,
|
|
20
|
+
TaskState,
|
|
24
21
|
TaskStatusUpdateEvent,
|
|
25
22
|
TextPart,
|
|
26
23
|
)
|
|
24
|
+
from google.adk.agents import RunConfig
|
|
25
|
+
from google.adk.agents.run_config import StreamingMode
|
|
26
|
+
from solace_ai_connector.common.event import Event, EventType
|
|
27
|
+
from solace_ai_connector.common.message import Message as SolaceMessage
|
|
28
|
+
|
|
29
|
+
from ...agent.adk.callbacks import _publish_data_part_status_update
|
|
30
|
+
from ...agent.adk.runner import run_adk_async_task_thread_wrapper
|
|
31
|
+
from ...agent.utils.artifact_helpers import generate_artifact_metadata_summary
|
|
27
32
|
from ...common import a2a
|
|
28
33
|
from ...common.a2a import (
|
|
29
34
|
get_agent_request_topic,
|
|
30
|
-
get_discovery_topic,
|
|
31
|
-
translate_a2a_to_adk_content,
|
|
32
|
-
get_client_response_topic,
|
|
33
35
|
get_agent_response_subscription_topic,
|
|
34
36
|
get_agent_status_subscription_topic,
|
|
37
|
+
get_client_response_topic,
|
|
38
|
+
get_discovery_topic,
|
|
35
39
|
get_sam_events_subscription_topic,
|
|
36
40
|
get_text_from_message,
|
|
37
41
|
topic_matches_subscription,
|
|
42
|
+
translate_a2a_to_adk_content,
|
|
38
43
|
)
|
|
39
|
-
from ...
|
|
40
|
-
|
|
41
|
-
)
|
|
42
|
-
from ...agent.adk.runner import run_adk_async_task_thread_wrapper
|
|
44
|
+
from ...common.a2a.types import ToolsExtensionParams
|
|
45
|
+
from ...common.data_parts import ToolResultData
|
|
43
46
|
from ..sac.task_execution_context import TaskExecutionContext
|
|
44
|
-
from google.adk.agents import RunConfig
|
|
45
47
|
|
|
46
48
|
if TYPE_CHECKING:
|
|
47
49
|
from ..sac.component import SamAgentComponent
|
|
48
|
-
from google.adk.agents.run_config import StreamingMode
|
|
49
50
|
|
|
50
51
|
log = logging.getLogger(__name__)
|
|
52
|
+
trace_logger = logging.getLogger("sam_trace")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _forward_jsonrpc_response(
|
|
56
|
+
component: "SamAgentComponent",
|
|
57
|
+
original_jsonrpc_request_id: str,
|
|
58
|
+
result_data: Any,
|
|
59
|
+
target_topic: str,
|
|
60
|
+
main_logical_task_id: str,
|
|
61
|
+
peer_agent_name: str,
|
|
62
|
+
message: SolaceMessage,
|
|
63
|
+
) -> None:
|
|
64
|
+
"""
|
|
65
|
+
Utility method to forward a JSONRPCResponse with the given result data.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
component: The SamAgentComponent instance
|
|
69
|
+
original_jsonrpc_request_id: The original JSONRPC request ID
|
|
70
|
+
result_data: The data to include in the response result
|
|
71
|
+
target_topic: The topic to publish to
|
|
72
|
+
main_logical_task_id: The main logical task ID for logging
|
|
73
|
+
peer_agent_name: The peer agent name for logging
|
|
74
|
+
message: The original message to acknowledge
|
|
75
|
+
"""
|
|
76
|
+
forwarded_rpc_response = JSONRPCResponse(
|
|
77
|
+
id=original_jsonrpc_request_id,
|
|
78
|
+
result=result_data,
|
|
79
|
+
)
|
|
80
|
+
payload_to_publish = forwarded_rpc_response.model_dump(
|
|
81
|
+
by_alias=True, exclude_none=True
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
component.publish_a2a_message(
|
|
86
|
+
payload_to_publish,
|
|
87
|
+
target_topic,
|
|
88
|
+
)
|
|
89
|
+
log.debug(
|
|
90
|
+
"%s Forwarded DataPart signal for main task %s (from peer %s) to %s.",
|
|
91
|
+
component.log_identifier,
|
|
92
|
+
main_logical_task_id,
|
|
93
|
+
peer_agent_name,
|
|
94
|
+
target_topic,
|
|
95
|
+
)
|
|
96
|
+
except Exception as pub_err:
|
|
97
|
+
log.exception(
|
|
98
|
+
"%s Failed to publish forwarded status signal for main task %s: %s",
|
|
99
|
+
component.log_identifier,
|
|
100
|
+
main_logical_task_id,
|
|
101
|
+
pub_err,
|
|
102
|
+
)
|
|
103
|
+
message.call_acknowledgements()
|
|
51
104
|
|
|
52
105
|
|
|
53
106
|
def _register_peer_artifacts_in_parent_context(
|
|
@@ -196,7 +249,7 @@ async def process_event(component, event: Event):
|
|
|
196
249
|
|
|
197
250
|
async def _publish_peer_tool_result_notification(
|
|
198
251
|
component: "SamAgentComponent",
|
|
199
|
-
correlation_data:
|
|
252
|
+
correlation_data: dict[str, Any],
|
|
200
253
|
payload_to_queue: Any,
|
|
201
254
|
log_identifier: str,
|
|
202
255
|
):
|
|
@@ -465,6 +518,35 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
465
518
|
# The gateway/client is the source of truth for the task ID.
|
|
466
519
|
# The agent adopts the ID from the JSON-RPC request envelope.
|
|
467
520
|
logical_task_id = str(a2a.get_request_id(a2a_request))
|
|
521
|
+
|
|
522
|
+
try:
|
|
523
|
+
from solace_agent_mesh_enterprise.auth.input_required import (
|
|
524
|
+
a2a_auth_message_handler,
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
try:
|
|
528
|
+
message_handled = await a2a_auth_message_handler(
|
|
529
|
+
component, a2a_message, logical_task_id
|
|
530
|
+
)
|
|
531
|
+
if message_handled:
|
|
532
|
+
message.call_acknowledgements()
|
|
533
|
+
log.debug(
|
|
534
|
+
"%s ACKed message handled by input-required auth handler.",
|
|
535
|
+
component.log_identifier,
|
|
536
|
+
)
|
|
537
|
+
return None
|
|
538
|
+
except Exception as auth_import_err:
|
|
539
|
+
log.error(
|
|
540
|
+
"%s Error in input-required auth handler: %s",
|
|
541
|
+
component.log_identifier,
|
|
542
|
+
auth_import_err,
|
|
543
|
+
)
|
|
544
|
+
message.call_acknowledgements()
|
|
545
|
+
return None
|
|
546
|
+
|
|
547
|
+
except ImportError:
|
|
548
|
+
pass
|
|
549
|
+
|
|
468
550
|
# The session id is now contextId on the message
|
|
469
551
|
original_session_id = a2a_message.context_id
|
|
470
552
|
message_id = a2a_message.message_id
|
|
@@ -490,7 +572,7 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
490
572
|
)
|
|
491
573
|
else:
|
|
492
574
|
session_behavior = component.default_session_behavior
|
|
493
|
-
log.
|
|
575
|
+
log.debug(
|
|
494
576
|
"%s No 'sessionBehavior' in task metadata. Using component default: '%s'.",
|
|
495
577
|
component.log_identifier,
|
|
496
578
|
session_behavior,
|
|
@@ -632,7 +714,6 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
632
714
|
"is_streaming": is_streaming_request,
|
|
633
715
|
"statusTopic": status_topic_from_peer,
|
|
634
716
|
"replyToTopic": reply_topic_from_peer,
|
|
635
|
-
"original_solace_message": message,
|
|
636
717
|
"a2a_user_config": a2a_user_config,
|
|
637
718
|
"effective_session_id": effective_session_id,
|
|
638
719
|
"is_run_based_session": is_run_based_session,
|
|
@@ -654,17 +735,28 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
654
735
|
component.log_identifier,
|
|
655
736
|
logical_task_id,
|
|
656
737
|
)
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
738
|
+
if trace_logger.isEnabledFor(logging.DEBUG):
|
|
739
|
+
trace_logger.debug(
|
|
740
|
+
"%s A2A Context (shared service model): %s",
|
|
741
|
+
component.log_identifier,
|
|
742
|
+
a2a_context,
|
|
743
|
+
)
|
|
744
|
+
else:
|
|
745
|
+
log.debug(
|
|
746
|
+
"%s A2A Context prepared for task %s",
|
|
747
|
+
component.log_identifier,
|
|
748
|
+
a2a_context.get("logical_task_id", "unknown"),
|
|
749
|
+
)
|
|
662
750
|
|
|
663
751
|
# Create and store the execution context for this task
|
|
664
752
|
task_context = TaskExecutionContext(
|
|
665
753
|
task_id=logical_task_id, a2a_context=a2a_context
|
|
666
754
|
)
|
|
667
755
|
|
|
756
|
+
# Store the original Solace message in TaskExecutionContext instead of a2a_context
|
|
757
|
+
# This avoids serialization issues when a2a_context is stored in ADK session state
|
|
758
|
+
task_context.set_original_solace_message(message)
|
|
759
|
+
|
|
668
760
|
# Store auth token for peer delegation using generic security storage
|
|
669
761
|
if hasattr(component, "trust_manager") and component.trust_manager:
|
|
670
762
|
auth_token = message.get_user_properties().get("authToken")
|
|
@@ -760,7 +852,7 @@ async def handle_a2a_request(component, message: SolaceMessage):
|
|
|
760
852
|
streaming_mode = StreamingMode.SSE
|
|
761
853
|
|
|
762
854
|
max_llm_calls_per_task = component.get_config("max_llm_calls_per_task", 20)
|
|
763
|
-
log.
|
|
855
|
+
log.debug(
|
|
764
856
|
"%s Using max_llm_calls_per_task: %s",
|
|
765
857
|
component.log_identifier,
|
|
766
858
|
max_llm_calls_per_task,
|
|
@@ -926,13 +1018,13 @@ def handle_agent_card_message(component, message: SolaceMessage):
|
|
|
926
1018
|
break
|
|
927
1019
|
|
|
928
1020
|
if is_allowed:
|
|
929
|
-
|
|
1021
|
+
|
|
930
1022
|
# Also store in peer_agents for backward compatibility
|
|
931
1023
|
component.peer_agents[agent_name] = agent_card
|
|
932
1024
|
|
|
933
1025
|
# Store the agent card in the registry for health tracking
|
|
934
1026
|
is_new = component.agent_registry.add_or_update_agent(agent_card)
|
|
935
|
-
|
|
1027
|
+
|
|
936
1028
|
if is_new:
|
|
937
1029
|
log.info(
|
|
938
1030
|
"%s Registered new agent '%s' in registry.",
|
|
@@ -1053,93 +1145,143 @@ async def handle_a2a_response(component, message: SolaceMessage):
|
|
|
1053
1145
|
if isinstance(payload_data, TaskStatusUpdateEvent):
|
|
1054
1146
|
try:
|
|
1055
1147
|
status_event = payload_data
|
|
1148
|
+
|
|
1056
1149
|
data_parts = a2a.get_data_parts_from_status_update(
|
|
1057
1150
|
status_event
|
|
1058
1151
|
)
|
|
1059
1152
|
if data_parts:
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
sub_task_id,
|
|
1153
|
+
|
|
1154
|
+
peer_agent_name = (
|
|
1155
|
+
status_event.metadata.get(
|
|
1156
|
+
"agent_name", "UnknownPeer"
|
|
1065
1157
|
)
|
|
1066
|
-
|
|
1158
|
+
if status_event.metadata
|
|
1159
|
+
else "UnknownPeer"
|
|
1160
|
+
)
|
|
1161
|
+
|
|
1162
|
+
correlation_data = (
|
|
1163
|
+
await component._get_correlation_data_for_sub_task(
|
|
1067
1164
|
sub_task_id
|
|
1068
1165
|
)
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
message.call_acknowledgements()
|
|
1076
|
-
return
|
|
1077
|
-
|
|
1078
|
-
original_task_context = correlation_data.get(
|
|
1079
|
-
"original_task_context"
|
|
1166
|
+
)
|
|
1167
|
+
if not correlation_data:
|
|
1168
|
+
log.warning(
|
|
1169
|
+
"%s Correlation data not found for sub-task %s. Cannot forward status signal.",
|
|
1170
|
+
component.log_identifier,
|
|
1171
|
+
sub_task_id,
|
|
1080
1172
|
)
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
"%s original_task_context not found in correlation data for sub-task %s. Cannot forward status signal.",
|
|
1084
|
-
component.log_identifier,
|
|
1085
|
-
sub_task_id,
|
|
1086
|
-
)
|
|
1087
|
-
message.call_acknowledgements()
|
|
1088
|
-
return
|
|
1173
|
+
message.call_acknowledgements()
|
|
1174
|
+
return
|
|
1089
1175
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1176
|
+
original_task_context = correlation_data.get(
|
|
1177
|
+
"original_task_context"
|
|
1178
|
+
)
|
|
1179
|
+
if not original_task_context:
|
|
1180
|
+
log.warning(
|
|
1181
|
+
"%s original_task_context not found in correlation data for sub-task %s. Cannot forward status signal.",
|
|
1182
|
+
component.log_identifier,
|
|
1183
|
+
sub_task_id,
|
|
1095
1184
|
)
|
|
1096
|
-
|
|
1097
|
-
|
|
1185
|
+
message.call_acknowledgements()
|
|
1186
|
+
return
|
|
1187
|
+
|
|
1188
|
+
main_logical_task_id = original_task_context.get(
|
|
1189
|
+
"logical_task_id"
|
|
1190
|
+
)
|
|
1191
|
+
original_jsonrpc_request_id = original_task_context.get(
|
|
1192
|
+
"jsonrpc_request_id"
|
|
1193
|
+
)
|
|
1194
|
+
main_context_id = original_task_context.get("contextId")
|
|
1195
|
+
|
|
1196
|
+
target_topic_for_forward = original_task_context.get(
|
|
1197
|
+
"statusTopic"
|
|
1198
|
+
)
|
|
1199
|
+
|
|
1200
|
+
if (
|
|
1201
|
+
not main_logical_task_id
|
|
1202
|
+
or not original_jsonrpc_request_id
|
|
1203
|
+
or not target_topic_for_forward
|
|
1204
|
+
):
|
|
1205
|
+
log.error(
|
|
1206
|
+
"%s Missing critical info (main_task_id, original_rpc_id, or target_status_topic) in context for sub-task %s. Cannot forward. Context: %s",
|
|
1207
|
+
component.log_identifier,
|
|
1208
|
+
sub_task_id,
|
|
1209
|
+
original_task_context,
|
|
1098
1210
|
)
|
|
1211
|
+
message.call_acknowledgements()
|
|
1212
|
+
return
|
|
1099
1213
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1214
|
+
event_metadata = {
|
|
1215
|
+
"agent_name": component.agent_name,
|
|
1216
|
+
"forwarded_from_peer": peer_agent_name,
|
|
1217
|
+
"original_peer_event_taskId": status_event.task_id,
|
|
1218
|
+
"original_peer_event_timestamp": (
|
|
1219
|
+
status_event.status.timestamp
|
|
1220
|
+
if status_event.status
|
|
1221
|
+
and status_event.status.timestamp
|
|
1222
|
+
else None
|
|
1223
|
+
),
|
|
1224
|
+
"function_call_id": correlation_data.get(
|
|
1225
|
+
"adk_function_call_id", None
|
|
1226
|
+
),
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
if (
|
|
1230
|
+
status_event.status.state
|
|
1231
|
+
== TaskState.input_required
|
|
1232
|
+
):
|
|
1233
|
+
log.debug(
|
|
1234
|
+
"%s Received input-required status for sub-task %s. Requesting user input. Forwarding to target.",
|
|
1235
|
+
component.log_identifier,
|
|
1236
|
+
sub_task_id,
|
|
1102
1237
|
)
|
|
1103
1238
|
|
|
1104
1239
|
if (
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1240
|
+
status_event.metadata
|
|
1241
|
+
and "task_call_stack" in status_event.metadata
|
|
1242
|
+
and isinstance(
|
|
1243
|
+
status_event.metadata["task_call_stack"],
|
|
1244
|
+
list,
|
|
1245
|
+
)
|
|
1108
1246
|
):
|
|
1109
|
-
|
|
1110
|
-
"
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1247
|
+
task_call_stack = status_event.metadata[
|
|
1248
|
+
"task_call_stack"
|
|
1249
|
+
].copy()
|
|
1250
|
+
task_call_stack.insert(0, sub_task_id)
|
|
1251
|
+
event_metadata["task_call_stack"] = (
|
|
1252
|
+
task_call_stack
|
|
1114
1253
|
)
|
|
1115
|
-
|
|
1116
|
-
|
|
1254
|
+
else:
|
|
1255
|
+
event_metadata["task_call_stack"] = [
|
|
1256
|
+
sub_task_id
|
|
1257
|
+
]
|
|
1258
|
+
|
|
1259
|
+
status_event.metadata = event_metadata
|
|
1260
|
+
status_event.task_id = main_logical_task_id
|
|
1261
|
+
|
|
1262
|
+
_forward_jsonrpc_response(
|
|
1263
|
+
component=component,
|
|
1264
|
+
original_jsonrpc_request_id=original_jsonrpc_request_id,
|
|
1265
|
+
result_data=status_event,
|
|
1266
|
+
target_topic=target_topic_for_forward,
|
|
1267
|
+
main_logical_task_id=main_logical_task_id,
|
|
1268
|
+
peer_agent_name=peer_agent_name,
|
|
1269
|
+
message=message,
|
|
1270
|
+
)
|
|
1271
|
+
return
|
|
1117
1272
|
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
else "UnknownPeer"
|
|
1273
|
+
for data_part in data_parts:
|
|
1274
|
+
log.info(
|
|
1275
|
+
"%s Received DataPart signal from peer for sub-task %s. Forwarding...",
|
|
1276
|
+
component.log_identifier,
|
|
1277
|
+
sub_task_id,
|
|
1124
1278
|
)
|
|
1125
1279
|
|
|
1126
1280
|
forwarded_message = a2a.create_agent_parts_message(
|
|
1127
1281
|
parts=[data_part],
|
|
1128
|
-
metadata=
|
|
1129
|
-
"agent_name": component.agent_name,
|
|
1130
|
-
"forwarded_from_peer": peer_agent_name,
|
|
1131
|
-
"original_peer_event_taskId": status_event.task_id,
|
|
1132
|
-
"original_peer_event_timestamp": (
|
|
1133
|
-
status_event.status.timestamp
|
|
1134
|
-
if status_event.status
|
|
1135
|
-
and status_event.status.timestamp
|
|
1136
|
-
else None
|
|
1137
|
-
),
|
|
1138
|
-
"function_call_id": correlation_data.get(
|
|
1139
|
-
"adk_function_call_id", None
|
|
1140
|
-
),
|
|
1141
|
-
},
|
|
1282
|
+
metadata=event_metadata,
|
|
1142
1283
|
)
|
|
1284
|
+
|
|
1143
1285
|
forwarded_event = a2a.create_status_update(
|
|
1144
1286
|
task_id=main_logical_task_id,
|
|
1145
1287
|
context_id=main_context_id,
|
|
@@ -1153,36 +1295,15 @@ async def handle_a2a_response(component, message: SolaceMessage):
|
|
|
1153
1295
|
forwarded_event.status.timestamp = (
|
|
1154
1296
|
status_event.status.timestamp
|
|
1155
1297
|
)
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1298
|
+
_forward_jsonrpc_response(
|
|
1299
|
+
component=component,
|
|
1300
|
+
original_jsonrpc_request_id=original_jsonrpc_request_id,
|
|
1301
|
+
result_data=forwarded_event,
|
|
1302
|
+
target_topic=target_topic_for_forward,
|
|
1303
|
+
main_logical_task_id=main_logical_task_id,
|
|
1304
|
+
peer_agent_name=peer_agent_name,
|
|
1305
|
+
message=message,
|
|
1159
1306
|
)
|
|
1160
|
-
payload_to_publish = (
|
|
1161
|
-
forwarded_rpc_response.model_dump(
|
|
1162
|
-
by_alias=True, exclude_none=True
|
|
1163
|
-
)
|
|
1164
|
-
)
|
|
1165
|
-
|
|
1166
|
-
try:
|
|
1167
|
-
component.publish_a2a_message(
|
|
1168
|
-
payload_to_publish,
|
|
1169
|
-
target_topic_for_forward,
|
|
1170
|
-
)
|
|
1171
|
-
log.info(
|
|
1172
|
-
"%s Forwarded DataPart signal for main task %s (from peer %s) to %s.",
|
|
1173
|
-
component.log_identifier,
|
|
1174
|
-
main_logical_task_id,
|
|
1175
|
-
peer_agent_name,
|
|
1176
|
-
target_topic_for_forward,
|
|
1177
|
-
)
|
|
1178
|
-
except Exception as pub_err:
|
|
1179
|
-
log.exception(
|
|
1180
|
-
"%s Failed to publish forwarded status signal for main task %s: %s",
|
|
1181
|
-
component.log_identifier,
|
|
1182
|
-
main_logical_task_id,
|
|
1183
|
-
pub_err,
|
|
1184
|
-
)
|
|
1185
|
-
message.call_acknowledgements()
|
|
1186
1307
|
return
|
|
1187
1308
|
|
|
1188
1309
|
payload_to_queue = status_event.model_dump(
|
|
@@ -43,8 +43,9 @@ class A2AProxyApp(BaseProxyApp):
|
|
|
43
43
|
app_info["app_config"] = app_config
|
|
44
44
|
log.debug("A2A proxy configuration validated successfully.")
|
|
45
45
|
except ValidationError as e:
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
message = A2AProxyAppConfig.format_validation_error_message(e, app_info['name'])
|
|
47
|
+
log.error("Invalid A2A Proxy configuration:\n%s", message)
|
|
48
|
+
raise
|
|
48
49
|
|
|
49
50
|
super().__init__(app_info, **kwargs)
|
|
50
51
|
|
|
@@ -43,8 +43,9 @@ class BaseProxyApp(App, ABC):
|
|
|
43
43
|
# Overwrite the raw dict with the validated object for downstream use
|
|
44
44
|
app_info["app_config"] = app_config
|
|
45
45
|
except ValidationError as e:
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
message = BaseProxyAppConfig.format_validation_error_message(e, app_info['name'])
|
|
47
|
+
log.error("Invalid Proxy configuration:\n%s", message)
|
|
48
|
+
raise
|
|
48
49
|
|
|
49
50
|
namespace = app_config.get("namespace")
|
|
50
51
|
proxied_agents = app_config.get("proxied_agents", [])
|
|
@@ -230,6 +230,32 @@ class ArtifactServiceConfig(SamConfigBase):
|
|
|
230
230
|
)
|
|
231
231
|
return self
|
|
232
232
|
|
|
233
|
+
class AgentIdentityConfig(SamConfigBase):
|
|
234
|
+
"""Configuration for agent identity and key management."""
|
|
235
|
+
key_mode: Literal["auto", "manual"] = Field(
|
|
236
|
+
default="auto",
|
|
237
|
+
description="Key mode for agent identity: 'auto' for automatic generation, 'manual' for user-provided."
|
|
238
|
+
)
|
|
239
|
+
key_identity: Optional[str] = Field(
|
|
240
|
+
default=None,
|
|
241
|
+
description="Actual key value when key_mode is 'manual'."
|
|
242
|
+
)
|
|
243
|
+
key_persistence: Optional[str] = Field(
|
|
244
|
+
default=None,
|
|
245
|
+
description="Path to the key file, e.g. '/path/to/keys/agent_{name}.key'."
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
@model_validator(mode="after")
|
|
249
|
+
def check_key_mode_and_identity(self) -> "AgentIdentityConfig":
|
|
250
|
+
if self.key_mode == "manual" and not self.key_identity:
|
|
251
|
+
raise ValueError(
|
|
252
|
+
"'key_identity' is required when 'key_mode' is 'manual'."
|
|
253
|
+
)
|
|
254
|
+
if self.key_mode == "auto" and self.key_identity:
|
|
255
|
+
log.warning(
|
|
256
|
+
"Configuration Warning: 'key_identity' is ignored when 'key_mode' is 'auto'."
|
|
257
|
+
)
|
|
258
|
+
return self
|
|
233
259
|
|
|
234
260
|
class SessionServiceConfig(SamConfigBase):
|
|
235
261
|
"""Configuration for the ADK Session Service."""
|
|
@@ -245,6 +271,12 @@ class SessionServiceConfig(SamConfigBase):
|
|
|
245
271
|
)
|
|
246
272
|
|
|
247
273
|
|
|
274
|
+
class CredentialServiceConfig(SamConfigBase):
|
|
275
|
+
"""Configuration for the ADK Credential Service."""
|
|
276
|
+
|
|
277
|
+
type: str = Field(..., description="Service type (e.g., 'memory').")
|
|
278
|
+
|
|
279
|
+
|
|
248
280
|
class SamAgentAppConfig(SamConfigBase):
|
|
249
281
|
"""Pydantic model for the complete agent application configuration."""
|
|
250
282
|
|
|
@@ -264,6 +296,10 @@ class SamAgentAppConfig(SamConfigBase):
|
|
|
264
296
|
model: Union[str, Dict[str, Any]] = Field(
|
|
265
297
|
..., description="ADK model name (string) or BaseLlm config dict."
|
|
266
298
|
)
|
|
299
|
+
agent_identity: Optional[AgentIdentityConfig] = Field(
|
|
300
|
+
default_factory=lambda: AgentIdentityConfig(key_mode="auto"),
|
|
301
|
+
description="Configuration for agent identity and key management."
|
|
302
|
+
)
|
|
267
303
|
trust_manager: Optional[Union[TrustManagerConfig, Dict[str, Any]]] = Field(
|
|
268
304
|
default=None,
|
|
269
305
|
description="Configuration for the Trust Manager (enterprise feature)",
|
|
@@ -306,6 +342,10 @@ class SamAgentAppConfig(SamConfigBase):
|
|
|
306
342
|
default={"type": "memory"},
|
|
307
343
|
description="Configuration for ADK Memory Service (defaults to memory).",
|
|
308
344
|
)
|
|
345
|
+
credential_service: Optional[CredentialServiceConfig] = Field(
|
|
346
|
+
default=None,
|
|
347
|
+
description="Configuration for ADK Credential Service (optional).",
|
|
348
|
+
)
|
|
309
349
|
multi_session_request_response: Dict[str, Any] = Field(
|
|
310
350
|
default_factory=lambda: {"enabled": True},
|
|
311
351
|
description="Enables multi-session request/response capabilities for the agent, required for peer delegation.",
|
|
@@ -436,8 +476,9 @@ class SamAgentApp(App):
|
|
|
436
476
|
# Overwrite the raw dict with the validated object for downstream use
|
|
437
477
|
app_info["app_config"] = app_config
|
|
438
478
|
except ValidationError as e:
|
|
439
|
-
|
|
440
|
-
|
|
479
|
+
message = SamAgentAppConfig.format_validation_error_message(e, app_info['name'], app_config_dict.get('agent_name'))
|
|
480
|
+
log.error("Invalid Agent configuration:\n%s", message)
|
|
481
|
+
raise
|
|
441
482
|
|
|
442
483
|
# The rest of the method can now safely use .get() on the app_config object,
|
|
443
484
|
# ensuring full backward compatibility.
|