solace-agent-mesh 1.0.9__py3-none-any.whl → 1.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of solace-agent-mesh might be problematic. Click here for more details.

Files changed (220) hide show
  1. solace_agent_mesh/agent/adk/adk_llm.txt +182 -42
  2. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +171 -0
  3. solace_agent_mesh/agent/adk/callbacks.py +165 -104
  4. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +0 -18
  5. solace_agent_mesh/agent/adk/models/models_llm.txt +104 -55
  6. solace_agent_mesh/agent/adk/runner.py +25 -17
  7. solace_agent_mesh/agent/adk/services.py +3 -3
  8. solace_agent_mesh/agent/adk/setup.py +11 -0
  9. solace_agent_mesh/agent/adk/stream_parser.py +8 -1
  10. solace_agent_mesh/agent/adk/tool_wrapper.py +10 -3
  11. solace_agent_mesh/agent/agent_llm.txt +355 -18
  12. solace_agent_mesh/agent/protocol/event_handlers.py +460 -317
  13. solace_agent_mesh/agent/protocol/protocol_llm.txt +54 -7
  14. solace_agent_mesh/agent/sac/app.py +2 -2
  15. solace_agent_mesh/agent/sac/component.py +211 -517
  16. solace_agent_mesh/agent/sac/sac_llm.txt +133 -63
  17. solace_agent_mesh/agent/testing/testing_llm.txt +25 -58
  18. solace_agent_mesh/agent/tools/peer_agent_tool.py +15 -11
  19. solace_agent_mesh/agent/tools/tools_llm.txt +234 -69
  20. solace_agent_mesh/agent/utils/artifact_helpers.py +35 -1
  21. solace_agent_mesh/agent/utils/utils_llm.txt +90 -105
  22. solace_agent_mesh/assets/docs/404.html +3 -3
  23. solace_agent_mesh/assets/docs/assets/js/6e0db977.39a79ca9.js +1 -0
  24. solace_agent_mesh/assets/docs/assets/js/{75384d09.ccd480c4.js → 75384d09.bf78fbdb.js} +1 -1
  25. solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +1 -0
  26. solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +1 -0
  27. solace_agent_mesh/assets/docs/assets/js/main.08d30374.js +2 -0
  28. solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +1 -0
  29. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +4 -4
  30. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +4 -4
  31. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +4 -4
  32. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
  33. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +4 -4
  34. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +4 -4
  35. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
  36. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +4 -4
  37. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +4 -4
  38. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +4 -4
  39. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +4 -4
  40. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +4 -4
  41. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
  42. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +4 -4
  43. solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +105 -0
  44. solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html +53 -0
  45. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +4 -4
  46. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +4 -4
  47. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +4 -4
  48. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
  49. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +4 -4
  50. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +4 -4
  51. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +4 -4
  52. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +4 -4
  53. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +4 -4
  54. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +4 -4
  55. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +4 -4
  56. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +4 -4
  57. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +4 -4
  58. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +4 -4
  59. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +4 -4
  60. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +4 -4
  61. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +4 -4
  62. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +4 -4
  63. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
  64. solace_agent_mesh/assets/docs/lunr-index-1757433031159.json +1 -0
  65. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  66. solace_agent_mesh/assets/docs/search-doc-1757433031159.json +1 -0
  67. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  68. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  69. solace_agent_mesh/cli/__init__.py +1 -1
  70. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
  71. solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
  72. solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
  73. solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
  74. solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
  75. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
  76. solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
  77. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
  78. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
  79. solace_agent_mesh/cli/commands/run_cmd.py +5 -3
  80. solace_agent_mesh/cli/utils.py +68 -12
  81. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-vY5eu2lI.js +1 -0
  82. solace_agent_mesh/client/webui/frontend/static/assets/client-BeBkzgWW.js +25 -0
  83. solace_agent_mesh/client/webui/frontend/static/assets/main-Bjys1KQs.js +339 -0
  84. solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
  85. solace_agent_mesh/client/webui/frontend/static/assets/vendor-CE0AeXyK.js +395 -0
  86. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
  87. solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
  88. solace_agent_mesh/common/a2a/__init__.py +213 -0
  89. solace_agent_mesh/common/a2a/a2a_llm.txt +182 -0
  90. solace_agent_mesh/common/a2a/artifact.py +328 -0
  91. solace_agent_mesh/common/a2a/events.py +183 -0
  92. solace_agent_mesh/common/a2a/message.py +307 -0
  93. solace_agent_mesh/common/a2a/protocol.py +513 -0
  94. solace_agent_mesh/common/a2a/task.py +127 -0
  95. solace_agent_mesh/common/a2a/translation.py +653 -0
  96. solace_agent_mesh/common/a2a/types.py +54 -0
  97. solace_agent_mesh/common/a2a_spec/a2a.json +2576 -0
  98. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +407 -0
  99. solace_agent_mesh/common/a2a_spec/schemas/agent_progress_update.json +18 -0
  100. solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +31 -0
  101. solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +18 -0
  102. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +235 -0
  103. solace_agent_mesh/common/a2a_spec/schemas/tool_invocation_start.json +26 -0
  104. solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +25 -0
  105. solace_agent_mesh/common/agent_registry.py +1 -1
  106. solace_agent_mesh/common/common_llm.txt +192 -70
  107. solace_agent_mesh/common/data_parts.py +99 -0
  108. solace_agent_mesh/common/middleware/middleware_llm.txt +17 -17
  109. solace_agent_mesh/common/sac/__init__.py +0 -0
  110. solace_agent_mesh/common/sac/sac_llm.txt +71 -0
  111. solace_agent_mesh/common/sac/sam_component_base.py +252 -0
  112. solace_agent_mesh/common/services/providers/providers_llm.txt +51 -84
  113. solace_agent_mesh/common/services/services_llm.txt +206 -26
  114. solace_agent_mesh/common/utils/artifact_utils.py +29 -0
  115. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +176 -80
  116. solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
  117. solace_agent_mesh/common/utils/utils_llm.txt +323 -42
  118. solace_agent_mesh/config_portal/backend/common.py +2 -2
  119. solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +1 -1
  120. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
  121. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
  122. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  123. solace_agent_mesh/core_a2a/core_a2a_llm.txt +10 -8
  124. solace_agent_mesh/core_a2a/service.py +20 -44
  125. solace_agent_mesh/evaluation/message_organizer.py +35 -56
  126. solace_agent_mesh/evaluation/run.py +26 -5
  127. solace_agent_mesh/evaluation/subscriber.py +35 -10
  128. solace_agent_mesh/evaluation/summary_builder.py +27 -34
  129. solace_agent_mesh/gateway/base/app.py +27 -1
  130. solace_agent_mesh/gateway/base/base_llm.txt +177 -72
  131. solace_agent_mesh/gateway/base/component.py +294 -523
  132. solace_agent_mesh/gateway/gateway_llm.txt +299 -58
  133. solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
  134. solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
  135. solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
  136. solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
  137. solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
  138. solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
  139. solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
  140. solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
  141. solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
  142. solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
  143. solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
  144. solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
  145. solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
  146. solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
  147. solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
  148. solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
  149. solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
  150. solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
  151. solace_agent_mesh/gateway/http_sse/app.py +31 -1
  152. solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
  153. solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
  154. solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
  155. solace_agent_mesh/gateway/http_sse/component.py +371 -236
  156. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +29 -29
  157. solace_agent_mesh/gateway/http_sse/dependencies.py +142 -39
  158. solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
  159. solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
  160. solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
  161. solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
  162. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +272 -36
  163. solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
  164. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
  165. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
  166. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
  167. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
  168. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
  169. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
  170. solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
  171. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
  172. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
  173. solace_agent_mesh/gateway/http_sse/main.py +293 -91
  174. solace_agent_mesh/gateway/http_sse/routers/agents.py +1 -1
  175. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +137 -56
  176. solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
  177. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +231 -5
  178. solace_agent_mesh/gateway/http_sse/routers/tasks.py +199 -171
  179. solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
  180. solace_agent_mesh/gateway/http_sse/services/agent_service.py +1 -1
  181. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +89 -135
  182. solace_agent_mesh/gateway/http_sse/services/task_service.py +2 -5
  183. solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
  184. solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
  185. solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
  186. solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
  187. solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
  188. solace_agent_mesh/solace_agent_mesh_llm.txt +362 -0
  189. solace_agent_mesh/templates/gateway_component_template.py +149 -98
  190. solace_agent_mesh/templates/shared_config.yaml +4 -5
  191. solace_agent_mesh/templates/webui.yaml +8 -10
  192. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/METADATA +9 -6
  193. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/RECORD +197 -141
  194. solace_agent_mesh/assets/docs/assets/js/f284c35a.731836ad.js +0 -1
  195. solace_agent_mesh/assets/docs/assets/js/main.3d0e7879.js +0 -2
  196. solace_agent_mesh/assets/docs/assets/js/runtime~main.05d19492.js +0 -1
  197. solace_agent_mesh/assets/docs/lunr-index-1757091012487.json +0 -1
  198. solace_agent_mesh/assets/docs/search-doc-1757091012487.json +0 -1
  199. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
  200. solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
  201. solace_agent_mesh/client/webui/frontend/static/assets/main-D0FnP_W4.css +0 -1
  202. solace_agent_mesh/client/webui/frontend/static/assets/main-Do32sFPX.js +0 -708
  203. solace_agent_mesh/common/a2a_protocol.py +0 -564
  204. solace_agent_mesh/common/client/__init__.py +0 -4
  205. solace_agent_mesh/common/client/card_resolver.py +0 -21
  206. solace_agent_mesh/common/client/client.py +0 -85
  207. solace_agent_mesh/common/client/client_llm.txt +0 -133
  208. solace_agent_mesh/common/server/__init__.py +0 -4
  209. solace_agent_mesh/common/server/server.py +0 -122
  210. solace_agent_mesh/common/server/server_llm.txt +0 -169
  211. solace_agent_mesh/common/server/task_manager.py +0 -291
  212. solace_agent_mesh/common/server/utils.py +0 -28
  213. solace_agent_mesh/common/types.py +0 -411
  214. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
  215. solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -80
  216. solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
  217. /solace_agent_mesh/assets/docs/assets/js/{main.3d0e7879.js.LICENSE.txt → main.08d30374.js.LICENSE.txt} +0 -0
  218. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/WHEEL +0 -0
  219. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/entry_points.txt +0 -0
  220. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -2,76 +2,81 @@
