solace-agent-mesh 1.1.0__py3-none-any.whl → 1.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of solace-agent-mesh might be problematic. Click here for more details.
- solace_agent_mesh/agent/adk/runner.py +18 -12
- solace_agent_mesh/agent/adk/services.py +3 -3
- solace_agent_mesh/agent/adk/setup.py +141 -34
- solace_agent_mesh/agent/protocol/event_handlers.py +27 -21
- solace_agent_mesh/agent/sac/app.py +0 -1
- solace_agent_mesh/agent/sac/component.py +0 -1
- solace_agent_mesh/agent/tools/__init__.py +1 -0
- solace_agent_mesh/agent/tools/dynamic_tool.py +362 -0
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.d97b8e94.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/483cef9a.4e972867.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55f47984.cf3781c4.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/664b740a.1b744a32.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/75384d09.c193a8f0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9a09e75d.d6607c56.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/aba87c2f.071e2d94.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.4d8dda10.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c835a94d.146e3186.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.7334119c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.1c79039d.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.858117b7.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +29 -0
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +25 -0
- solace_agent_mesh/assets/docs/docs/documentation/{migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html → Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html } +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/{migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html → Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html } +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +19 -27
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +5 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +63 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
- solace_agent_mesh/assets/docs/lunr-index-1757531604543.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1757531604543.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/assets/docs/sitemap.xml +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
- solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
- solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
- solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
- solace_agent_mesh/cli/commands/run_cmd.py +5 -3
- solace_agent_mesh/cli/utils.py +68 -12
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-CAX9u8a7.js +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/client-DXU9SPI5.js +25 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C1k9E0aC.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-B0BEKoAR.js +390 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
- solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
- solace_agent_mesh/config_portal/backend/common.py +2 -2
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
- solace_agent_mesh/evaluation/message_organizer.py +35 -56
- solace_agent_mesh/evaluation/run.py +26 -5
- solace_agent_mesh/evaluation/subscriber.py +35 -10
- solace_agent_mesh/evaluation/summary_builder.py +27 -34
- solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
- solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
- solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
- solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
- solace_agent_mesh/gateway/http_sse/app.py +31 -1
- solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
- solace_agent_mesh/gateway/http_sse/component.py +224 -62
- solace_agent_mesh/gateway/http_sse/dependencies.py +148 -45
- solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
- solace_agent_mesh/gateway/http_sse/main.py +291 -87
- solace_agent_mesh/gateway/http_sse/routers/{agents.py → agent_cards.py} +7 -7
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +121 -54
- solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +83 -2
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
- solace_agent_mesh/gateway/http_sse/services/{agent_service.py → agent_card_service.py} +19 -19
- solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
- solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
- solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
- solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
- solace_agent_mesh/templates/shared_config.yaml +4 -5
- solace_agent_mesh/templates/webui.yaml +8 -10
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/METADATA +5 -3
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/RECORD +150 -104
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.8ccb9901.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/55f47984.c484bf96.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6e0db977.39a79ca9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/75384d09.bf78fbdb.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/aba87c2f.76376d7c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.a75ecc0d.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1756992446316.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1756992446316.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
- solace_agent_mesh/client/webui/frontend/static/assets/main-C0jZjYa8.js +0 -699
- solace_agent_mesh/client/webui/frontend/static/assets/main-CCeG324-.css +0 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -85
- solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
- /solace_agent_mesh/assets/docs/assets/js/{main.a75ecc0d.js.LICENSE.txt → main.1c79039d.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,77 +2,81 @@
|
|
|
2
2
|
FastAPI router for managing session-specific artifacts via REST endpoints.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
Dict,
|
|
8
|
-
Optional,
|
|
9
|
-
Union,
|
|
10
|
-
Any,
|
|
11
|
-
TYPE_CHECKING,
|
|
12
|
-
)
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
13
7
|
|
|
14
8
|
from fastapi import (
|
|
15
9
|
APIRouter,
|
|
16
10
|
Depends,
|
|
17
|
-
HTTPException,
|
|
18
|
-
UploadFile,
|
|
19
11
|
File,
|
|
12
|
+
Form,
|
|
13
|
+
HTTPException,
|
|
20
14
|
Path,
|
|
15
|
+
UploadFile,
|
|
21
16
|
status,
|
|
22
|
-
Form,
|
|
23
17
|
)
|
|
24
|
-
from fastapi.responses import
|
|
25
|
-
|
|
18
|
+
from fastapi.responses import Response, StreamingResponse
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
from google.adk.artifacts import BaseArtifactService
|
|
22
|
+
except ImportError:
|
|
23
|
+
|
|
24
|
+
class BaseArtifactService:
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
26
28
|
import io
|
|
27
29
|
import json
|
|
28
30
|
from datetime import datetime, timezone
|
|
29
|
-
from urllib.parse import
|
|
30
|
-
|
|
31
|
-
from ..dependencies import (
|
|
32
|
-
get_shared_artifact_service,
|
|
33
|
-
get_sac_component,
|
|
34
|
-
ensure_session_id,
|
|
35
|
-
get_user_id,
|
|
36
|
-
get_config_resolver,
|
|
37
|
-
get_user_config,
|
|
38
|
-
)
|
|
31
|
+
from urllib.parse import parse_qs, quote, urlparse
|
|
39
32
|
|
|
40
33
|
from solace_ai_connector.common.log import log
|
|
41
34
|
|
|
42
|
-
from ....common.middleware import ConfigResolver
|
|
43
35
|
from ....common.a2a.types import ArtifactInfo
|
|
44
|
-
from ....common.
|
|
36
|
+
from ....common.middleware import ConfigResolver
|
|
45
37
|
from ....common.utils.embeds import (
|
|
46
|
-
resolve_embeds_recursively_in_string,
|
|
47
|
-
evaluate_embed,
|
|
48
38
|
LATE_EMBED_TYPES,
|
|
39
|
+
evaluate_embed,
|
|
40
|
+
resolve_embeds_recursively_in_string,
|
|
41
|
+
)
|
|
42
|
+
from ....common.utils.mime_helpers import is_text_based_mime_type
|
|
43
|
+
from ..dependencies import (
|
|
44
|
+
get_config_resolver,
|
|
45
|
+
get_sac_component,
|
|
46
|
+
get_session_validator,
|
|
47
|
+
get_shared_artifact_service,
|
|
48
|
+
get_user_config,
|
|
49
|
+
get_user_id,
|
|
49
50
|
)
|
|
50
|
-
|
|
51
51
|
|
|
52
52
|
if TYPE_CHECKING:
|
|
53
53
|
from ....gateway.http_sse.component import WebUIBackendComponent
|
|
54
|
+
|
|
54
55
|
from ....agent.utils.artifact_helpers import (
|
|
55
|
-
get_artifact_info_list,
|
|
56
|
-
save_artifact_with_metadata,
|
|
57
|
-
load_artifact_content_or_metadata,
|
|
58
56
|
DEFAULT_SCHEMA_MAX_KEYS,
|
|
59
57
|
format_artifact_uri,
|
|
58
|
+
get_artifact_info_list,
|
|
59
|
+
load_artifact_content_or_metadata,
|
|
60
|
+
save_artifact_with_metadata,
|
|
60
61
|
)
|
|
61
62
|
|
|
62
63
|
router = APIRouter()
|
|
63
64
|
|
|
64
65
|
|
|
65
66
|
@router.get(
|
|
66
|
-
"/{filename}/versions",
|
|
67
|
-
response_model=
|
|
67
|
+
"/{session_id}/{filename}/versions",
|
|
68
|
+
response_model=list[int],
|
|
68
69
|
summary="List Artifact Versions",
|
|
69
70
|
description="Retrieves a list of available version numbers for a specific artifact.",
|
|
70
71
|
)
|
|
71
72
|
async def list_artifact_versions(
|
|
73
|
+
session_id: str = Path(
|
|
74
|
+
..., title="Session ID", description="The session ID to get artifacts from"
|
|
75
|
+
),
|
|
72
76
|
filename: str = Path(..., title="Filename", description="The name of the artifact"),
|
|
73
77
|
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
74
78
|
user_id: str = Depends(get_user_id),
|
|
75
|
-
|
|
79
|
+
validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
|
|
76
80
|
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
77
81
|
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
78
82
|
user_config: dict = Depends(get_user_config),
|
|
@@ -91,6 +95,14 @@ async def list_artifact_versions(
|
|
|
91
95
|
log_prefix = f"[ArtifactRouter:ListVersions:{filename}] User={user_id}, Session={session_id} -"
|
|
92
96
|
log.info("%s Request received.", log_prefix)
|
|
93
97
|
|
|
98
|
+
# Validate session exists and belongs to user
|
|
99
|
+
if not validate_session(session_id, user_id):
|
|
100
|
+
log.warning("%s Session validation failed or access denied.", log_prefix)
|
|
101
|
+
raise HTTPException(
|
|
102
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
103
|
+
detail="Session not found or access denied.",
|
|
104
|
+
)
|
|
105
|
+
|
|
94
106
|
if artifact_service is None:
|
|
95
107
|
log.error("%s Artifact service is not configured or available.", log_prefix)
|
|
96
108
|
raise HTTPException(
|
|
@@ -134,23 +146,32 @@ async def list_artifact_versions(
|
|
|
134
146
|
)
|
|
135
147
|
|
|
136
148
|
|
|
149
|
+
@router.get(
|
|
150
|
+
"/{session_id}",
|
|
151
|
+
response_model=list[ArtifactInfo],
|
|
152
|
+
summary="List Artifact Information",
|
|
153
|
+
description="Retrieves detailed information for artifacts available for the specified user session.",
|
|
154
|
+
)
|
|
137
155
|
@router.get(
|
|
138
156
|
"/",
|
|
139
|
-
response_model=
|
|
157
|
+
response_model=list[ArtifactInfo],
|
|
140
158
|
summary="List Artifact Information",
|
|
141
159
|
description="Retrieves detailed information for artifacts available for the current user session.",
|
|
142
160
|
)
|
|
143
161
|
async def list_artifacts(
|
|
162
|
+
session_id: str = Path(
|
|
163
|
+
..., title="Session ID", description="The session ID to list artifacts for"
|
|
164
|
+
),
|
|
144
165
|
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
145
166
|
user_id: str = Depends(get_user_id),
|
|
146
|
-
|
|
167
|
+
validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
|
|
147
168
|
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
148
169
|
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
149
170
|
user_config: dict = Depends(get_user_config),
|
|
150
171
|
):
|
|
151
172
|
"""
|
|
152
173
|
Lists detailed information (filename, size, type, modified date, uri)
|
|
153
|
-
for all artifacts associated with the
|
|
174
|
+
for all artifacts associated with the specified user and session ID
|
|
154
175
|
by calling the artifact helper function.
|
|
155
176
|
"""
|
|
156
177
|
if not config_resolver.is_feature_enabled(
|
|
@@ -161,6 +182,19 @@ async def list_artifacts(
|
|
|
161
182
|
log_prefix = f"[ArtifactRouter:ListInfo] User={user_id}, Session={session_id} -"
|
|
162
183
|
log.info("%s Request received.", log_prefix)
|
|
163
184
|
|
|
185
|
+
# Validate session exists and belongs to user
|
|
186
|
+
if not validate_session(session_id, user_id):
|
|
187
|
+
log.warning(
|
|
188
|
+
"%s Session validation failed for session_id=%s, user_id=%s",
|
|
189
|
+
log_prefix,
|
|
190
|
+
session_id,
|
|
191
|
+
user_id,
|
|
192
|
+
)
|
|
193
|
+
raise HTTPException(
|
|
194
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
195
|
+
detail="Session not found or access denied.",
|
|
196
|
+
)
|
|
197
|
+
|
|
164
198
|
if artifact_service is None:
|
|
165
199
|
log.error("%s Artifact service is not configured or available.", log_prefix)
|
|
166
200
|
raise HTTPException(
|
|
@@ -194,15 +228,18 @@ async def list_artifacts(
|
|
|
194
228
|
|
|
195
229
|
|
|
196
230
|
@router.get(
|
|
197
|
-
"/{filename}",
|
|
231
|
+
"/{session_id}/{filename}",
|
|
198
232
|
summary="Get Latest Artifact Content",
|
|
199
233
|
description="Retrieves the content of the latest version of a specific artifact.",
|
|
200
234
|
)
|
|
201
235
|
async def get_latest_artifact(
|
|
236
|
+
session_id: str = Path(
|
|
237
|
+
..., title="Session ID", description="The session ID to get artifacts from"
|
|
238
|
+
),
|
|
202
239
|
filename: str = Path(..., title="Filename", description="The name of the artifact"),
|
|
203
240
|
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
204
241
|
user_id: str = Depends(get_user_id),
|
|
205
|
-
|
|
242
|
+
validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
|
|
206
243
|
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
207
244
|
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
208
245
|
user_config: dict = Depends(get_user_config),
|
|
@@ -331,20 +368,23 @@ async def get_latest_artifact(
|
|
|
331
368
|
|
|
332
369
|
|
|
333
370
|
@router.get(
|
|
334
|
-
"/{filename}/versions/{version}",
|
|
371
|
+
"/{session_id}/{filename}/versions/{version}",
|
|
335
372
|
summary="Get Specific Artifact Version Content",
|
|
336
373
|
description="Retrieves the content of a specific version of an artifact.",
|
|
337
374
|
)
|
|
338
375
|
async def get_specific_artifact_version(
|
|
376
|
+
session_id: str = Path(
|
|
377
|
+
..., title="Session ID", description="The session ID to get artifacts from"
|
|
378
|
+
),
|
|
339
379
|
filename: str = Path(..., title="Filename", description="The name of the artifact"),
|
|
340
|
-
version:
|
|
380
|
+
version: int | str = Path(
|
|
341
381
|
...,
|
|
342
382
|
title="Version",
|
|
343
383
|
description="The specific version number to retrieve, or 'latest'",
|
|
344
384
|
),
|
|
345
385
|
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
346
386
|
user_id: str = Depends(get_user_id),
|
|
347
|
-
|
|
387
|
+
validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
|
|
348
388
|
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
349
389
|
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
350
390
|
user_config: dict = Depends(get_user_config),
|
|
@@ -362,6 +402,14 @@ async def get_specific_artifact_version(
|
|
|
362
402
|
log_prefix = f"[ArtifactRouter:GetVersion:{filename} v{version}] User={user_id}, Session={session_id} -"
|
|
363
403
|
log.info("%s Request received.", log_prefix)
|
|
364
404
|
|
|
405
|
+
# Validate session exists and belongs to user
|
|
406
|
+
if not validate_session(session_id, user_id):
|
|
407
|
+
log.warning("%s Session validation failed or access denied.", log_prefix)
|
|
408
|
+
raise HTTPException(
|
|
409
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
410
|
+
detail="Session not found or access denied.",
|
|
411
|
+
)
|
|
412
|
+
|
|
365
413
|
if artifact_service is None:
|
|
366
414
|
log.error("%s Artifact service is not configured or available.", log_prefix)
|
|
367
415
|
raise HTTPException(
|
|
@@ -381,7 +429,7 @@ async def get_specific_artifact_version(
|
|
|
381
429
|
version=version,
|
|
382
430
|
load_metadata_only=False,
|
|
383
431
|
return_raw_bytes=True,
|
|
384
|
-
log_identifier_prefix=
|
|
432
|
+
log_identifier_prefix="[ArtifactRouter:GetVersion]",
|
|
385
433
|
)
|
|
386
434
|
|
|
387
435
|
if load_result.get("status") != "success":
|
|
@@ -404,7 +452,6 @@ async def get_specific_artifact_version(
|
|
|
404
452
|
mime_type = load_result.get("mime_type", "application/octet-stream")
|
|
405
453
|
resolved_version_from_helper = load_result.get("version")
|
|
406
454
|
if data_bytes is None:
|
|
407
|
-
|
|
408
455
|
log.error(
|
|
409
456
|
"%s Helper (with return_raw_bytes=True) returned success but no raw_bytes for '%s' v%s (resolved to %s).",
|
|
410
457
|
log_prefix,
|
|
@@ -529,7 +576,7 @@ async def get_artifact_by_uri(
|
|
|
529
576
|
This allows fetching artifacts from any context, not just the current user's session,
|
|
530
577
|
after performing an authorization check.
|
|
531
578
|
"""
|
|
532
|
-
log_id_prefix =
|
|
579
|
+
log_id_prefix = "[ArtifactRouter:by-uri]"
|
|
533
580
|
log.info(
|
|
534
581
|
"%s Received request for URI: %s from user: %s",
|
|
535
582
|
log_id_prefix,
|
|
@@ -632,23 +679,26 @@ async def get_artifact_by_uri(
|
|
|
632
679
|
|
|
633
680
|
|
|
634
681
|
@router.post(
|
|
635
|
-
"/{filename}",
|
|
682
|
+
"/{session_id}/{filename}",
|
|
636
683
|
status_code=status.HTTP_201_CREATED,
|
|
637
|
-
response_model=
|
|
684
|
+
response_model=dict[str, Any],
|
|
638
685
|
summary="Upload Artifact (Create/Update Version with Metadata)",
|
|
639
686
|
description="Uploads file content and optional metadata to create or update an artifact version.",
|
|
640
687
|
)
|
|
641
688
|
async def upload_artifact(
|
|
689
|
+
session_id: str = Path(
|
|
690
|
+
..., title="Session ID", description="The session ID to upload artifacts to"
|
|
691
|
+
),
|
|
642
692
|
filename: str = Path(
|
|
643
693
|
..., title="Filename", description="The name of the artifact to create/update"
|
|
644
694
|
),
|
|
645
695
|
upload_file: UploadFile = File(..., description="The file content to upload"),
|
|
646
|
-
metadata_json:
|
|
696
|
+
metadata_json: str | None = Form(
|
|
647
697
|
None, description="JSON string of artifact metadata (e.g., description, source)"
|
|
648
698
|
),
|
|
649
699
|
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
650
700
|
user_id: str = Depends(get_user_id),
|
|
651
|
-
|
|
701
|
+
validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
|
|
652
702
|
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
653
703
|
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
654
704
|
user_config: dict = Depends(get_user_config),
|
|
@@ -665,12 +715,20 @@ async def upload_artifact(
|
|
|
665
715
|
f"[ArtifactRouter:Post:{filename}] User={user_id}, Session={session_id} -"
|
|
666
716
|
)
|
|
667
717
|
log.info(
|
|
668
|
-
"%s Request received. Upload filename: '%s', content type: %s",
|
|
718
|
+
"%s Request received. Upload filename: '%s', content type: %s, Metadata provided: %s",
|
|
669
719
|
log_prefix,
|
|
670
720
|
upload_file.filename,
|
|
671
721
|
upload_file.content_type,
|
|
672
722
|
)
|
|
673
723
|
|
|
724
|
+
# Validate session exists and belongs to user
|
|
725
|
+
if not validate_session(session_id, user_id):
|
|
726
|
+
log.warning("%s Session validation failed or access denied.", log_prefix)
|
|
727
|
+
raise HTTPException(
|
|
728
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
729
|
+
detail="Session not found or access denied.",
|
|
730
|
+
)
|
|
731
|
+
|
|
674
732
|
if artifact_service is None:
|
|
675
733
|
log.error("%s Artifact service is not configured or available.", log_prefix)
|
|
676
734
|
raise HTTPException(
|
|
@@ -777,24 +835,26 @@ async def upload_artifact(
|
|
|
777
835
|
detail=f"Failed to save artifact: {str(e)}",
|
|
778
836
|
)
|
|
779
837
|
finally:
|
|
780
|
-
|
|
781
838
|
await upload_file.close()
|
|
782
839
|
log.debug("%s Upload file closed.", log_prefix)
|
|
783
840
|
|
|
784
841
|
|
|
785
842
|
@router.delete(
|
|
786
|
-
"/{filename}",
|
|
843
|
+
"/{session_id}/{filename}",
|
|
787
844
|
status_code=status.HTTP_204_NO_CONTENT,
|
|
788
845
|
summary="Delete Artifact",
|
|
789
846
|
description="Deletes an artifact and all its versions.",
|
|
790
847
|
)
|
|
791
848
|
async def delete_artifact(
|
|
849
|
+
session_id: str = Path(
|
|
850
|
+
..., title="Session ID", description="The session ID to delete artifacts from"
|
|
851
|
+
),
|
|
792
852
|
filename: str = Path(
|
|
793
853
|
..., title="Filename", description="The name of the artifact to delete"
|
|
794
854
|
),
|
|
795
855
|
artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
|
|
796
856
|
user_id: str = Depends(get_user_id),
|
|
797
|
-
|
|
857
|
+
validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
|
|
798
858
|
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
799
859
|
config_resolver: ConfigResolver = Depends(get_config_resolver),
|
|
800
860
|
user_config: dict = Depends(get_user_config),
|
|
@@ -812,6 +872,14 @@ async def delete_artifact(
|
|
|
812
872
|
)
|
|
813
873
|
log.info("%s Request received.", log_prefix)
|
|
814
874
|
|
|
875
|
+
# Validate session exists and belongs to user
|
|
876
|
+
if not validate_session(session_id, user_id):
|
|
877
|
+
log.warning("%s Session validation failed or access denied.", log_prefix)
|
|
878
|
+
raise HTTPException(
|
|
879
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
880
|
+
detail="Session not found or access denied.",
|
|
881
|
+
)
|
|
882
|
+
|
|
815
883
|
if artifact_service is None:
|
|
816
884
|
log.error("%s Artifact service is not configured or available.", log_prefix)
|
|
817
885
|
raise HTTPException(
|
|
@@ -833,7 +901,6 @@ async def delete_artifact(
|
|
|
833
901
|
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
|
834
902
|
|
|
835
903
|
except Exception as e:
|
|
836
|
-
|
|
837
904
|
log.exception("%s Error deleting artifact: %s", log_prefix, e)
|
|
838
905
|
raise HTTPException(
|
|
839
906
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
@@ -7,7 +7,7 @@ from typing import Dict, Any
|
|
|
7
7
|
|
|
8
8
|
from solace_ai_connector.common.log import log
|
|
9
9
|
|
|
10
|
-
from ....gateway.http_sse.dependencies import get_sac_component
|
|
10
|
+
from ....gateway.http_sse.dependencies import get_sac_component, get_api_config
|
|
11
11
|
from typing import TYPE_CHECKING
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
@@ -19,6 +19,7 @@ router = APIRouter()
|
|
|
19
19
|
@router.get("/config", response_model=Dict[str, Any])
|
|
20
20
|
async def get_app_config(
|
|
21
21
|
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
22
|
+
api_config: Dict[str, Any] = Depends(get_api_config),
|
|
22
23
|
):
|
|
23
24
|
"""
|
|
24
25
|
Provides configuration settings needed by the frontend application.
|
|
@@ -42,6 +43,7 @@ async def get_app_config(
|
|
|
42
43
|
"frontend_collect_feedback", False
|
|
43
44
|
),
|
|
44
45
|
"frontend_bot_name": component.get_config("frontend_bot_name", "A2A Agent"),
|
|
46
|
+
"persistence_enabled": api_config.get("persistence_enabled", False),
|
|
45
47
|
}
|
|
46
48
|
log.info("%sReturning frontend configuration.", log_prefix)
|
|
47
49
|
return config_data
|
|
@@ -76,19 +76,99 @@ async def _submit_task(
|
|
|
76
76
|
)
|
|
77
77
|
|
|
78
78
|
client_id = session_manager.get_a2a_client_id(request)
|
|
79
|
-
|
|
79
|
+
|
|
80
|
+
# Use session ID from frontend request (contextId) instead of cookie-based session
|
|
81
|
+
# Handle various falsy values: None, empty string, whitespace-only string
|
|
82
|
+
log.info("%s[DEBUG] payload.params.message: %s", log_prefix, payload.params.message)
|
|
83
|
+
log.info("%s[DEBUG] hasattr context_id: %s", log_prefix, hasattr(payload.params.message, 'context_id'))
|
|
84
|
+
if hasattr(payload.params.message, 'context_id'):
|
|
85
|
+
log.info("%s[DEBUG] context_id value: %s", log_prefix, payload.params.message.context_id)
|
|
86
|
+
|
|
87
|
+
frontend_session_id = None
|
|
88
|
+
if hasattr(payload.params.message, 'context_id') and payload.params.message.context_id:
|
|
89
|
+
context_id = payload.params.message.context_id
|
|
90
|
+
if isinstance(context_id, str) and context_id.strip():
|
|
91
|
+
frontend_session_id = context_id.strip()
|
|
92
|
+
log.info("%s[DEBUG] Extracted frontend_session_id: %s", log_prefix, frontend_session_id)
|
|
93
|
+
|
|
94
|
+
if frontend_session_id:
|
|
95
|
+
session_id = frontend_session_id
|
|
96
|
+
log.info("%sUsing session ID from frontend request: %s", log_prefix, session_id)
|
|
97
|
+
else:
|
|
98
|
+
# Create new session when frontend doesn't provide one (None, empty, or whitespace-only)
|
|
99
|
+
session_id = session_manager.create_new_session_id(request)
|
|
100
|
+
log.info("%sNo valid session ID from frontend, created new session: %s", log_prefix, session_id)
|
|
80
101
|
|
|
81
102
|
log.info(
|
|
82
103
|
"%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
|
|
83
104
|
)
|
|
84
105
|
|
|
106
|
+
# Store message in persistence layer if available
|
|
107
|
+
user_id = user_identity.get("id")
|
|
108
|
+
if is_streaming and hasattr(component, "persistence_service") and component.persistence_service:
|
|
109
|
+
try:
|
|
110
|
+
from ....gateway.http_sse.dependencies import get_session_service
|
|
111
|
+
from ....gateway.http_sse.shared.enums import SenderType
|
|
112
|
+
|
|
113
|
+
session_service = get_session_service(component)
|
|
114
|
+
|
|
115
|
+
# First ensure session exists in database - create it with the SessionManager's ID
|
|
116
|
+
# Handle race condition where multiple requests might try to create the same session
|
|
117
|
+
existing_session = session_service.get_session(session_id=session_id, user_id=user_id)
|
|
118
|
+
if not existing_session:
|
|
119
|
+
log.info("%sCreating new session in database: %s", log_prefix, session_id)
|
|
120
|
+
try:
|
|
121
|
+
session_service.create_session(
|
|
122
|
+
user_id=user_id,
|
|
123
|
+
agent_id=agent_name,
|
|
124
|
+
name=None, # Will be auto-generated if needed
|
|
125
|
+
session_id=session_id # Use the SessionManager's session ID
|
|
126
|
+
)
|
|
127
|
+
except Exception as create_error:
|
|
128
|
+
# Another request may have created the session concurrently
|
|
129
|
+
log.warning("%sSession creation failed, checking if session exists: %s", log_prefix, create_error)
|
|
130
|
+
existing_session = session_service.get_session(session_id=session_id, user_id=user_id)
|
|
131
|
+
if not existing_session:
|
|
132
|
+
# If session still doesn't exist, re-raise the original error
|
|
133
|
+
raise create_error
|
|
134
|
+
log.info("%sSession was created by another request: %s", log_prefix, session_id)
|
|
135
|
+
|
|
136
|
+
# Extract text content from the message for storage
|
|
137
|
+
message_text = ""
|
|
138
|
+
if payload.params and payload.params.message:
|
|
139
|
+
parts = a2a.get_parts_from_message(payload.params.message)
|
|
140
|
+
for part in parts:
|
|
141
|
+
if hasattr(part, 'text'):
|
|
142
|
+
message_text = part.text
|
|
143
|
+
break
|
|
144
|
+
|
|
145
|
+
# Now store the message in the existing session
|
|
146
|
+
message_domain = session_service.add_message_to_session(
|
|
147
|
+
session_id=session_id,
|
|
148
|
+
user_id=user_id,
|
|
149
|
+
message=message_text or "Task submitted",
|
|
150
|
+
sender_type=SenderType.USER,
|
|
151
|
+
sender_name=user_id or "user",
|
|
152
|
+
agent_id=agent_name,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
if message_domain:
|
|
156
|
+
log.info("%sMessage stored in session %s", log_prefix, session_id)
|
|
157
|
+
else:
|
|
158
|
+
log.warning("%sFailed to store message in session %s", log_prefix, session_id)
|
|
159
|
+
except Exception as e:
|
|
160
|
+
log.error("%sFailed to store message in session service: %s", log_prefix, e)
|
|
161
|
+
# Don't fail the request, just log the error
|
|
162
|
+
else:
|
|
163
|
+
log.debug("%sNo persistence available or non-streaming - skipping message storage", log_prefix)
|
|
164
|
+
|
|
85
165
|
# Use the helper to get the unwrapped parts from the incoming message.
|
|
86
166
|
a2a_parts = a2a.get_parts_from_message(payload.params.message)
|
|
87
167
|
|
|
88
168
|
external_req_ctx = {
|
|
89
169
|
"app_name_for_artifacts": component.gateway_id,
|
|
90
170
|
"user_id_for_artifacts": client_id,
|
|
91
|
-
"a2a_session_id": session_id,
|
|
171
|
+
"a2a_session_id": session_id, # This may have been updated by persistence layer
|
|
92
172
|
"user_id_for_a2a": client_id,
|
|
93
173
|
"target_agent_name": agent_name,
|
|
94
174
|
}
|
|
@@ -110,6 +190,7 @@ async def _submit_task(
|
|
|
110
190
|
)
|
|
111
191
|
|
|
112
192
|
if is_streaming:
|
|
193
|
+
# The task_object already contains the contextId from create_initial_task
|
|
113
194
|
return a2a.create_send_streaming_message_success_response(
|
|
114
195
|
result=task_object, request_id=payload.id
|
|
115
196
|
)
|
|
@@ -212,19 +212,19 @@ def _resolve_user_identity_for_authorization(
|
|
|
212
212
|
return user_identity
|
|
213
213
|
|
|
214
214
|
if not user_identity:
|
|
215
|
-
|
|
216
|
-
if
|
|
217
|
-
user_identity =
|
|
215
|
+
use_authorization = component.get_config("frontend_use_authorization", False)
|
|
216
|
+
if not use_authorization:
|
|
217
|
+
user_identity = "sam_dev_user"
|
|
218
218
|
log.info(
|
|
219
|
-
"%s No user_identity provided, using
|
|
219
|
+
"%s No user_identity provided and auth is disabled, using sam_dev_user for visualization",
|
|
220
220
|
log_id_prefix,
|
|
221
|
-
user_identity,
|
|
222
221
|
)
|
|
223
222
|
else:
|
|
224
|
-
log.
|
|
225
|
-
"%s No user_identity
|
|
223
|
+
log.error(
|
|
224
|
+
"%s No user_identity provided but authorization is enabled. This should not happen.",
|
|
226
225
|
log_id_prefix,
|
|
227
226
|
)
|
|
227
|
+
raise ValueError("No user identity available when authorization is required")
|
|
228
228
|
|
|
229
229
|
return user_identity
|
|
230
230
|
|
|
@@ -11,14 +11,14 @@ from ....common.agent_registry import AgentRegistry
|
|
|
11
11
|
from a2a.types import AgentCard
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class
|
|
14
|
+
class AgentCardService:
|
|
15
15
|
"""
|
|
16
|
-
Provides methods for accessing information about discovered A2A agents.
|
|
16
|
+
Provides methods for accessing information about discovered A2A agents' cards.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
def __init__(self, agent_registry: AgentRegistry):
|
|
20
20
|
"""
|
|
21
|
-
Initializes the
|
|
21
|
+
Initializes the AgentCardService.
|
|
22
22
|
|
|
23
23
|
Args:
|
|
24
24
|
agent_registry: An instance of the shared AgentRegistry.
|
|
@@ -26,33 +26,33 @@ class AgentService:
|
|
|
26
26
|
if not isinstance(agent_registry, AgentRegistry):
|
|
27
27
|
raise TypeError("agent_registry must be an instance of AgentRegistry")
|
|
28
28
|
self._agent_registry = agent_registry
|
|
29
|
-
log.info("[
|
|
29
|
+
log.info("[AgentCardService] Initialized.")
|
|
30
30
|
|
|
31
|
-
def
|
|
31
|
+
def get_all_agent_cards(self) -> List[AgentCard]:
|
|
32
32
|
"""
|
|
33
33
|
Retrieves all currently discovered and registered agent cards.
|
|
34
34
|
|
|
35
35
|
Returns:
|
|
36
36
|
A list of AgentCard objects.
|
|
37
37
|
"""
|
|
38
|
-
log_prefix = "[
|
|
39
|
-
log.info("%sRetrieving all
|
|
38
|
+
log_prefix = "[AgentCardService.get_all_agent_cards] "
|
|
39
|
+
log.info("%sRetrieving all agent cards.", log_prefix)
|
|
40
40
|
agent_names = self._agent_registry.get_agent_names()
|
|
41
|
-
|
|
41
|
+
agent_cards = []
|
|
42
42
|
for name in agent_names:
|
|
43
|
-
|
|
44
|
-
if
|
|
45
|
-
|
|
43
|
+
agent_card = self._agent_registry.get_agent(name)
|
|
44
|
+
if agent_card:
|
|
45
|
+
agent_cards.append(agent_card)
|
|
46
46
|
else:
|
|
47
47
|
log.warning(
|
|
48
48
|
"%sAgent name '%s' found in list but not retrievable from registry.",
|
|
49
49
|
log_prefix,
|
|
50
50
|
name,
|
|
51
51
|
)
|
|
52
|
-
log.info("%sRetrieved %d agent cards.", log_prefix, len(
|
|
53
|
-
return
|
|
52
|
+
log.info("%sRetrieved %d agent cards.", log_prefix, len(agent_cards))
|
|
53
|
+
return agent_cards
|
|
54
54
|
|
|
55
|
-
def
|
|
55
|
+
def get_agent_card_by_name(self, agent_name: str) -> Optional[AgentCard]:
|
|
56
56
|
"""
|
|
57
57
|
Retrieves a specific agent card by its name.
|
|
58
58
|
|
|
@@ -62,8 +62,8 @@ class AgentService:
|
|
|
62
62
|
Returns:
|
|
63
63
|
The AgentCard object if found, otherwise None.
|
|
64
64
|
"""
|
|
65
|
-
log_prefix = "[
|
|
66
|
-
log.info("%sRetrieving agent by name '%s'.", log_prefix, agent_name)
|
|
67
|
-
|
|
68
|
-
log.info("%sFound: %s", log_prefix,
|
|
69
|
-
return
|
|
65
|
+
log_prefix = "[AgentCardService.get_agent_card_by_name] "
|
|
66
|
+
log.info("%sRetrieving agent card by name '%s'.", log_prefix, agent_name)
|
|
67
|
+
agent_card = self._agent_registry.get_agent(agent_name)
|
|
68
|
+
log.info("%sFound: %s", log_prefix, agent_card is not None)
|
|
69
|
+
return agent_card
|