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.
- solace_agent_mesh/agent/adk/adk_llm.txt +182 -42
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +171 -0
- solace_agent_mesh/agent/adk/callbacks.py +165 -104
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +0 -18
- solace_agent_mesh/agent/adk/models/models_llm.txt +104 -55
- solace_agent_mesh/agent/adk/runner.py +25 -17
- solace_agent_mesh/agent/adk/services.py +3 -3
- solace_agent_mesh/agent/adk/setup.py +11 -0
- solace_agent_mesh/agent/adk/stream_parser.py +8 -1
- solace_agent_mesh/agent/adk/tool_wrapper.py +10 -3
- solace_agent_mesh/agent/agent_llm.txt +355 -18
- solace_agent_mesh/agent/protocol/event_handlers.py +460 -317
- solace_agent_mesh/agent/protocol/protocol_llm.txt +54 -7
- solace_agent_mesh/agent/sac/app.py +2 -2
- solace_agent_mesh/agent/sac/component.py +211 -517
- solace_agent_mesh/agent/sac/sac_llm.txt +133 -63
- solace_agent_mesh/agent/testing/testing_llm.txt +25 -58
- solace_agent_mesh/agent/tools/peer_agent_tool.py +15 -11
- solace_agent_mesh/agent/tools/tools_llm.txt +234 -69
- solace_agent_mesh/agent/utils/artifact_helpers.py +35 -1
- solace_agent_mesh/agent/utils/utils_llm.txt +90 -105
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/6e0db977.39a79ca9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{75384d09.ccd480c4.js → 75384d09.bf78fbdb.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.08d30374.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +4 -4
- 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/migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +105 -0
- solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html +53 -0
- 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 +4 -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-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-1757433031159.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1757433031159.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-vY5eu2lI.js +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/client-BeBkzgWW.js +25 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-Bjys1KQs.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-CE0AeXyK.js +395 -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/a2a/__init__.py +213 -0
- solace_agent_mesh/common/a2a/a2a_llm.txt +182 -0
- solace_agent_mesh/common/a2a/artifact.py +328 -0
- solace_agent_mesh/common/a2a/events.py +183 -0
- solace_agent_mesh/common/a2a/message.py +307 -0
- solace_agent_mesh/common/a2a/protocol.py +513 -0
- solace_agent_mesh/common/a2a/task.py +127 -0
- solace_agent_mesh/common/a2a/translation.py +653 -0
- solace_agent_mesh/common/a2a/types.py +54 -0
- solace_agent_mesh/common/a2a_spec/a2a.json +2576 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +407 -0
- solace_agent_mesh/common/a2a_spec/schemas/agent_progress_update.json +18 -0
- solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +31 -0
- solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +18 -0
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +235 -0
- solace_agent_mesh/common/a2a_spec/schemas/tool_invocation_start.json +26 -0
- solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +25 -0
- solace_agent_mesh/common/agent_registry.py +1 -1
- solace_agent_mesh/common/common_llm.txt +192 -70
- solace_agent_mesh/common/data_parts.py +99 -0
- solace_agent_mesh/common/middleware/middleware_llm.txt +17 -17
- solace_agent_mesh/common/sac/__init__.py +0 -0
- solace_agent_mesh/common/sac/sac_llm.txt +71 -0
- solace_agent_mesh/common/sac/sam_component_base.py +252 -0
- solace_agent_mesh/common/services/providers/providers_llm.txt +51 -84
- solace_agent_mesh/common/services/services_llm.txt +206 -26
- solace_agent_mesh/common/utils/artifact_utils.py +29 -0
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +176 -80
- solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
- solace_agent_mesh/common/utils/utils_llm.txt +323 -42
- solace_agent_mesh/config_portal/backend/common.py +2 -2
- solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +1 -1
- 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/core_a2a/core_a2a_llm.txt +10 -8
- solace_agent_mesh/core_a2a/service.py +20 -44
- 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/base/app.py +27 -1
- solace_agent_mesh/gateway/base/base_llm.txt +177 -72
- solace_agent_mesh/gateway/base/component.py +294 -523
- solace_agent_mesh/gateway/gateway_llm.txt +299 -58
- 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 +371 -236
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +29 -29
- solace_agent_mesh/gateway/http_sse/dependencies.py +142 -39
- 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/http_sse_llm.txt +272 -36
- 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 +293 -91
- solace_agent_mesh/gateway/http_sse/routers/agents.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +137 -56
- solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +231 -5
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +199 -171
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
- solace_agent_mesh/gateway/http_sse/services/agent_service.py +1 -1
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +89 -135
- solace_agent_mesh/gateway/http_sse/services/task_service.py +2 -5
- 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/solace_agent_mesh_llm.txt +362 -0
- solace_agent_mesh/templates/gateway_component_template.py +149 -98
- solace_agent_mesh/templates/shared_config.yaml +4 -5
- solace_agent_mesh/templates/webui.yaml +8 -10
- {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/METADATA +9 -6
- {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/RECORD +197 -141
- solace_agent_mesh/assets/docs/assets/js/f284c35a.731836ad.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.3d0e7879.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.05d19492.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1757091012487.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1757091012487.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-D0FnP_W4.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-Do32sFPX.js +0 -708
- solace_agent_mesh/common/a2a_protocol.py +0 -564
- solace_agent_mesh/common/client/__init__.py +0 -4
- solace_agent_mesh/common/client/card_resolver.py +0 -21
- solace_agent_mesh/common/client/client.py +0 -85
- solace_agent_mesh/common/client/client_llm.txt +0 -133
- solace_agent_mesh/common/server/__init__.py +0 -4
- solace_agent_mesh/common/server/server.py +0 -122
- solace_agent_mesh/common/server/server_llm.txt +0 -169
- solace_agent_mesh/common/server/task_manager.py +0 -291
- solace_agent_mesh/common/server/utils.py +0 -28
- solace_agent_mesh/common/types.py +0 -411
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -80
- solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
- /solace_agent_mesh/assets/docs/assets/js/{main.3d0e7879.js.LICENSE.txt → main.08d30374.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,30 +8,28 @@ from fastapi import (
|
|
|
8
8
|
HTTPException,
|
|
9
9
|
Request as FastAPIRequest,
|
|
10
10
|
status,
|
|
11
|
-
Form,
|
|
12
|
-
File,
|
|
13
|
-
UploadFile,
|
|
14
11
|
)
|
|
15
|
-
from
|
|
16
|
-
from typing import List
|
|
12
|
+
from typing import Union
|
|
17
13
|
|
|
18
14
|
from solace_ai_connector.common.log import log
|
|
19
15
|
|
|
20
16
|
from ....gateway.http_sse.session_manager import SessionManager
|
|
21
17
|
from ....gateway.http_sse.services.task_service import TaskService
|
|
22
18
|
|
|
23
|
-
from
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
from a2a.types import (
|
|
20
|
+
CancelTaskRequest,
|
|
21
|
+
SendMessageRequest,
|
|
22
|
+
SendStreamingMessageRequest,
|
|
23
|
+
SendMessageSuccessResponse,
|
|
24
|
+
SendStreamingMessageSuccessResponse,
|
|
27
25
|
)
|
|
26
|
+
from ....common import a2a
|
|
28
27
|
|
|
29
28
|
from ....gateway.http_sse.dependencies import (
|
|
30
29
|
get_session_manager,
|
|
31
30
|
get_sac_component,
|
|
32
31
|
get_task_service,
|
|
33
32
|
)
|
|
34
|
-
from ....gateway.http_sse.routers.users import get_current_user
|
|
35
33
|
|
|
36
34
|
from typing import TYPE_CHECKING
|
|
37
35
|
|
|
@@ -41,29 +39,26 @@ if TYPE_CHECKING:
|
|
|
41
39
|
router = APIRouter()
|
|
42
40
|
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
async def _submit_task(
|
|
43
|
+
request: FastAPIRequest,
|
|
44
|
+
payload: Union[SendMessageRequest, SendStreamingMessageRequest],
|
|
45
|
+
session_manager: SessionManager,
|
|
46
|
+
component: "WebUIBackendComponent",
|
|
47
|
+
is_streaming: bool,
|
|
48
|
+
):
|
|
49
|
+
"""Helper to submit a task, handling both streaming and non-streaming cases."""
|
|
50
|
+
log_prefix = f"[POST /api/v1/message:{'stream' if is_streaming else 'send'}] "
|
|
46
51
|
|
|
47
|
-
agent_name
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
task_id: str = Field(..., description="The ID of the task to cancel.")
|
|
52
|
+
agent_name = None
|
|
53
|
+
if payload.params and payload.params.message and payload.params.message.metadata:
|
|
54
|
+
agent_name = payload.params.message.metadata.get("agent_name")
|
|
51
55
|
|
|
56
|
+
if not agent_name:
|
|
57
|
+
raise HTTPException(
|
|
58
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
59
|
+
detail="Missing 'agent_name' in request payload message metadata.",
|
|
60
|
+
)
|
|
52
61
|
|
|
53
|
-
@router.post("/send", response_model=JSONRPCResponse)
|
|
54
|
-
async def send_task_to_agent(
|
|
55
|
-
request: FastAPIRequest,
|
|
56
|
-
agent_name: str = Form(...),
|
|
57
|
-
message: str = Form(...),
|
|
58
|
-
files: List[UploadFile] = File([]),
|
|
59
|
-
session_manager: SessionManager = Depends(get_session_manager),
|
|
60
|
-
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
61
|
-
):
|
|
62
|
-
"""
|
|
63
|
-
Submits a non-streaming task request to the specified agent.
|
|
64
|
-
Accepts multipart/form-data.
|
|
65
|
-
"""
|
|
66
|
-
log_prefix = "[POST /api/v1/tasks/send] "
|
|
67
62
|
log.info("%sReceived request for agent: %s", log_prefix, agent_name)
|
|
68
63
|
|
|
69
64
|
try:
|
|
@@ -81,213 +76,246 @@ async def send_task_to_agent(
|
|
|
81
76
|
)
|
|
82
77
|
|
|
83
78
|
client_id = session_manager.get_a2a_client_id(request)
|
|
84
|
-
|
|
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)
|
|
85
101
|
|
|
86
102
|
log.info(
|
|
87
103
|
"%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
|
|
88
104
|
)
|
|
89
105
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
+
|
|
165
|
+
# Use the helper to get the unwrapped parts from the incoming message.
|
|
166
|
+
a2a_parts = a2a.get_parts_from_message(payload.params.message)
|
|
167
|
+
|
|
168
|
+
external_req_ctx = {
|
|
169
|
+
"app_name_for_artifacts": component.gateway_id,
|
|
170
|
+
"user_id_for_artifacts": client_id,
|
|
171
|
+
"a2a_session_id": session_id, # This may have been updated by persistence layer
|
|
172
|
+
"user_id_for_a2a": client_id,
|
|
173
|
+
"target_agent_name": agent_name,
|
|
96
174
|
}
|
|
97
175
|
|
|
98
|
-
target_agent, a2a_parts, external_req_ctx = (
|
|
99
|
-
await component._translate_external_input(external_event_data)
|
|
100
|
-
)
|
|
101
|
-
|
|
102
176
|
task_id = await component.submit_a2a_task(
|
|
103
|
-
target_agent_name=
|
|
177
|
+
target_agent_name=agent_name,
|
|
104
178
|
a2a_parts=a2a_parts,
|
|
105
179
|
external_request_context=external_req_ctx,
|
|
106
180
|
user_identity=user_identity,
|
|
107
|
-
is_streaming=
|
|
181
|
+
is_streaming=is_streaming,
|
|
108
182
|
)
|
|
109
183
|
|
|
110
184
|
log.info("%sTask submitted successfully. TaskID: %s", log_prefix, task_id)
|
|
111
185
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
raise HTTPException(
|
|
117
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
118
|
-
detail=e.model_dump(exclude_none=True),
|
|
186
|
+
task_object = a2a.create_initial_task(
|
|
187
|
+
task_id=task_id,
|
|
188
|
+
context_id=session_id,
|
|
189
|
+
agent_name=agent_name,
|
|
119
190
|
)
|
|
191
|
+
|
|
192
|
+
if is_streaming:
|
|
193
|
+
# The task_object already contains the contextId from create_initial_task
|
|
194
|
+
return a2a.create_send_streaming_message_success_response(
|
|
195
|
+
result=task_object, request_id=payload.id
|
|
196
|
+
)
|
|
197
|
+
else:
|
|
198
|
+
return a2a.create_send_message_success_response(
|
|
199
|
+
result=task_object, request_id=payload.id
|
|
200
|
+
)
|
|
201
|
+
|
|
120
202
|
except PermissionError as pe:
|
|
121
203
|
log.warning("%sPermission denied: %s", log_prefix, str(pe))
|
|
122
204
|
raise HTTPException(
|
|
123
205
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
124
206
|
detail=str(pe),
|
|
125
207
|
)
|
|
126
|
-
except InternalError as e:
|
|
127
|
-
log.error(
|
|
128
|
-
"%sInternal error submitting task: %s", log_prefix, e.message, exc_info=True
|
|
129
|
-
)
|
|
130
|
-
raise HTTPException(
|
|
131
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
132
|
-
detail=e.model_dump(exclude_none=True),
|
|
133
|
-
)
|
|
134
208
|
except Exception as e:
|
|
135
209
|
log.exception("%sUnexpected error submitting task: %s", log_prefix, e)
|
|
136
|
-
error_resp =
|
|
210
|
+
error_resp = a2a.create_internal_error(
|
|
211
|
+
message="Unexpected server error: %s" % e
|
|
212
|
+
)
|
|
137
213
|
raise HTTPException(
|
|
138
214
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
139
215
|
detail=error_resp.model_dump(exclude_none=True),
|
|
140
216
|
)
|
|
141
217
|
|
|
142
218
|
|
|
143
|
-
@router.post("/
|
|
144
|
-
async def
|
|
219
|
+
@router.post("/message:send", response_model=SendMessageSuccessResponse)
|
|
220
|
+
async def send_task_to_agent(
|
|
145
221
|
request: FastAPIRequest,
|
|
146
|
-
|
|
147
|
-
message: str = Form(...),
|
|
148
|
-
files: List[UploadFile] = File([]),
|
|
222
|
+
payload: SendMessageRequest,
|
|
149
223
|
session_manager: SessionManager = Depends(get_session_manager),
|
|
150
224
|
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
151
|
-
user: dict = Depends(get_current_user),
|
|
152
225
|
):
|
|
153
226
|
"""
|
|
154
|
-
Submits a streaming task request
|
|
155
|
-
Accepts
|
|
156
|
-
The client should subsequently connect to the SSE endpoint using the returned taskId.
|
|
227
|
+
Submits a non-streaming task request to the specified agent.
|
|
228
|
+
Accepts application/json.
|
|
157
229
|
"""
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
raise HTTPException(
|
|
166
|
-
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
167
|
-
detail="User authentication failed or identity not found.",
|
|
168
|
-
)
|
|
169
|
-
log.info(
|
|
170
|
-
"%sAuthenticated user identity: %s",
|
|
171
|
-
log_prefix,
|
|
172
|
-
user_identity.get("id", "unknown"),
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
client_id = session_manager.get_a2a_client_id(request)
|
|
176
|
-
session_id = session_manager.ensure_a2a_session(request)
|
|
177
|
-
|
|
178
|
-
log.info(
|
|
179
|
-
"%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
|
|
180
|
-
)
|
|
230
|
+
return await _submit_task(
|
|
231
|
+
request=request,
|
|
232
|
+
payload=payload,
|
|
233
|
+
session_manager=session_manager,
|
|
234
|
+
component=component,
|
|
235
|
+
is_streaming=False,
|
|
236
|
+
)
|
|
181
237
|
|
|
182
|
-
external_event_data = {
|
|
183
|
-
"agent_name": agent_name,
|
|
184
|
-
"message": message,
|
|
185
|
-
"files": files,
|
|
186
|
-
"client_id": client_id,
|
|
187
|
-
"a2a_session_id": session_id,
|
|
188
|
-
}
|
|
189
238
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
239
|
+
@router.post("/message:stream", response_model=SendStreamingMessageSuccessResponse)
|
|
240
|
+
async def subscribe_task_from_agent(
|
|
241
|
+
request: FastAPIRequest,
|
|
242
|
+
payload: SendStreamingMessageRequest,
|
|
243
|
+
session_manager: SessionManager = Depends(get_session_manager),
|
|
244
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
245
|
+
):
|
|
246
|
+
"""
|
|
247
|
+
Submits a streaming task request to the specified agent.
|
|
248
|
+
Accepts application/json.
|
|
249
|
+
The client should subsequently connect to the SSE endpoint using the returned taskId.
|
|
250
|
+
"""
|
|
251
|
+
return await _submit_task(
|
|
252
|
+
request=request,
|
|
253
|
+
payload=payload,
|
|
254
|
+
session_manager=session_manager,
|
|
255
|
+
component=component,
|
|
256
|
+
is_streaming=True,
|
|
257
|
+
)
|
|
201
258
|
|
|
202
|
-
log.info(
|
|
203
|
-
"%sStreaming task submitted successfully. TaskID: %s", log_prefix, task_id
|
|
204
|
-
)
|
|
205
259
|
|
|
206
|
-
|
|
260
|
+
@router.post("/tasks/{taskId}:cancel", status_code=status.HTTP_202_ACCEPTED)
|
|
261
|
+
async def cancel_agent_task(
|
|
262
|
+
request: FastAPIRequest,
|
|
263
|
+
taskId: str,
|
|
264
|
+
payload: CancelTaskRequest,
|
|
265
|
+
session_manager: SessionManager = Depends(get_session_manager),
|
|
266
|
+
task_service: TaskService = Depends(get_task_service),
|
|
267
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
268
|
+
):
|
|
269
|
+
"""
|
|
270
|
+
Sends a cancellation request for a specific task to the specified agent.
|
|
271
|
+
Returns 202 Accepted, as cancellation is asynchronous.
|
|
272
|
+
"""
|
|
273
|
+
log_prefix = f"[POST /api/v1/tasks/{taskId}:cancel] "
|
|
274
|
+
log.info("%sReceived cancellation request.", log_prefix)
|
|
207
275
|
|
|
208
|
-
|
|
209
|
-
log.warning("%sInvalid request: %s", log_prefix, e.message, exc_info=True)
|
|
276
|
+
if taskId != payload.params.id:
|
|
210
277
|
raise HTTPException(
|
|
211
278
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
212
|
-
detail=
|
|
279
|
+
detail="Task ID in URL path does not match task ID in payload.",
|
|
213
280
|
)
|
|
214
|
-
|
|
215
|
-
|
|
281
|
+
|
|
282
|
+
context = component.task_context_manager.get_context(taskId)
|
|
283
|
+
if not context:
|
|
216
284
|
raise HTTPException(
|
|
217
|
-
status_code=status.
|
|
218
|
-
detail=
|
|
285
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
286
|
+
detail=f"No active task context found for task ID: {taskId}",
|
|
219
287
|
)
|
|
220
|
-
|
|
288
|
+
|
|
289
|
+
agent_name = context.get("target_agent_name")
|
|
290
|
+
if not agent_name:
|
|
221
291
|
log.error(
|
|
222
|
-
"%
|
|
292
|
+
"%sCould not determine target agent for task %s. Context is missing 'target_agent_name'.",
|
|
223
293
|
log_prefix,
|
|
224
|
-
|
|
225
|
-
exc_info=True,
|
|
226
|
-
)
|
|
227
|
-
raise HTTPException(
|
|
228
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
229
|
-
detail=e.model_dump(exclude_none=True),
|
|
294
|
+
taskId,
|
|
230
295
|
)
|
|
231
|
-
except Exception as e:
|
|
232
|
-
log.exception("%sUnexpected error submitting streaming task: %s", log_prefix, e)
|
|
233
|
-
error_resp = InternalError(message="Unexpected server error: %s" % e)
|
|
234
296
|
raise HTTPException(
|
|
235
297
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
236
|
-
detail=
|
|
298
|
+
detail="Could not determine target agent for the task.",
|
|
237
299
|
)
|
|
238
300
|
|
|
239
|
-
|
|
240
|
-
@router.post("/cancel", status_code=status.HTTP_202_ACCEPTED)
|
|
241
|
-
async def cancel_agent_task(
|
|
242
|
-
request: FastAPIRequest,
|
|
243
|
-
payload: CancelTaskApiPayload,
|
|
244
|
-
session_manager: SessionManager = Depends(get_session_manager),
|
|
245
|
-
task_service: TaskService = Depends(get_task_service),
|
|
246
|
-
):
|
|
247
|
-
"""
|
|
248
|
-
Sends a cancellation request for a specific task to the specified agent.
|
|
249
|
-
Returns 202 Accepted, as cancellation is asynchronous.
|
|
250
|
-
"""
|
|
251
|
-
log_prefix = "[POST /api/v1/tasks/cancel][Task:%s] " % payload.task_id
|
|
252
|
-
log.info(
|
|
253
|
-
"%sReceived cancellation request for agent: %s", log_prefix, payload.agent_name
|
|
254
|
-
)
|
|
301
|
+
log.info("%sTarget agent for cancellation is '%s'", log_prefix, agent_name)
|
|
255
302
|
|
|
256
303
|
try:
|
|
257
304
|
client_id = session_manager.get_a2a_client_id(request)
|
|
258
305
|
|
|
259
306
|
log.info("%sUsing ClientID: %s", log_prefix, client_id)
|
|
260
307
|
|
|
261
|
-
await task_service.cancel_task(
|
|
262
|
-
payload.agent_name, payload.task_id, client_id, client_id
|
|
263
|
-
)
|
|
308
|
+
await task_service.cancel_task(agent_name, taskId, client_id, client_id)
|
|
264
309
|
|
|
265
310
|
log.info("%sCancellation request published successfully.", log_prefix)
|
|
266
311
|
|
|
267
312
|
return {"message": "Cancellation request sent"}
|
|
268
313
|
|
|
269
|
-
except InvalidRequestError as e:
|
|
270
|
-
log.warning(
|
|
271
|
-
"%sInvalid cancellation request: %s", log_prefix, e.message, exc_info=True
|
|
272
|
-
)
|
|
273
|
-
raise HTTPException(
|
|
274
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
275
|
-
detail=e.model_dump(exclude_none=True),
|
|
276
|
-
)
|
|
277
|
-
except InternalError as e:
|
|
278
|
-
log.error(
|
|
279
|
-
"%sInternal error sending cancellation: %s",
|
|
280
|
-
log_prefix,
|
|
281
|
-
e.message,
|
|
282
|
-
exc_info=True,
|
|
283
|
-
)
|
|
284
|
-
raise HTTPException(
|
|
285
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
286
|
-
detail=e.model_dump(exclude_none=True),
|
|
287
|
-
)
|
|
288
314
|
except Exception as e:
|
|
289
315
|
log.exception("%sUnexpected error sending cancellation: %s", log_prefix, e)
|
|
290
|
-
error_resp =
|
|
316
|
+
error_resp = a2a.create_internal_error(
|
|
317
|
+
message="Unexpected server error: %s" % e
|
|
318
|
+
)
|
|
291
319
|
raise HTTPException(
|
|
292
320
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
293
321
|
detail=error_resp.model_dump(exclude_none=True),
|
|
@@ -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
|
|