2
2
  FastAPI router for managing session-specific artifacts via REST endpoints.
3
3
  """
4
4
 
5
- from typing import (
6
- List,
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 StreamingResponse, Response
25
- from google.adk.artifacts import BaseArtifactService
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 urlparse, parse_qs, quote
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
 
35
+ from ....common.a2a.types import ArtifactInfo
42
36
  from ....common.middleware import ConfigResolver
43
- from ....common.types import ArtifactInfo
44
- from ....common.utils.mime_helpers import is_text_based_mime_type
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 (
56
+ DEFAULT_SCHEMA_MAX_KEYS,
57
+ format_artifact_uri,
55
58
  get_artifact_info_list,
56
- save_artifact_with_metadata,
57
59
  load_artifact_content_or_metadata,
58
- DEFAULT_SCHEMA_MAX_KEYS,
60
+ save_artifact_with_metadata,
59
61
  )
60
62
 
61
63
  router = APIRouter()
62
64
 
63
65
 
64
66
  @router.get(
65
- "/{filename}/versions",
66
- response_model=List[int],
67
+ "/{session_id}/{filename}/versions",
68
+ response_model=list[int],
67
69
  summary="List Artifact Versions",
68
70
  description="Retrieves a list of available version numbers for a specific artifact.",
69
71
  )
70
72
  async def list_artifact_versions(
73
+ session_id: str = Path(
74
+ ..., title="Session ID", description="The session ID to get artifacts from"
75
+ ),
71
76
  filename: str = Path(..., title="Filename", description="The name of the artifact"),
72
77
  artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
73
78
  user_id: str = Depends(get_user_id),
74
- session_id: str = Depends(ensure_session_id),
79
+ validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
75
80
  component: "WebUIBackendComponent" = Depends(get_sac_component),
76
81
  config_resolver: ConfigResolver = Depends(get_config_resolver),
77
82
  user_config: dict = Depends(get_user_config),
@@ -90,6 +95,14 @@ async def list_artifact_versions(
90
95
  log_prefix = f"[ArtifactRouter:ListVersions:{filename}] User={user_id}, Session={session_id} -"
91
96
  log.info("%s Request received.", log_prefix)
92
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
+
93
106
  if artifact_service is None:
94
107
  log.error("%s Artifact service is not configured or available.", log_prefix)
95
108
  raise HTTPException(
@@ -133,23 +146,32 @@ async def list_artifact_versions(
133
146
  )
134
147
 
135
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
+ )
136
155
  @router.get(
137
156
  "/",
138
- response_model=List[ArtifactInfo],
157
+ response_model=list[ArtifactInfo],
139
158
  summary="List Artifact Information",
140
159
  description="Retrieves detailed information for artifacts available for the current user session.",
141
160
  )
142
161
  async def list_artifacts(
162
+ session_id: str = Path(
163
+ ..., title="Session ID", description="The session ID to list artifacts for"
164
+ ),
143
165
  artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
144
166
  user_id: str = Depends(get_user_id),
145
- session_id: str = Depends(ensure_session_id),
167
+ validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
146
168
  component: "WebUIBackendComponent" = Depends(get_sac_component),
147
169
  config_resolver: ConfigResolver = Depends(get_config_resolver),
148
170
  user_config: dict = Depends(get_user_config),
149
171
  ):
150
172
  """
