solace-agent-mesh 1.4.7__py3-none-any.whl → 1.4.9__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 (120) hide show
  1. solace_agent_mesh/agent/sac/app.py +3 -3
  2. solace_agent_mesh/agent/sac/component.py +2 -3
  3. solace_agent_mesh/agent/utils/artifact_helpers.py +23 -7
  4. solace_agent_mesh/assets/docs/404.html +3 -3
  5. solace_agent_mesh/assets/docs/assets/js/{0e682baa.da822665.js → 0e682baa.d054e1d8.js} +1 -1
  6. solace_agent_mesh/assets/docs/assets/js/166ab619.e27886d9.js +1 -0
  7. solace_agent_mesh/assets/docs/assets/js/453a82a6.3c6bb61d.js +1 -0
  8. solace_agent_mesh/assets/docs/assets/js/{75384d09.1e7d7cb7.js → 75384d09.c19e8b51.js} +1 -1
  9. solace_agent_mesh/assets/docs/assets/js/a3a92b25.af35e313.js +1 -0
  10. solace_agent_mesh/assets/docs/assets/js/{bac0be12.bf0181cf.js → bac0be12.17de4316.js} +1 -1
  11. solace_agent_mesh/assets/docs/assets/js/d6a81ee7.829198f1.js +1 -0
  12. solace_agent_mesh/assets/docs/assets/js/f284c35a.ed8dd236.js +1 -0
  13. solace_agent_mesh/assets/docs/assets/js/{main.11f9f9f3.js → main.51e33228.js} +2 -2
  14. solace_agent_mesh/assets/docs/assets/js/runtime~main.0d2ff2b6.js +1 -0
  15. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +4 -4
  16. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/rbac-setup-guilde/index.html +4 -4
  17. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +4 -4
  18. solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +4 -4
  19. solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html +4 -4
  20. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +4 -4
  21. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +4 -4
  22. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +4 -4
  23. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
  24. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +4 -4
  25. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +4 -4
  26. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
  27. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +4 -4
  28. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +4 -4
  29. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +4 -4
  30. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +11 -12
  31. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/litellm_models/index.html +49 -0
  32. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +4 -4
  33. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
  34. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +4 -4
  35. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +4 -4
  36. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +4 -4
  37. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +5 -5
  38. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +5 -5
  39. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +4 -4
  40. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +6 -6
  41. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +4 -4
  42. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +4 -4
  43. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +4 -4
  44. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +4 -4
  45. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +4 -4
  46. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +4 -4
  47. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +4 -4
  48. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +4 -4
  49. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +4 -4
  50. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +4 -4
  51. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +4 -4
  52. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +4 -4
  53. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +4 -4
  54. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
  55. solace_agent_mesh/assets/docs/lunr-index-1759254374040.json +1 -0
  56. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  57. solace_agent_mesh/assets/docs/search-doc-1759254374040.json +1 -0
  58. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  59. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  60. solace_agent_mesh/cli/__init__.py +1 -1
  61. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +6 -3
  62. solace_agent_mesh/cli/commands/init_cmd/__init__.py +3 -3
  63. solace_agent_mesh/cli/commands/init_cmd/broker_step.py +1 -1
  64. solace_agent_mesh/cli/commands/init_cmd/env_step.py +1 -1
  65. solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +4 -4
  66. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +12 -1
  67. solace_agent_mesh/cli/commands/plugin_cmd/install_cmd.py +5 -5
  68. solace_agent_mesh/client/webui/frontend/static/assets/main-B0PHV3hm.js +339 -0
  69. solace_agent_mesh/client/webui/frontend/static/index.html +1 -1
  70. solace_agent_mesh/common/constants.py +2 -0
  71. solace_agent_mesh/config_portal/backend/common.py +1 -1
  72. solace_agent_mesh/config_portal/frontend/static/client/assets/{_index-bFMKlzKf.js → _index-BNuqpWDc.js} +1 -1
  73. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-89db7c30.js → manifest-44d62be6.js} +1 -1
  74. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  75. solace_agent_mesh/gateway/http_sse/component.py +21 -15
  76. solace_agent_mesh/gateway/http_sse/dependencies.py +84 -88
  77. solace_agent_mesh/gateway/http_sse/main.py +8 -2
  78. solace_agent_mesh/gateway/http_sse/repository/entities/message.py +3 -1
  79. solace_agent_mesh/gateway/http_sse/repository/entities/session.py +3 -1
  80. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +5 -0
  81. solace_agent_mesh/gateway/http_sse/repository/message_repository.py +25 -23
  82. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +12 -4
  83. solace_agent_mesh/gateway/http_sse/repository/models/message_model.py +19 -1
  84. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +19 -1
  85. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +46 -42
  86. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +199 -59
  87. solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +1 -6
  88. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +3 -17
  89. solace_agent_mesh/gateway/http_sse/routers/people.py +4 -37
  90. solace_agent_mesh/gateway/http_sse/routers/sessions.py +33 -68
  91. solace_agent_mesh/gateway/http_sse/routers/tasks.py +54 -28
  92. solace_agent_mesh/gateway/http_sse/services/session_service.py +60 -28
  93. solace_agent_mesh/gateway/http_sse/shared/__init__.py +122 -1
  94. solace_agent_mesh/gateway/http_sse/shared/base_repository.py +278 -0
  95. solace_agent_mesh/gateway/http_sse/shared/database_exceptions.py +274 -0
  96. solace_agent_mesh/gateway/http_sse/shared/database_helpers.py +43 -0
  97. solace_agent_mesh/gateway/http_sse/shared/error_dto.py +107 -0
  98. solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +192 -0
  99. solace_agent_mesh/gateway/http_sse/shared/exceptions.py +192 -0
  100. solace_agent_mesh/gateway/http_sse/shared/pagination.py +138 -0
  101. solace_agent_mesh/gateway/http_sse/shared/response_utils.py +134 -0
  102. solace_agent_mesh/gateway/http_sse/shared/utils.py +22 -0
  103. solace_agent_mesh/templates/plugin_agent_config_template.yaml +1 -1
  104. solace_agent_mesh/templates/plugin_custom_config_template.yaml +1 -1
  105. solace_agent_mesh/templates/plugin_gateway_config_template.yaml +1 -1
  106. solace_agent_mesh/templates/shared_config.yaml +1 -1
  107. {solace_agent_mesh-1.4.7.dist-info → solace_agent_mesh-1.4.9.dist-info}/METADATA +34 -35
  108. {solace_agent_mesh-1.4.7.dist-info → solace_agent_mesh-1.4.9.dist-info}/RECORD +112 -101
  109. solace_agent_mesh/assets/docs/assets/js/166ab619.bdddc63a.js +0 -1
  110. solace_agent_mesh/assets/docs/assets/js/a3a92b25.6def8980.js +0 -1
  111. solace_agent_mesh/assets/docs/assets/js/beecea0d.ce915979.js +0 -1
  112. solace_agent_mesh/assets/docs/assets/js/f284c35a.525933db.js +0 -1
  113. solace_agent_mesh/assets/docs/assets/js/runtime~main.5922bcf0.js +0 -1
  114. solace_agent_mesh/assets/docs/lunr-index-1759151175744.json +0 -1
  115. solace_agent_mesh/assets/docs/search-doc-1759151175744.json +0 -1
  116. solace_agent_mesh/client/webui/frontend/static/assets/main-BKIoiLSu.js +0 -339
  117. /solace_agent_mesh/assets/docs/assets/js/{main.11f9f9f3.js.LICENSE.txt → main.51e33228.js.LICENSE.txt} +0 -0
  118. {solace_agent_mesh-1.4.7.dist-info → solace_agent_mesh-1.4.9.dist-info}/WHEEL +0 -0
  119. {solace_agent_mesh-1.4.7.dist-info → solace_agent_mesh-1.4.9.dist-info}/entry_points.txt +0 -0
  120. {solace_agent_mesh-1.4.7.dist-info → solace_agent_mesh-1.4.9.dist-info}/licenses/LICENSE +0 -0
