solace-agent-mesh 1.0.1__py3-none-any.whl → 1.0.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/__init__.py +5 -0
- solace_agent_mesh/agent/adk/callbacks.py +23 -1
- solace_agent_mesh/agent/adk/filesystem_artifact_service.py +34 -41
- solace_agent_mesh/agent/adk/runner.py +10 -6
- solace_agent_mesh/agent/adk/services.py +141 -60
- solace_agent_mesh/agent/protocol/event_handlers.py +84 -155
- solace_agent_mesh/agent/sac/app.py +12 -2
- solace_agent_mesh/agent/sac/component.py +182 -38
- solace_agent_mesh/agent/sac/task_execution_context.py +15 -6
- solace_agent_mesh/agent/tools/builtin_artifact_tools.py +8 -1
- solace_agent_mesh/agent/tools/general_agent_tools.py +4 -2
- solace_agent_mesh/agent/tools/peer_agent_tool.py +97 -88
- solace_agent_mesh/agent/utils/artifact_helpers.py +148 -14
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/{04989206.674a8007.js → 04989206.da8246cd.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/1023fc19.8e6d174c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1c6e87d2.a8c5ce5a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{3d406171.f722eaf5.js → 3d406171.9b081d5f.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/75384d09.c3991823.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9eff14a2.036c35ea.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{aba87c2f.d3e2dcc3.js → aba87c2f.a6b84da6.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/{ae4415af.8e279b5d.js → ae4415af.96189a93.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/b7006a3a.38c0cf3d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/bb2ef573.56931473.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{cc969b05.954186d4.js → cc969b05.bd3e0d6c.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.5aff74ab.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f897a61a.862b0514.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.dc7db184.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.aa687c82.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +8 -6
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +21 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/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/quick-start/index.html +10 -10
- 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 +5 -5
- 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 +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +140 -0
- 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 +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +3 -3
- solace_agent_mesh/assets/docs/img/solace-logo-text.svg +18 -0
- solace_agent_mesh/assets/docs/lunr-index-1755120326601.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1755120326601.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/init_cmd/env_step.py +8 -0
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +21 -1
- solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +1 -0
- solace_agent_mesh/cli/commands/plugin_cmd/official_registry.py +2 -1
- solace_agent_mesh/cli/commands/run_cmd.py +42 -3
- solace_agent_mesh/cli/main.py +1 -3
- solace_agent_mesh/client/webui/frontend/static/assets/main-BCpII1-0.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-DzKPMTRs.js +673 -0
- solace_agent_mesh/client/webui/frontend/static/index.html +2 -2
- solace_agent_mesh/common/exceptions.py +25 -0
- solace_agent_mesh/common/utils/initializer.py +51 -0
- solace_agent_mesh/common/utils/message_utils.py +79 -0
- solace_agent_mesh/config_portal/backend/common.py +1 -1
- solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +2 -1
- solace_agent_mesh/config_portal/backend/plugin_catalog/registry_manager.py +6 -2
- solace_agent_mesh/config_portal/backend/plugin_catalog/scraper.py +1 -5
- solace_agent_mesh/config_portal/backend/plugin_catalog_server.py +1 -0
- solace_agent_mesh/config_portal/backend/server.py +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-xSu2leR8.js +48 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d2b54a97.js → manifest-950eb3be.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
- solace_agent_mesh/gateway/base/component.py +15 -2
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +9 -3
- solace_agent_mesh/gateway/http_sse/sse_manager.py +23 -1
- solace_agent_mesh/templates/gateway_component_template.py +75 -44
- solace_agent_mesh/templates/logging_config_template.ini +64 -0
- solace_agent_mesh/templates/plugin_agent_config_template.yaml +1 -1
- {solace_agent_mesh-1.0.1.dist-info → solace_agent_mesh-1.0.3.dist-info}/METADATA +56 -46
- {solace_agent_mesh-1.0.1.dist-info → solace_agent_mesh-1.0.3.dist-info}/RECORD +102 -96
- solace_agent_mesh/assets/docs/assets/js/1023fc19.015679ca.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1c6e87d2.23bccffb.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9eff14a2.1bf8f61c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/b7006a3a.40b10c9d.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/bb2ef573.207e6990.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.ecc3d195.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f897a61a.2c2e152c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.7ed3319f.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.d9520ae2.js +0 -1
- solace_agent_mesh/assets/docs/img/Solace_AI_Framework_README.png +0 -0
- solace_agent_mesh/assets/docs/lunr-index-1753813536522.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1753813536522.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-An0a5j5k.js +0 -663
- solace_agent_mesh/client/webui/frontend/static/assets/main-Bu5-4Bac.css +0 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-DNxCwAGB.js +0 -48
- /solace_agent_mesh/assets/docs/assets/js/{main.7ed3319f.js.LICENSE.txt → main.dc7db184.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.0.1.dist-info → solace_agent_mesh-1.0.3.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.0.1.dist-info → solace_agent_mesh-1.0.3.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.0.1.dist-info → solace_agent_mesh-1.0.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
window.__remixManifest={"entry":{"module":"/assets/entry.client-CEumGClk.js","imports":["/assets/index-DSo1AH_7.js","/assets/components-B7lKcHVY.js"],"css":[]},"routes":{"root":{"id":"root","path":"","hasAction":false,"hasLoader":false,"hasClientAction":false,"hasClientLoader":false,"hasErrorBoundary":false,"module":"/assets/root-C4XmHinv.js","imports":["/assets/index-DSo1AH_7.js","/assets/components-B7lKcHVY.js"],"css":["/assets/root-DxRwaWiE.css"]},"routes/_index":{"id":"routes/_index","parentId":"root","index":true,"hasAction":false,"hasLoader":false,"hasClientAction":false,"hasClientLoader":false,"hasErrorBoundary":false,"module":"/assets/_index-
|
|
1
|
+
window.__remixManifest={"entry":{"module":"/assets/entry.client-CEumGClk.js","imports":["/assets/index-DSo1AH_7.js","/assets/components-B7lKcHVY.js"],"css":[]},"routes":{"root":{"id":"root","path":"","hasAction":false,"hasLoader":false,"hasClientAction":false,"hasClientLoader":false,"hasErrorBoundary":false,"module":"/assets/root-C4XmHinv.js","imports":["/assets/index-DSo1AH_7.js","/assets/components-B7lKcHVY.js"],"css":["/assets/root-DxRwaWiE.css"]},"routes/_index":{"id":"routes/_index","parentId":"root","index":true,"hasAction":false,"hasLoader":false,"hasClientAction":false,"hasClientLoader":false,"hasErrorBoundary":false,"module":"/assets/_index-xSu2leR8.js","imports":["/assets/index-DSo1AH_7.js"],"css":[]}},"url":"/assets/manifest-950eb3be.js","version":"950eb3be"};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/assets/root-DxRwaWiE.css"/><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous"/><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"/></head><body><p>Loading...</p><link rel="modulepreload" href="/assets/manifest-
|
|
2
|
+
<html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/assets/root-DxRwaWiE.css"/><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous"/><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"/></head><body><p>Loading...</p><link rel="modulepreload" href="/assets/manifest-950eb3be.js"/><link rel="modulepreload" href="/assets/entry.client-CEumGClk.js"/><link rel="modulepreload" href="/assets/index-DSo1AH_7.js"/><link rel="modulepreload" href="/assets/components-B7lKcHVY.js"/><link rel="modulepreload" href="/assets/root-C4XmHinv.js"/><script>window.__remixContext = {"basename":"/","future":{"v3_fetcherPersist":false,"v3_relativeSplatPath":false,"v3_throwAbortReason":false,"v3_routeConfig":false,"v3_singleFetch":false,"v3_lazyRouteDiscovery":false,"unstable_optimizeDeps":false},"isSpaMode":true,"state":{"loaderData":{"root":null,"routes/_index":null},"actionData":null,"errors":null}};</script><script type="module" async="">import "/assets/manifest-950eb3be.js";
|
|
3
3
|
import * as route0 from "/assets/root-C4XmHinv.js";
|
|
4
4
|
|
|
5
5
|
window.__remixRouteModules = {"root":route0};
|
|
@@ -65,7 +65,9 @@ from solace_ai_connector.common.event import Event, EventType
|
|
|
65
65
|
from abc import abstractmethod
|
|
66
66
|
|
|
67
67
|
from ...common.middleware.registry import MiddlewareRegistry
|
|
68
|
-
from ...agent.utils.artifact_helpers import
|
|
68
|
+
from ...agent.utils.artifact_helpers import (
|
|
69
|
+
load_artifact_content_or_metadata,
|
|
70
|
+
)
|
|
69
71
|
|
|
70
72
|
info = {
|
|
71
73
|
"class_name": "BaseGatewayComponent",
|
|
@@ -157,6 +159,7 @@ class BaseGatewayComponent(ComponentBase):
|
|
|
157
159
|
self.shared_artifact_service: Optional[BaseArtifactService] = (
|
|
158
160
|
initialize_artifact_service(self)
|
|
159
161
|
)
|
|
162
|
+
|
|
160
163
|
self.task_context_manager: TaskContextManager = TaskContextManager()
|
|
161
164
|
self.internal_event_queue: queue.Queue = queue.Queue()
|
|
162
165
|
self.message_processor_thread: Optional[threading.Thread] = None
|
|
@@ -340,7 +343,17 @@ class BaseGatewayComponent(ComponentBase):
|
|
|
340
343
|
)
|
|
341
344
|
external_request_context["a2a_session_id"] = a2a_session_id
|
|
342
345
|
|
|
343
|
-
|
|
346
|
+
a2a_metadata = {}
|
|
347
|
+
invoked_artifacts = external_request_context.get("invoked_with_artifacts")
|
|
348
|
+
if invoked_artifacts:
|
|
349
|
+
a2a_metadata["invoked_with_artifacts"] = invoked_artifacts
|
|
350
|
+
log.debug(
|
|
351
|
+
"%s Found %d artifact identifiers in external context to pass to agent.",
|
|
352
|
+
log_id_prefix,
|
|
353
|
+
len(invoked_artifacts),
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
a2a_message = A2AMessage(role="user", parts=a2a_parts, metadata=a2a_metadata)
|
|
344
357
|
reply_topic_pattern = get_gateway_response_topic(
|
|
345
358
|
self.namespace, self.gateway_id, "{task_id}"
|
|
346
359
|
)
|
|
@@ -310,7 +310,9 @@ async def get_latest_artifact(
|
|
|
310
310
|
return StreamingResponse(
|
|
311
311
|
io.BytesIO(data_bytes),
|
|
312
312
|
media_type=mime_type,
|
|
313
|
-
headers={
|
|
313
|
+
headers={
|
|
314
|
+
"Content-Disposition": f"attachment; filename*=UTF-8''{filename_encoded}"
|
|
315
|
+
},
|
|
314
316
|
)
|
|
315
317
|
|
|
316
318
|
except FileNotFoundError:
|
|
@@ -483,7 +485,9 @@ async def get_specific_artifact_version(
|
|
|
483
485
|
return StreamingResponse(
|
|
484
486
|
io.BytesIO(data_bytes),
|
|
485
487
|
media_type=mime_type,
|
|
486
|
-
headers={
|
|
488
|
+
headers={
|
|
489
|
+
"Content-Disposition": f"attachment; filename*=UTF-8''{filename_encoded}"
|
|
490
|
+
},
|
|
487
491
|
)
|
|
488
492
|
|
|
489
493
|
except FileNotFoundError:
|
|
@@ -612,7 +616,9 @@ async def get_artifact_by_uri(
|
|
|
612
616
|
return StreamingResponse(
|
|
613
617
|
io.BytesIO(content_bytes),
|
|
614
618
|
media_type=mime_type,
|
|
615
|
-
headers={
|
|
619
|
+
headers={
|
|
620
|
+
"Content-Disposition": f"attachment; filename*=UTF-8''{filename_encoded}"
|
|
621
|
+
},
|
|
616
622
|
)
|
|
617
623
|
|
|
618
624
|
except (ValueError, IndexError) as e:
|
|
@@ -6,6 +6,8 @@ import asyncio
|
|
|
6
6
|
import threading
|
|
7
7
|
from typing import Dict, List, Any
|
|
8
8
|
import json
|
|
9
|
+
import datetime
|
|
10
|
+
import math
|
|
9
11
|
|
|
10
12
|
from solace_ai_connector.common.log import log
|
|
11
13
|
|
|
@@ -46,6 +48,23 @@ class SSEManager:
|
|
|
46
48
|
)
|
|
47
49
|
return self._locks[current_loop]
|
|
48
50
|
|
|
51
|
+
def _sanitize_json(self, obj):
|
|
52
|
+
if isinstance(obj, dict):
|
|
53
|
+
return {k: self._sanitize_json(v) for k, v in obj.items()}
|
|
54
|
+
elif isinstance(obj, list):
|
|
55
|
+
return [self._sanitize_json(v) for v in obj]
|
|
56
|
+
elif isinstance(obj, (float, int)):
|
|
57
|
+
if math.isnan(obj) or math.isinf(obj):
|
|
58
|
+
return None
|
|
59
|
+
return obj
|
|
60
|
+
elif isinstance(obj, (str, bool, type(None))):
|
|
61
|
+
return obj
|
|
62
|
+
elif isinstance(obj, (datetime.datetime, datetime.date)):
|
|
63
|
+
return obj.isoformat()
|
|
64
|
+
else:
|
|
65
|
+
return str(obj)
|
|
66
|
+
|
|
67
|
+
|
|
49
68
|
async def create_sse_connection(self, task_id: str) -> asyncio.Queue:
|
|
50
69
|
"""
|
|
51
70
|
Creates a new queue for an SSE connection subscribing to a task.
|
|
@@ -136,7 +155,10 @@ class SSEManager:
|
|
|
136
155
|
|
|
137
156
|
queues_to_remove = []
|
|
138
157
|
try:
|
|
139
|
-
serialized_data = json.dumps(
|
|
158
|
+
serialized_data = json.dumps(
|
|
159
|
+
self._sanitize_json(event_data),
|
|
160
|
+
allow_nan=False
|
|
161
|
+
)
|
|
140
162
|
except Exception as json_err:
|
|
141
163
|
log.error(
|
|
142
164
|
"%s Failed to JSON serialize event data for Task ID %s: %s",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Solace Agent Mesh Component class for the __GATEWAY_NAME_PASCAL_CASE__ Gateway.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import asyncio
|
|
5
|
+
import asyncio # If needed for async operations with external system
|
|
6
6
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
7
7
|
|
|
8
8
|
from solace_ai_connector.common.log import log
|
|
@@ -10,14 +10,15 @@ from solace_agent_mesh.gateway.base.component import BaseGatewayComponent
|
|
|
10
10
|
from solace_agent_mesh.common.types import (
|
|
11
11
|
Part as A2APart,
|
|
12
12
|
TextPart,
|
|
13
|
-
FilePart,
|
|
14
|
-
DataPart,
|
|
13
|
+
FilePart, # If handling files
|
|
14
|
+
DataPart, # If handling structured data
|
|
15
15
|
Task,
|
|
16
16
|
TaskStatusUpdateEvent,
|
|
17
17
|
TaskArtifactUpdateEvent,
|
|
18
18
|
JSONRPCError,
|
|
19
|
-
FileContent,
|
|
19
|
+
FileContent, # Added for FilePart example
|
|
20
20
|
)
|
|
21
|
+
|
|
21
22
|
# from solace_agent_mesh.core_a2a.service import CoreA2AService # If direct interaction needed
|
|
22
23
|
|
|
23
24
|
info = {
|
|
@@ -26,7 +27,7 @@ info = {
|
|
|
26
27
|
"Implements the A2A __GATEWAY_NAME_PASCAL_CASE__ Gateway, inheriting from BaseGatewayComponent. "
|
|
27
28
|
"Handles communication between the __GATEWAY_NAME_SNAKE_CASE__ system and the A2A agent ecosystem."
|
|
28
29
|
),
|
|
29
|
-
"config_parameters": [],
|
|
30
|
+
"config_parameters": [], # Defined by __GATEWAY_NAME_PASCAL_CASE__GatewayApp
|
|
30
31
|
"input_schema": {
|
|
31
32
|
"type": "object",
|
|
32
33
|
"description": "Not typically used directly by GDK; component reacts to external events or A2A control messages.",
|
|
@@ -37,6 +38,7 @@ info = {
|
|
|
37
38
|
},
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
|
|
40
42
|
class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
41
43
|
"""
|
|
42
44
|
Solace Agent Mesh Component implementing the A2A __GATEWAY_NAME_PASCAL_CASE__ Gateway.
|
|
@@ -72,8 +74,11 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
72
74
|
- For SDKs with callbacks: Register your callbacks here.
|
|
73
75
|
"""
|
|
74
76
|
log_id_prefix = f"{self.log_identifier}[StartListener]"
|
|
75
|
-
log.info(
|
|
76
|
-
|
|
77
|
+
log.info(
|
|
78
|
+
"%s Starting listener for __GATEWAY_NAME_SNAKE_CASE__ system...",
|
|
79
|
+
log_id_prefix,
|
|
80
|
+
)
|
|
81
|
+
|
|
77
82
|
# Example for a polling mechanism (adapt as needed):
|
|
78
83
|
# if self.async_loop and self.async_loop.is_running():
|
|
79
84
|
# self.async_loop.create_task(self._poll_external_system())
|
|
@@ -85,7 +90,9 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
85
90
|
# a blocking call to start, manage that appropriately (e.g., in a separate thread
|
|
86
91
|
# that communicates back to the async_loop via asyncio.run_coroutine_threadsafe).
|
|
87
92
|
|
|
88
|
-
log.info(
|
|
93
|
+
log.info(
|
|
94
|
+
"%s __GATEWAY_NAME_SNAKE_CASE__ listener startup initiated.", log_id_prefix
|
|
95
|
+
)
|
|
89
96
|
|
|
90
97
|
# async def _poll_external_system(self): # Example polling loop
|
|
91
98
|
# log_id_prefix = f"{self.log_identifier}[PollLoop]"
|
|
@@ -111,7 +118,6 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
111
118
|
# await asyncio.sleep(60) # Wait before retrying on error
|
|
112
119
|
# log.info("%s __GATEWAY_NAME_SNAKE_CASE__ polling loop stopped.", log_id_prefix)
|
|
113
120
|
|
|
114
|
-
|
|
115
121
|
def _stop_listener(self) -> None:
|
|
116
122
|
"""
|
|
117
123
|
GDK Hook: Stop listening for events/requests and clean up resources.
|
|
@@ -121,15 +127,18 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
121
127
|
- For SDKs: Unregister callbacks, close connections.
|
|
122
128
|
"""
|
|
123
129
|
log_id_prefix = f"{self.log_identifier}[StopListener]"
|
|
124
|
-
log.info(
|
|
125
|
-
|
|
130
|
+
log.info(
|
|
131
|
+
"%s Stopping listener for __GATEWAY_NAME_SNAKE_CASE__ system...",
|
|
132
|
+
log_id_prefix,
|
|
133
|
+
)
|
|
134
|
+
|
|
126
135
|
# self.stop_signal is already set by BaseGatewayComponent before calling this.
|
|
127
136
|
# Ensure your _start_listener logic (e.g., polling loop) respects self.stop_signal.
|
|
128
137
|
|
|
129
138
|
# Example: If you started a thread for a blocking SDK client:
|
|
130
139
|
# if hasattr(self, "sdk_thread") and self.sdk_thread.is_alive():
|
|
131
140
|
# # Signal SDK to shutdown if possible, then join thread
|
|
132
|
-
# # self.external_client.shutdown()
|
|
141
|
+
# # self.external_client.shutdown()
|
|
133
142
|
# self.sdk_thread.join(timeout=10)
|
|
134
143
|
|
|
135
144
|
# Example: If an asyncio task was created for polling:
|
|
@@ -137,11 +146,12 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
137
146
|
# self.polling_task.cancel()
|
|
138
147
|
# # Optionally await it if _stop_listener can be async, or manage in cleanup
|
|
139
148
|
|
|
140
|
-
log.info(
|
|
141
|
-
|
|
149
|
+
log.info(
|
|
150
|
+
"%s __GATEWAY_NAME_SNAKE_CASE__ listener shutdown initiated.", log_id_prefix
|
|
151
|
+
)
|
|
142
152
|
|
|
143
153
|
async def _authenticate_external_user(
|
|
144
|
-
self, external_event_data: Any
|
|
154
|
+
self, external_event_data: Any # Type hint with actual external event data type
|
|
145
155
|
) -> Optional[str]:
|
|
146
156
|
"""
|
|
147
157
|
GDK Hook: Authenticates the user or system from the external event data.
|
|
@@ -163,13 +173,14 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
163
173
|
# else:
|
|
164
174
|
# log.warning("%s Authentication failed: API key mismatch or missing.", log_id_prefix)
|
|
165
175
|
# return None
|
|
166
|
-
|
|
167
|
-
# If no authentication is needed for this gateway:
|
|
168
|
-
# return "anonymous___GATEWAY_NAME_SNAKE_CASE___user"
|
|
169
176
|
|
|
170
|
-
|
|
171
|
-
return "
|
|
177
|
+
# If no authentication is needed for this gateway:
|
|
178
|
+
# return "anonymous___GATEWAY_NAME_SNAKE_CASE___user"
|
|
172
179
|
|
|
180
|
+
log.warning(
|
|
181
|
+
"%s _authenticate_external_user not fully implemented.", log_id_prefix
|
|
182
|
+
)
|
|
183
|
+
return "placeholder_user_identity" # Replace with actual logic
|
|
173
184
|
|
|
174
185
|
async def _translate_external_input(
|
|
175
186
|
self, external_event_data: Any, authenticated_user_identity: str
|
|
@@ -178,7 +189,7 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
178
189
|
GDK Hook: Translates the incoming external event/request into an A2A task.
|
|
179
190
|
- `external_event_data`: The raw data from the external system.
|
|
180
191
|
- `authenticated_user_identity`: The identity returned by _authenticate_external_user.
|
|
181
|
-
|
|
192
|
+
|
|
182
193
|
Returns a tuple:
|
|
183
194
|
- `target_agent_name` (str | None): Name of the A2A agent to route the task to. None if translation fails.
|
|
184
195
|
- `a2a_parts` (List[A2APart]): List of A2A Parts (TextPart, FilePart, DataPart) for the task.
|
|
@@ -189,12 +200,14 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
189
200
|
# log.debug("%s Translating external event: %s", log_id_prefix, external_event_data)
|
|
190
201
|
|
|
191
202
|
a2a_parts: List[A2APart] = []
|
|
192
|
-
target_agent_name: Optional[str] =
|
|
203
|
+
target_agent_name: Optional[str] = (
|
|
204
|
+
None # Determine this based on event data or config
|
|
205
|
+
)
|
|
193
206
|
external_request_context: Dict[str, Any] = {
|
|
194
207
|
"user_id_for_a2a": authenticated_user_identity,
|
|
195
|
-
"app_name_for_artifacts": self.gateway_id,
|
|
208
|
+
"app_name_for_artifacts": self.gateway_id, # For artifact service context
|
|
196
209
|
"user_id_for_artifacts": authenticated_user_identity,
|
|
197
|
-
"a2a_session_id": f"__GATEWAY_NAME_SNAKE_CASE__-session-{self.generate_uuid()}",
|
|
210
|
+
"a2a_session_id": f"__GATEWAY_NAME_SNAKE_CASE__-session-{self.generate_uuid()}", # Example session ID
|
|
198
211
|
# Add any other relevant context from external_event_data needed for response handling
|
|
199
212
|
# "original_request_id": external_event_data.get("id"),
|
|
200
213
|
}
|
|
@@ -208,7 +221,7 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
208
221
|
# if rule.matches(external_event_data):
|
|
209
222
|
# target_agent_name = rule.get_agent_name()
|
|
210
223
|
# break
|
|
211
|
-
target_agent_name = "OrchestratorAgent"
|
|
224
|
+
target_agent_name = "OrchestratorAgent" # Placeholder
|
|
212
225
|
|
|
213
226
|
# 2. Construct A2A Parts:
|
|
214
227
|
# - Extract text:
|
|
@@ -222,7 +235,7 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
222
235
|
# # file_name = external_event_data.get("file_name", "attachment.dat")
|
|
223
236
|
# # mime_type = external_event_data.get("mime_type", "application/octet-stream")
|
|
224
237
|
# # artifact_uri = await self.save_to_artifact_service(
|
|
225
|
-
# # file_bytes, file_name, mime_type,
|
|
238
|
+
# # file_bytes, file_name, mime_type,
|
|
226
239
|
# # authenticated_user_identity, external_request_context["a2a_session_id"]
|
|
227
240
|
# # )
|
|
228
241
|
# # if artifact_uri:
|
|
@@ -233,21 +246,32 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
233
246
|
# # a2a_parts.append(DataPart(data=structured_data, metadata={"source": "__GATEWAY_NAME_SNAKE_CASE__"}))
|
|
234
247
|
|
|
235
248
|
# Example: Simple text passthrough
|
|
236
|
-
raw_text = str(
|
|
249
|
+
raw_text = str(
|
|
250
|
+
external_event_data.get(
|
|
251
|
+
"text_input_field", "Default text from __GATEWAY_NAME_SNAKE_CASE__"
|
|
252
|
+
)
|
|
253
|
+
)
|
|
237
254
|
a2a_parts.append(TextPart(text=raw_text))
|
|
238
|
-
|
|
255
|
+
|
|
239
256
|
if not target_agent_name:
|
|
240
257
|
log.error("%s Could not determine target_agent_name.", log_id_prefix)
|
|
241
|
-
return None, [], {}
|
|
258
|
+
return None, [], {} # Indicate translation failure
|
|
242
259
|
|
|
243
260
|
if not a2a_parts:
|
|
244
|
-
log.warning(
|
|
261
|
+
log.warning(
|
|
262
|
+
"%s No A2A parts created from external event. Task might be empty.",
|
|
263
|
+
log_id_prefix,
|
|
264
|
+
)
|
|
245
265
|
# Depending on requirements, you might want to return None, [], {} here too.
|
|
246
266
|
|
|
247
|
-
log.info(
|
|
267
|
+
log.info(
|
|
268
|
+
"%s Translation complete. Target: %s, Parts: %d",
|
|
269
|
+
log_id_prefix,
|
|
270
|
+
target_agent_name,
|
|
271
|
+
len(a2a_parts),
|
|
272
|
+
)
|
|
248
273
|
return target_agent_name, a2a_parts, external_request_context
|
|
249
274
|
|
|
250
|
-
|
|
251
275
|
async def _send_final_response_to_external(
|
|
252
276
|
self, external_request_context: Dict[str, Any], task_data: Task
|
|
253
277
|
) -> None:
|
|
@@ -274,14 +298,17 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
274
298
|
# break
|
|
275
299
|
# if task_data.status and task_data.status.state == TaskState.FAILED:
|
|
276
300
|
# response_text = f"Task failed: {response_text}"
|
|
277
|
-
|
|
301
|
+
|
|
278
302
|
# 3. Use information from external_request_context to send the response
|
|
279
303
|
# (e.g., reply-to address, original request ID).
|
|
280
304
|
# # original_request_id = external_request_context.get("original_request_id")
|
|
281
305
|
# # await self.external_client.send_reply(original_request_id, response_text)
|
|
282
306
|
|
|
283
|
-
log.warning(
|
|
284
|
-
|
|
307
|
+
log.warning(
|
|
308
|
+
"%s _send_final_response_to_external not fully implemented for task %s.",
|
|
309
|
+
log_id_prefix,
|
|
310
|
+
task_data.id,
|
|
311
|
+
)
|
|
285
312
|
|
|
286
313
|
async def _send_error_to_external(
|
|
287
314
|
self, external_request_context: Dict[str, Any], error_data: JSONRPCError
|
|
@@ -301,8 +328,11 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
301
328
|
# # original_request_id = external_request_context.get("original_request_id")
|
|
302
329
|
# # await self.external_client.send_error_reply(original_request_id, error_message_to_send)
|
|
303
330
|
|
|
304
|
-
log.warning(
|
|
305
|
-
|
|
331
|
+
log.warning(
|
|
332
|
+
"%s _send_error_to_external not fully implemented. Error: %s",
|
|
333
|
+
log_id_prefix,
|
|
334
|
+
error_data.message,
|
|
335
|
+
)
|
|
306
336
|
|
|
307
337
|
async def _send_update_to_external(
|
|
308
338
|
self,
|
|
@@ -318,7 +348,7 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
318
348
|
"""
|
|
319
349
|
log_id_prefix = f"{self.log_identifier}[SendUpdate]"
|
|
320
350
|
# task_id = event_data.id
|
|
321
|
-
# log.debug("%s Received A2A update for task %s. Type: %s. FinalChunk: %s",
|
|
351
|
+
# log.debug("%s Received A2A update for task %s. Type: %s. FinalChunk: %s",
|
|
322
352
|
# log_id_prefix, task_id, type(event_data).__name__, is_final_chunk_of_update)
|
|
323
353
|
|
|
324
354
|
# --- Implement Logic to Send Intermediate Update (if supported) ---
|
|
@@ -334,15 +364,16 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
334
364
|
# elif isinstance(event_data, TaskArtifactUpdateEvent):
|
|
335
365
|
# # Handle artifact updates (e.g., notify external system of new artifact URI)
|
|
336
366
|
# pass
|
|
337
|
-
|
|
367
|
+
|
|
338
368
|
# Default: Log that this gateway does not handle intermediate updates.
|
|
339
|
-
# log.debug("%s __GATEWAY_NAME_PASCAL_CASE__ Gateway does not process intermediate updates. Update for task %s ignored.",
|
|
369
|
+
# log.debug("%s __GATEWAY_NAME_PASCAL_CASE__ Gateway does not process intermediate updates. Update for task %s ignored.",
|
|
340
370
|
# log_id_prefix, task_id)
|
|
341
|
-
pass
|
|
371
|
+
pass # No-op by default
|
|
342
372
|
|
|
343
373
|
# --- Optional: Helper methods for your gateway ---
|
|
344
|
-
def generate_uuid(self) -> str:
|
|
374
|
+
def generate_uuid(self) -> str: # Made this a method of the class
|
|
345
375
|
import uuid
|
|
376
|
+
|
|
346
377
|
return str(uuid.uuid4())
|
|
347
378
|
|
|
348
379
|
# async def save_to_artifact_service(self, content_bytes: bytes, filename: str, mime_type: str, user_id: str, session_id: str) -> Optional[str]:
|
|
@@ -393,8 +424,8 @@ class __GATEWAY_NAME_PASCAL_CASE__GatewayComponent(BaseGatewayComponent):
|
|
|
393
424
|
# Example: Close any persistent connections not handled in _stop_listener
|
|
394
425
|
# if hasattr(self, "persistent_connection") and self.persistent_connection.is_open():
|
|
395
426
|
# self.persistent_connection.close()
|
|
396
|
-
super().cleanup()
|
|
427
|
+
super().cleanup() # Important to call super().cleanup()
|
|
397
428
|
log.info(
|
|
398
429
|
"%s __GATEWAY_NAME_PASCAL_CASE__ Gateway Component cleanup finished.",
|
|
399
430
|
self.log_identifier,
|
|
400
|
-
)
|
|
431
|
+
)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[loggers]
|
|
2
|
+
keys=root,LiteLLM,py_warnings,solace_ai_connector,uvicorn,uvicorn_error,uvicorn_access
|
|
3
|
+
|
|
4
|
+
[handlers]
|
|
5
|
+
keys=streamHandler,rotatingFileHandler
|
|
6
|
+
|
|
7
|
+
[formatters]
|
|
8
|
+
keys=simpleFormatter
|
|
9
|
+
|
|
10
|
+
[logger_root]
|
|
11
|
+
level=DEBUG
|
|
12
|
+
handlers=streamHandler,rotatingFileHandler
|
|
13
|
+
qualname=root
|
|
14
|
+
|
|
15
|
+
[handler_streamHandler]
|
|
16
|
+
class=StreamHandler
|
|
17
|
+
level=INFO
|
|
18
|
+
formatter=simpleFormatter
|
|
19
|
+
args=(sys.stdout,)
|
|
20
|
+
|
|
21
|
+
[logger_LiteLLM]
|
|
22
|
+
level=DEBUG
|
|
23
|
+
handlers=streamHandler,rotatingFileHandler
|
|
24
|
+
qualname=LiteLLM
|
|
25
|
+
propagate=0
|
|
26
|
+
|
|
27
|
+
[logger_py_warnings]
|
|
28
|
+
level=WARNING
|
|
29
|
+
handlers=streamHandler,rotatingFileHandler
|
|
30
|
+
qualname=py.warnings
|
|
31
|
+
propagate=0
|
|
32
|
+
|
|
33
|
+
[logger_solace_ai_connector]
|
|
34
|
+
level=DEBUG
|
|
35
|
+
handlers=streamHandler,rotatingFileHandler
|
|
36
|
+
qualname=solace_ai_connector
|
|
37
|
+
propagate=0
|
|
38
|
+
|
|
39
|
+
[logger_uvicorn]
|
|
40
|
+
level=DEBUG
|
|
41
|
+
handlers=streamHandler,rotatingFileHandler
|
|
42
|
+
qualname=uvicorn
|
|
43
|
+
propagate=0
|
|
44
|
+
|
|
45
|
+
[logger_uvicorn_error]
|
|
46
|
+
level=INFO
|
|
47
|
+
handlers=streamHandler,rotatingFileHandler
|
|
48
|
+
qualname=uvicorn.error
|
|
49
|
+
propagate=0
|
|
50
|
+
|
|
51
|
+
[logger_uvicorn_access]
|
|
52
|
+
level=INFO
|
|
53
|
+
handlers=streamHandler,rotatingFileHandler
|
|
54
|
+
qualname=uvicorn.access
|
|
55
|
+
propagate=0
|
|
56
|
+
|
|
57
|
+
[handler_rotatingFileHandler]
|
|
58
|
+
class=logging.handlers.RotatingFileHandler
|
|
59
|
+
level=DEBUG
|
|
60
|
+
formatter=simpleFormatter
|
|
61
|
+
args=('sam.log', 'a', 52428800, 10)
|
|
62
|
+
|
|
63
|
+
[formatter_simpleFormatter]
|
|
64
|
+
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
|
|
@@ -102,7 +102,7 @@ apps:
|
|
|
102
102
|
session_service: *default_session_service
|
|
103
103
|
artifact_service: *default_artifact_service
|
|
104
104
|
|
|
105
|
-
artifact_handling_mode: "
|
|
105
|
+
artifact_handling_mode: "reference"
|
|
106
106
|
enable_embed_resolution: true
|
|
107
107
|
enable_artifact_content_instruction: true
|
|
108
108
|
|