151
173
  Lists detailed information (filename, size, type, modified date, uri)
152
- for all artifacts associated with the current user and session ID
174
+ for all artifacts associated with the specified user and session ID
153
175
  by calling the artifact helper function.
154
176
  """
155
177
  if not config_resolver.is_feature_enabled(
@@ -160,6 +182,19 @@ async def list_artifacts(
160
182
  log_prefix = f"[ArtifactRouter:ListInfo] User={user_id}, Session={session_id} -"
161
183
  log.info("%s Request received.", log_prefix)
162
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
+
163
198
  if artifact_service is None:
164
199
  log.error("%s Artifact service is not configured or available.", log_prefix)
165
200
  raise HTTPException(
@@ -193,15 +228,18 @@ async def list_artifacts(
193
228
 
194
229
 
195
230
  @router.get(
196
- "/{filename}",
231
+ "/{session_id}/{filename}",
197
232
  summary="Get Latest Artifact Content",
198
233
  description="Retrieves the content of the latest version of a specific artifact.",
199
234
  )
200
235
  async def get_latest_artifact(
236
+ session_id: str = Path(
237
+ ..., title="Session ID", description="The session ID to get artifacts from"
238
+ ),
201
239
  filename: str = Path(..., title="Filename", description="The name of the artifact"),
202
240
  artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
203
241
  user_id: str = Depends(get_user_id),
204
- session_id: str = Depends(ensure_session_id),
242
+ validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
205
243
  component: "WebUIBackendComponent" = Depends(get_sac_component),
206
244
  config_resolver: ConfigResolver = Depends(get_config_resolver),
207
245
  user_config: dict = Depends(get_user_config),
@@ -330,20 +368,23 @@ async def get_latest_artifact(
330
368
 
331
369
 
332
370
  @router.get(
333
- "/{filename}/versions/{version}",
371
+ "/{session_id}/{filename}/versions/{version}",
334
372
  summary="Get Specific Artifact Version Content",
335
373
  description="Retrieves the content of a specific version of an artifact.",
336
374
  )
337
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
+ ),
338
379
  filename: str = Path(..., title="Filename", description="The name of the artifact"),
339
- version: Union[int, str] = Path(
380
+ version: int | str = Path(
340
381
  ...,
341
382
  title="Version",
342
383
  description="The specific version number to retrieve, or 'latest'",
343
384
  ),
344
385
  artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
345
386
  user_id: str = Depends(get_user_id),
346
- session_id: str = Depends(ensure_session_id),
387
+ validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
347
388
  component: "WebUIBackendComponent" = Depends(get_sac_component),
348
389
  config_resolver: ConfigResolver = Depends(get_config_resolver),
349
390
  user_config: dict = Depends(get_user_config),
@@ -361,6 +402,14 @@ async def get_specific_artifact_version(
361
402
  log_prefix = f"[ArtifactRouter:GetVersion:{filename} v{version}] User={user_id}, Session={session_id} -"
362
403
  log.info("%s Request received.", log_prefix)
363
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
+
364
413
  if artifact_service is None:
365
414
  log.error("%s Artifact service is not configured or available.", log_prefix)
366
415
  raise HTTPException(
@@ -380,7 +429,7 @@ async def get_specific_artifact_version(
380
429
  version=version,
381
430
  load_metadata_only=False,
382
431
  return_raw_bytes=True,
383
- log_identifier_prefix=f"[ArtifactRouter:GetVersion]",
432
+ log_identifier_prefix="[ArtifactRouter:GetVersion]",
384
433
  )
385
434
 
386
435
  if load_result.get("status") != "success":
@@ -403,7 +452,6 @@ async def get_specific_artifact_version(
403
452
  mime_type = load_result.get("mime_type", "application/octet-stream")
404
453
  resolved_version_from_helper = load_result.get("version")
405
454
  if data_bytes is None:
406
-
407
455
  log.error(
408
456
  "%s Helper (with return_raw_bytes=True) returned success but no raw_bytes for '%s' v%s (resolved to %s).",
409
457
  log_prefix,
@@ -528,7 +576,7 @@ async def get_artifact_by_uri(
528
576
  This allows fetching artifacts from any context, not just the current user's session,
529
577
  after performing an authorization check.
530
578
  """