@@ -14,7 +14,9 @@ from fastapi import (
14
14
  Path,
15
15
  UploadFile,
16
16
  status,
17
+ Request as FastAPIRequest,
17
18
  )
19
+ from pydantic import BaseModel, Field
18
20
  from fastapi.responses import Response, StreamingResponse
19
21
 
20
22
  try:
@@ -33,7 +35,6 @@ from urllib.parse import parse_qs, quote, urlparse
33
35
  from solace_ai_connector.common.log import log
34
36
 
35
37
  from ....common.a2a.types import ArtifactInfo
36
- from ....common.middleware import ConfigResolver
37
38
  from ....common.utils.embeds import (
38
39
  LATE_EMBED_TYPES,
39
40
  evaluate_embed,
@@ -41,17 +42,24 @@ from ....common.utils.embeds import (
41
42
  )
42
43
  from ....common.utils.mime_helpers import is_text_based_mime_type
43
44
  from ..dependencies import (
44
- get_config_resolver,
45
+ ValidatedUserConfig,
45
46
  get_sac_component,
46
47
  get_session_validator,
47
48
  get_shared_artifact_service,
48
49
  get_user_config,
49
50
  get_user_id,
51
+ get_session_manager,
52
+ get_session_business_service_optional,
53
+ get_db_optional,
50
54
  )
51
55
 
52
56
  if TYPE_CHECKING:
53
57
  from ....gateway.http_sse.component import WebUIBackendComponent
54
58
 
59
+ from ..session_manager import SessionManager
60
+ from ..services.session_service import SessionService
61
+ from sqlalchemy.orm import Session
62
+
55
63
  from ....agent.utils.artifact_helpers import (
56
64
  DEFAULT_SCHEMA_MAX_KEYS,
57
65
  format_artifact_uri,
@@ -60,9 +68,191 @@ from ....agent.utils.artifact_helpers import (
60
68
  save_artifact_with_metadata,
61
69
  )
62
70
 
71
+
72
+ class ArtifactUploadResponse(BaseModel):
73
+ """Response model for artifact upload with camelCase fields."""
74
+ uri: str
75
+ session_id: str = Field(..., alias="sessionId")
76
+ filename: str
77
+ size: int
78
+ mime_type: str = Field(..., alias="mimeType")
79
+ metadata: dict[str, Any]
80
+ created_at: str = Field(..., alias="createdAt")
81
+
82
+ model_config = {"populate_by_name": True}
83
+
84
+
63
85
  router = APIRouter()
64
86
 
65
87
 
88
+ @router.post(
89
+ "/upload",
90
+ status_code=status.HTTP_201_CREATED,
91
+ response_model=ArtifactUploadResponse,
92
+ summary="Upload Artifact (Body-Based Session Management)",
93
+ description="Uploads file with sessionId and filename in request body. Creates session if sessionId is null/empty.",
94
+ )
95
+ async def upload_artifact_with_session(
96
+ request: FastAPIRequest,
97
+ upload_file: UploadFile = File(..., description="The file content to upload"),
98
+ sessionId: str | None = Form(None, description="Session ID (null/empty to create new session)", alias="sessionId"),
99
+ filename: str = Form(..., description="The name of the artifact to create/update"),
100
+ metadata_json: str | None = Form(
101
+ None, description="JSON string of artifact metadata (e.g., description, source)"
102
+ ),
103
+ artifact_service: BaseArtifactService = Depends(get_shared_artifact_service),
104
+ user_id: str = Depends(get_user_id),
105
+ validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
106
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
107
+ user_config: dict = Depends(ValidatedUserConfig(["tool:artifact:create"])),
108
+ session_manager: SessionManager = Depends(get_session_manager),
109
+ session_service: SessionService | None = Depends(get_session_business_service_optional),
110
+ db: Session | None = Depends(get_db_optional),
111
+ ):
112
+ """
113
+ Uploads a file to create a new version of the specified artifact.
114
+
115
+ Key features:
116
+ - Session ID and filename provided in request body (not URL)
117
+ - Automatically creates new session if session_id is null/empty
118
+ - Consistent with chat API patterns
119
+ """
120
+ log_prefix = f"[POST /artifacts/upload] User {user_id}: "
121
+
122
+ # Handle session creation logic (matching chat API pattern)
123
+ effective_session_id = None
124
+
125
+ # Use session ID from request body (matching sessionId pattern in session APIs)
126
+ if sessionId and sessionId.strip():
127
+ effective_session_id = sessionId.strip()
128
+ log.info("%sUsing existing session: %s", log_prefix, effective_session_id)
129
+ else:
130
+ # Create new session when no sessionId provided (like chat does for new conversations)
131
+ effective_session_id = session_manager.create_new_session_id(request)
132
+ log.info("%sCreated new session for file upload: %s", log_prefix, effective_session_id)
133
+
134
+ # Persist session in database if persistence is available (matching chat pattern)
135
+ if session_service and db:
136
+ try:
137
+ session_service.create_session(
138
+ db=db,
139
+ user_id=user_id,
140
+ session_id=effective_session_id,
141
+ agent_id=None, # Will be determined when first message is sent
142
+ name=None, # Will be set when first message is sent
143
+ )
144
+ db.commit()
145
+ log.info("%sSession created and committed to database: %s", log_prefix, effective_session_id)
146
+ except Exception as session_error:
147
+ db.rollback()
148
+ log.warning("%sSession persistence failed, continuing with in-memory session: %s",
149
+ log_prefix, session_error)
150
+ else:
151
+ log.debug("%sNo persistence available - using in-memory session: %s",
152
+ log_prefix, effective_session_id)
153
+
154
+ # Validate inputs
155
+ if not filename or not filename.strip():
156
+ raise HTTPException(
157
+ status_code=status.HTTP_400_BAD_REQUEST,
158
+ detail="Filename is required.",
159
+ )
160
+
161
+ if not upload_file.filename:
162
+ raise HTTPException(
163
+ status_code=status.HTTP_400_BAD_REQUEST,
164
+ detail="File upload is required.",
165
+ )
166
+
167
+ # Validate artifact service availability
168
+ if not artifact_service:
169
+ log.error("%sArtifact service is not configured.", log_prefix)
170
+ raise HTTPException(
171
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
172
+ detail="Artifact service is not configured.",
173
+ )
174
+
175
+ # Validate session (now that we have an effective_session_id)
176
+ if not validate_session(effective_session_id, user_id):
177
+ log.warning("%sSession validation failed for session: %s", log_prefix, effective_session_id)
178
+ raise HTTPException(
179
+ status_code=status.HTTP_403_FORBIDDEN,
180
+ detail="Invalid session or insufficient permissions.",
181
+ )
182
+
183
+ log.info("%sUploading file '%s' to session '%s'", log_prefix, filename.strip(), effective_session_id)
184
+
185
+ try:
186
+ # Read and validate file content
187
+ content_bytes = await upload_file.read()
188
+ if not content_bytes:
189
+ raise HTTPException(
190
+ status_code=status.HTTP_400_BAD_REQUEST,
191
+ detail="File is empty.",
192
+ )
193
+
194
+ mime_type = upload_file.content_type or "application/octet-stream"
195
+ filename_clean = filename.strip()
196
+
197
+ log.debug("%sProcessing file: %s (%d bytes, %s)", log_prefix, filename_clean, len(content_bytes), mime_type)
198
+
199
+ # Parse and validate metadata
200
+ metadata = {}
201
+ if metadata_json and metadata_json.strip():
202
+ try:
203
+ metadata = json.loads(metadata_json.strip())
204
+ if not isinstance(metadata, dict):
205
+ raise ValueError("Metadata must be a JSON object")
206
+ except (json.JSONDecodeError, ValueError) as e:
207
+ log.warning("%sInvalid metadata JSON: %s", log_prefix, e)
208
+ raise HTTPException(
209
+ status_code=status.HTTP_400_BAD_REQUEST,
210
+ detail=f"Invalid JSON in metadata field: {str(e)}",
211
+ )
212
+
213
+ app_name = component.get_config("name", "A2A_WebUI_App")
214
+
215
+ # Store the artifact using the service
216
+ artifact_uri = await artifact_service.store(
217
+ app_name=app_name,
218
+ user_id=user_id,
219
+ session_id=effective_session_id,
220
+ filename=filename_clean,
221
+ content_bytes=content_bytes,
222
+ mime_type=mime_type,
223
+ metadata=metadata,
224
+ )
225
+
226
+ log.info("%sArtifact stored successfully: %s (%d bytes)", log_prefix, artifact_uri, len(content_bytes))
227
+
228
+ # Return standardized response using Pydantic model (ensures camelCase conversion)
229
+ return ArtifactUploadResponse(
230
+ uri=artifact_uri,
231
+ session_id=effective_session_id, # Will be returned as "sessionId" due to alias
232
+ filename=filename_clean,
233
+ size=len(content_bytes),
234
+ mime_type=mime_type, # Will be returned as "mimeType" due to alias
235
+ metadata=metadata,
236
+ created_at=datetime.now(timezone.utc).isoformat(), # Will be returned as "createdAt" due to alias
237
+ )
238
+
239
+ except HTTPException:
240
+ # Re-raise HTTP exceptions as-is
241
+ raise
242
+ except Exception as e:
243
+ log.exception("%sUnexpected error storing artifact: %s", log_prefix, e)
244
+ raise HTTPException(
245
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
246
+ detail="Failed to store artifact due to an internal error.",
247
+ )
248
+ finally:
249
+ # Ensure file is properly closed
250
+ try:
251
+ await upload_file.close()
252
+ except Exception as close_error:
253
+ log.warning("%sError closing upload file: %s", log_prefix, close_error)
254
+
255
+
66
256
  @router.get(
67
257
  "/{session_id}/{filename}/versions",
68
258
  response_model=list[int],
@@ -78,19 +268,12 @@ async def list_artifact_versions(
78
268
  user_id: str = Depends(get_user_id),
79
269
  validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
80
270
  component: "WebUIBackendComponent" = Depends(get_sac_component),
81
- config_resolver: ConfigResolver = Depends(get_config_resolver),
82
- user_config: dict = Depends(get_user_config),
271
+ user_config: dict = Depends(ValidatedUserConfig(["tool:artifact:list"])),
83
272
  ):
84
273
  """
85
274
  Lists the available integer versions for a given artifact filename
86
275
  associated with the current user and session ID.
87
276
  """
88
- if not config_resolver.is_feature_enabled(
89
- user_config, {"required_scopes": ["tool:artifact:list"]}, {}
90
- ):
91
- raise HTTPException(
92
- status_code=403, detail="Not authorized to list artifact versions"
93
- )
94
277
 
95
278
  log_prefix = f"[ArtifactRouter:ListVersions:{filename}] User={user_id}, Session={session_id} -"
96
279
  log.info("%s Request received.", log_prefix)
@@ -166,18 +349,13 @@ async def list_artifacts(
166
349
  user_id: str = Depends(get_user_id),
167
350
  validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
168
351
  component: "WebUIBackendComponent" = Depends(get_sac_component),
169
- config_resolver: ConfigResolver = Depends(get_config_resolver),
170
- user_config: dict = Depends(get_user_config),
352
+ user_config: dict = Depends(ValidatedUserConfig(["tool:artifact:list"])),
171
353
  ):
172
354
  """
173
355
  Lists detailed information (filename, size, type, modified date, uri)
174
356
  for all artifacts associated with the specified user and session ID
175
357
  by calling the artifact helper function.
176
358
  """
177
- if not config_resolver.is_feature_enabled(
178
- user_config, {"required_scopes": ["tool:artifact:list"]}, {}
179
- ):
180
- raise HTTPException(status_code=403, detail="Not authorized to list artifacts")
181
359
 
182
360
  log_prefix = f"[ArtifactRouter:ListInfo] User={user_id}, Session={session_id} -"
183
361
  log.info("%s Request received.", log_prefix)
@@ -241,17 +419,12 @@ async def get_latest_artifact(
241
419
  user_id: str = Depends(get_user_id),
242
420
  validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
243
421
  component: "WebUIBackendComponent" = Depends(get_sac_component),
244
- config_resolver: ConfigResolver = Depends(get_config_resolver),
245
- user_config: dict = Depends(get_user_config),
422
+ user_config: dict = Depends(ValidatedUserConfig(["tool:artifact:load"])),
246
423
  ):
247
424
  """
248
425
  Retrieves the content of the latest version of the specified artifact
249
426
  associated with the current user and session ID.
250
427
  """
251
- if not config_resolver.is_feature_enabled(
252
- user_config, {"required_scopes": ["tool:artifact:load"]}, {}
253
- ):
254
- raise HTTPException(status_code=403, detail="Not authorized to load artifact")
255
428
  log_prefix = (
256
429
  f"[ArtifactRouter:GetLatest:{filename}] User={user_id}, Session={session_id} -"
257
430
  )
@@ -386,19 +559,12 @@ async def get_specific_artifact_version(
386
559
  user_id: str = Depends(get_user_id),
387
560
  validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
388
561
  component: "WebUIBackendComponent" = Depends(get_sac_component),
389
- config_resolver: ConfigResolver = Depends(get_config_resolver),
390
- user_config: dict = Depends(get_user_config),
562
+ user_config: dict = Depends(ValidatedUserConfig(["tool:artifact:load"])),
391
563
  ):
392
564
  """
393
565
  Retrieves the content of a specific version of the specified artifact
394
566
  associated with the current user and session ID.
395
567
  """
396
- if not config_resolver.is_feature_enabled(
397
- user_config, {"required_scopes": ["tool:artifact:load"]}, {}
398
- ):
399
- raise HTTPException(
400
- status_code=403, detail="Not authorized to load artifact version"
401
- )
402
568
  log_prefix = f"[ArtifactRouter:GetVersion:{filename} v{version}] User={user_id}, Session={session_id} -"
403
569
  log.info("%s Request received.", log_prefix)
404
570
 
@@ -568,8 +734,7 @@ async def get_artifact_by_uri(
568
734
  uri: str,
569
735
  requesting_user_id: str = Depends(get_user_id),
570
736
  component: "WebUIBackendComponent" = Depends(get_sac_component),
571
- config_resolver: ConfigResolver = Depends(get_config_resolver),
572
- user_config: dict = Depends(get_user_config),
737
+ user_config: dict = Depends(ValidatedUserConfig(["tool:artifact:load"])),
573
738
  ):
574
739
  """
575
740
  Resolves an artifact:// URI and streams its content.
@@ -620,21 +785,6 @@ async def get_artifact_by_uri(
620
785
  version,
621
786
  )
622
787
 
623
- if not config_resolver.is_feature_enabled(
624
- user_config, {"required_scopes": ["tool:artifact:load"]}, {}
625
- ):
626
- raise HTTPException(
627
- status_code=403, detail="Not authorized to load artifact by URI"
628
- )
629
- log.warning(
630
- "%s Authorization denied for user '%s' to access artifact URI '%s'",
631
- log_id_prefix,
632
- requesting_user_id,
633
- uri,
634
- )
635
- raise HTTPException(
636
- status_code=403, detail="Permission denied to access this artifact."
637
- )
638
788
 
639
789
  log.info(
640
790
  "%s User '%s' authorized to access artifact URI.",
@@ -700,17 +850,12 @@ async def upload_artifact(
700
850
  user_id: str = Depends(get_user_id),
701
851
  validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
702
852
  component: "WebUIBackendComponent" = Depends(get_sac_component),
703
- config_resolver: ConfigResolver = Depends(get_config_resolver),
704
- user_config: dict = Depends(get_user_config),
853
+ user_config: dict = Depends(ValidatedUserConfig(["tool:artifact:create"])),
705
854
  ):
706
855
  """
707
856
  Uploads a file to create a new version of the specified artifact
708
857
  associated with the current user and session ID. Also saves associated metadata.
709
858
  """
710
- if not config_resolver.is_feature_enabled(
711
- user_config, {"required_scopes": ["tool:artifact:create"]}, {}
712
- ):
713
- raise HTTPException(status_code=403, detail="Not authorized to upload artifact")
714
859
  log_prefix = (
715
860
  f"[ArtifactRouter:Post:{filename}] User={user_id}, Session={session_id} -"
716
861
  )
@@ -856,17 +1001,12 @@ async def delete_artifact(
856
1001
  user_id: str = Depends(get_user_id),
857
1002
  validate_session: Callable[[str, str], bool] = Depends(get_session_validator),
858
1003
  component: "WebUIBackendComponent" = Depends(get_sac_component),
859
- config_resolver: ConfigResolver = Depends(get_config_resolver),
860
- user_config: dict = Depends(get_user_config),
1004
+ user_config: dict = Depends(ValidatedUserConfig(["tool:artifact:delete"])),
861
1005
  ):
862
1006
  """
863
1007
  Deletes the specified artifact (including all its versions)
864
1008
  associated with the current user and session ID.
865
1009
  """
866
- if not config_resolver.is_feature_enabled(
867
- user_config, {"required_scopes": ["tool:artifact:delete"]}, {}
868
- ):
869
- raise HTTPException(status_code=403, detail="Not authorized to delete artifact")
870
1010
  log_prefix = (
871
1011
  f"[ArtifactRouter:Delete:{filename}] User={user_id}, Session={session_id} -"
872
1012
  )
@@ -3,18 +3,13 @@ Request DTOs for API endpoints.
3
3
  """
4
4
 
5
5
  from .session_requests import (
6
- GetSessionsRequest,
7
6
  GetSessionRequest,
8
7
  GetSessionHistoryRequest,
9
8
  UpdateSessionRequest,
10
- DeleteSessionRequest,
11
9
  )
12
10
 
13
11
  __all__ = [
14
- # Session requests
15
- "GetSessionsRequest",
16
- "GetSessionRequest",
12
+ "GetSessionRequest",
17
13
  "GetSessionHistoryRequest",
18
14
  "UpdateSessionRequest",
19
- "DeleteSessionRequest",
20
15
  ]
@@ -2,18 +2,10 @@
2
2
  Session-related request DTOs.
3
3
  """
4
4
 
5
- from typing import Optional, List
5
+ from typing import Optional
6
6
  from pydantic import BaseModel, Field
7
7
 
8
- from ....shared.types import SessionId, UserId, SortInfo, FilterInfo, PaginationInfo
9
-
10
-
11
- class GetSessionsRequest(BaseModel):
12
- """Request DTO for retrieving sessions."""
13
- user_id: UserId
14
- pagination: Optional[PaginationInfo] = None
15
- sort: Optional[SortInfo] = None
16
- filters: Optional[List[FilterInfo]] = None
8
+ from ....shared.types import SessionId, UserId, PaginationInfo
17
9
 
18
10
 
19
11
  class GetSessionRequest(BaseModel):
@@ -33,10 +25,4 @@ class UpdateSessionRequest(BaseModel):
33
25
  """Request DTO for updating session details."""
34
26
  session_id: SessionId
35
27
  user_id: UserId
36
- name: str = Field(..., min_length=1, max_length=255, description="New session name")
37
-
38
-
39
- class DeleteSessionRequest(BaseModel):
40
- """Request DTO for deleting a session."""
41
- session_id: SessionId
42
- user_id: UserId
28
+ name: str = Field(..., min_length=1, max_length=255, description="New session name")
@@ -9,11 +9,13 @@ from solace_ai_connector.common.log import log
9
9
 
10
10
  from ..dependencies import get_people_service
11
11
  from ..services.people_service import PeopleService
12
+ from ..shared.pagination import DataResponse
13
+ from ..shared.response_utils import create_data_response
12
14
 
13
15
  router = APIRouter()
14
16
 
15
17
 
16
- @router.get("/people/search", response_model=List[Dict[str, Any]])
18
+ @router.get("/people/search", response_model=DataResponse[List[Dict[str, Any]]])
17
19
  async def search_people(
18
20
  q: str = Query(
19
21
  ...,
@@ -31,39 +33,4 @@ async def search_people(
31
33
  """
32
34
  log.debug("Endpoint /people/search called with query: '%s'", q)
33
35
  results = await people_service.search_for_users(query=q, limit=limit)
34
- return results
35
-
36
-
37
- """
38
- API endpoints for people-related features, such as user search for autocomplete.
39
- """
40
-
41
- from typing import Any, Dict, List
42
-
43
- from fastapi import APIRouter, Depends, Query
44
- from solace_ai_connector.common.log import log
45
- from ..dependencies import get_people_service
46
- from ..services.people_service import PeopleService
47
-
48
- router = APIRouter()
49
-
50
-
51
- @router.get("/people/search", response_model=List[Dict[str, Any]])
52
- async def search_people(
53
- q: str = Query(
54
- ...,
55
- min_length=2,
56
- max_length=50,
57
- description="Search query for user name/email.",
58
- ),
59
- limit: int = Query(
60
- 10, ge=1, le=25, description="Maximum number of results to return."
61
- ),
62
- people_service: PeopleService = Depends(get_people_service),
63
- ):
64
- """
65
- Searches for users to populate frontend autocomplete suggestions (e.g., for @mentions).
66
- """
67
- log.debug("Endpoint /people/search called with query: '%s'", q)
68
- results = await people_service.search_for_users(query=q, limit=limit)
69
- return results
36
+ return create_data_response(results)