531
- log_id_prefix = f"[ArtifactRouter:by-uri]"
579
+ log_id_prefix = "[ArtifactRouter:by-uri]"
532
580
  log.info(
533
581
  "%s Received request for URI: %s from user: %s",
534
582
  log_id_prefix,
@@ -631,23 +679,26 @@ async def get_artifact_by_uri(
631
679
 
632
680
 
633
681
  @router.post(
634
- "/{filename}",
682
+ "/{session_id}/{filename}",
635
683
  status_code=status.HTTP_201_CREATED,
636
- response_model=Dict[str, Any],
684
+ response_model=dict[str, Any],
637
685
  summary="Upload Artifact (Create/Update Version with Metadata)",
638
686
  description="Uploads file content and optional metadata to create or update an artifact version.",
639
687
  )
640
688
  async def upload_artifact(
689
+ session_id: str = Path(
690
+ ..., title="Session ID", description="The session ID to upload artifacts to"
691
+ ),
641
692
  filename: str = Path(
642
693
  ..., title="Filename", description="The name of the artifact to create/update"
643
694
  ),
644
695
  upload_file: UploadFile = File(..., description="The file content to upload"),
645
- metadata_json: Optional[str] = Form(
696
+ metadata_json: str | None = Form(
646
697
  None, description="JSON string of artifact metadata (e.g., description, source)"
647
698
  ),
648
699
  artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
649
700
  user_id: str = Depends(get_user_id),
650
- session_id: str = Depends(ensure_session_id),
701
+ validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
651
702
  component: "WebUIBackendComponent" = Depends(get_sac_component),
652
703
  config_resolver: ConfigResolver = Depends(get_config_resolver),
653
704
  user_config: dict = Depends(get_user_config),
@@ -664,13 +715,20 @@ async def upload_artifact(
664
715
  f"[ArtifactRouter:Post:{filename}] User={user_id}, Session={session_id} -"
665
716
  )
666
717
  log.info(
667
- "%s Request received. Upload filename: '%s', content type: %s",
718
+ "%s Request received. Upload filename: '%s', content type: %s, Metadata provided: %s",
668
719
  log_prefix,
669
720
  upload_file.filename,
670
721
  upload_file.content_type,
671
- f"Metadata provided: {bool(metadata_json)}",
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(
@@ -724,7 +782,7 @@ async def upload_artifact(
724
782
  ),
725
783
  )
726
784
 
727
- if save_result["status"] in ["success", "partial_success"]:
785
+ if save_result["status"] == "success":
728
786
  log.info(
729
787
  "%s Artifact and metadata processing completed. Data version: %s, Metadata version: %s. Message: %s",
730
788
  log_prefix,
@@ -732,14 +790,28 @@ async def upload_artifact(
732
790
  save_result.get("metadata_version"),
733
791
  save_result.get("message"),
734
792
  )
793
+ saved_version = save_result.get("data_version")
794
+ artifact_uri = format_artifact_uri(
795
+ app_name=app_name,
796
+ user_id=user_id,
797
+ session_id=session_id,
798
+ filename=filename,
799
+ version=saved_version,
800
+ )
801
+ log.info(
802
+ "%s Successfully saved artifact. Returning URI: %s",
803
+ log_prefix,
804
+ artifact_uri,
805
+ )
735
806
  return {
736
807
  "filename": filename,
737
- "data_version": save_result.get("data_version"),
808
+ "data_version": saved_version,
738
809
  "metadata_version": save_result.get("metadata_version"),
739
810
  "mime_type": mime_type,
740
811
  "size": len(content_bytes),
741
812
  "message": save_result.get("message"),
742
813
  "status": save_result["status"],
814
+ "uri": artifact_uri,
743
815
  }
744
816
  else:
745
817
  log.error(
@@ -763,24 +835,26 @@ async def upload_artifact(
763
835
  detail=f"Failed to save artifact: {str(e)}",
764
836
  )
765
837
  finally:
766
-
767
838
  await upload_file.close()
768
839
  log.debug("%s Upload file closed.", log_prefix)
769
840
 
770
841
 
771
842
  @router.delete(
772
- "/{filename}",
843
+ "/{session_id}/{filename}",
773
844
  status_code=status.HTTP_204_NO_CONTENT,
774
845
  summary="Delete Artifact",
775
846
  description="Deletes an artifact and all its versions.",
776
847
  )
777
848
  async def delete_artifact(
849
+ session_id: str = Path(
850
+ ..., title="Session ID", description="The session ID to delete artifacts from"
851
+ ),
778
852
  filename: str = Path(
779
853
  ..., title="Filename", description="The name of the artifact to delete"
780
854
  ),
781
855
  artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
782
856
  user_id: str = Depends(get_user_id),
783
- session_id: str = Depends(ensure_session_id),
857
+ validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
784
858
  component: "WebUIBackendComponent" = Depends(get_sac_component),
785
859
  config_resolver: ConfigResolver = Depends(get_config_resolver),
786
860
  user_config: dict = Depends(get_user_config),
@@ -798,6 +872,14 @@ async def delete_artifact(
798
872
  )
799
873
  log.info("%s Request received.", log_prefix)
800
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
+
801
883
  if artifact_service is None:
802
884
  log.error("%s Artifact service is not configured or available.", log_prefix)
803
885
  raise HTTPException(
@@ -819,7 +901,6 @@ async def delete_artifact(
819
901
  return Response(status_code=status.HTTP_204_NO_CONTENT)
820
902
 
821
903
  except Exception as e:
822
-
823
904
  log.exception("%s Error deleting artifact: %s", log_prefix, e)
824
905
  raise HTTPException(
825
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