solace-agent-mesh 1.4.12__py3-none-any.whl → 1.5.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 +3 -4
- solace_agent_mesh/agent/adk/adk_llm_detail.txt +566 -0
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +1 -1
- solace_agent_mesh/agent/adk/callbacks.py +51 -2
- solace_agent_mesh/agent/adk/models/lite_llm.py +1 -0
- solace_agent_mesh/agent/adk/models/models_llm.txt +1 -2
- solace_agent_mesh/agent/agent_llm.txt +1 -1
- solace_agent_mesh/agent/agent_llm_detail.txt +1702 -0
- solace_agent_mesh/agent/protocol/event_handlers.py +2 -13
- solace_agent_mesh/agent/protocol/protocol_llm.txt +15 -2
- solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +92 -0
- solace_agent_mesh/agent/sac/component.py +51 -21
- solace_agent_mesh/agent/sac/sac_llm.txt +15 -1
- solace_agent_mesh/agent/sac/sac_llm_detail.txt +200 -0
- solace_agent_mesh/agent/sac/task_execution_context.py +73 -0
- solace_agent_mesh/agent/testing/testing_llm_detail.txt +68 -0
- solace_agent_mesh/agent/tools/tools_llm.txt +148 -154
- solace_agent_mesh/agent/tools/tools_llm_detail.txt +274 -0
- solace_agent_mesh/agent/utils/utils_llm.txt +1 -1
- solace_agent_mesh/agent/utils/utils_llm_detail.txt +149 -0
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/483cef9a.bf9398af.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{main.f67fc9f4.js → main.0c149855.js} +2 -2
- solace_agent_mesh/assets/docs/assets/js/{runtime~main.40527046.js → runtime~main.c66557e4.js} +1 -1
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/rbac-setup-guilde/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +8 -4
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/litellm_models/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +3 -3
- solace_agent_mesh/assets/docs/lunr-index-1760032255022.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1760032255022.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-j1LW-wlq.js → authCallback-DwrxZE0E.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-B9p_nFNA.js → client-DarGQzyw.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-CZbpmwfA.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C__uuUkB.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{vendor-CS5YMf8a.js → vendor-BKIeiHj_.js} +80 -70
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
- solace_agent_mesh/common/a2a/a2a_llm.txt +1 -1
- solace_agent_mesh/common/a2a/a2a_llm_detail.txt +193 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +1 -1
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +736 -0
- solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +23 -0
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +93 -15
- solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +23 -0
- solace_agent_mesh/common/common_llm.txt +24 -39
- solace_agent_mesh/common/common_llm_detail.txt +2562 -0
- solace_agent_mesh/common/data_parts.py +9 -1
- solace_agent_mesh/common/middleware/middleware_llm_detail.txt +185 -0
- solace_agent_mesh/common/sac/sac_llm.txt +1 -1
- solace_agent_mesh/common/sac/sac_llm_detail.txt +82 -0
- solace_agent_mesh/common/sam_events/sam_events_llm.txt +104 -0
- solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +115 -0
- solace_agent_mesh/common/services/services_llm.txt +57 -6
- solace_agent_mesh/common/services/services_llm_detail.txt +459 -0
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +1 -1
- solace_agent_mesh/common/utils/utils_llm.txt +75 -87
- solace_agent_mesh/common/utils/utils_llm_detail.txt +572 -0
- solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +101 -0
- solace_agent_mesh/gateway/base/app.py +1 -1
- solace_agent_mesh/gateway/base/base_llm.txt +1 -1
- solace_agent_mesh/gateway/base/base_llm_detail.txt +235 -0
- solace_agent_mesh/gateway/gateway_llm.txt +242 -235
- solace_agent_mesh/gateway/gateway_llm_detail.txt +3885 -0
- solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +295 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +10 -1
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251006_98882922fa59_add_tasks_events_feedback_chat_tasks.py +190 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +155 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +1 -1
- solace_agent_mesh/gateway/http_sse/app.py +148 -2
- solace_agent_mesh/gateway/http_sse/component.py +368 -60
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +46 -6
- solace_agent_mesh/gateway/http_sse/components/task_logger_forwarder.py +108 -0
- solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +1 -1
- solace_agent_mesh/gateway/http_sse/dependencies.py +116 -26
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +172 -172
- solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +3278 -0
- solace_agent_mesh/gateway/http_sse/main.py +146 -41
- solace_agent_mesh/gateway/http_sse/repository/__init__.py +3 -12
- solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +103 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/__init__.py +5 -3
- solace_agent_mesh/gateway/http_sse/repository/entities/chat_task.py +75 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +263 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/feedback.py +20 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session_history.py +0 -16
- solace_agent_mesh/gateway/http_sse/repository/entities/task.py +25 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/task_event.py +21 -0
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +81 -0
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +73 -18
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -5
- solace_agent_mesh/gateway/http_sse/repository/models/chat_task_model.py +31 -0
- solace_agent_mesh/gateway/http_sse/repository/models/feedback_model.py +21 -0
- solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +266 -0
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +3 -3
- solace_agent_mesh/gateway/http_sse/repository/models/task_event_model.py +25 -0
- solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +32 -0
- solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +340 -0
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +4 -53
- solace_agent_mesh/gateway/http_sse/repository/task_repository.py +173 -0
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/config.py +26 -4
- solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +346 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +3 -3
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +83 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +2 -10
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/task_requests.py +58 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/__init__.py +5 -3
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +107 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +1 -15
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/task_responses.py +30 -0
- solace_agent_mesh/gateway/http_sse/routers/feedback.py +37 -0
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +255 -204
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +220 -40
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +168 -42
- solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +272 -0
- solace_agent_mesh/gateway/http_sse/services/feedback_service.py +241 -0
- solace_agent_mesh/gateway/http_sse/services/people_service.py +0 -80
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +177 -13
- solace_agent_mesh/gateway/http_sse/services/session_service.py +151 -84
- solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +317 -0
- solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +25 -14
- solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +285 -0
- solace_agent_mesh/gateway/http_sse/shared/types.py +7 -0
- solace_agent_mesh/gateway/http_sse/utils/__init__.py +1 -0
- solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +32 -0
- solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +47 -0
- solace_agent_mesh/solace_agent_mesh_llm.txt +1 -1
- solace_agent_mesh/solace_agent_mesh_llm_detail.txt +8599 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/METADATA +1 -1
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/RECORD +172 -124
- solace_agent_mesh/agent/adk/invocation_monitor.py +0 -295
- solace_agent_mesh/assets/docs/assets/js/483cef9a.4736f2d8.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1759936913198.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1759936913198.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-ChRwcV89.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-DnnE01OM.js +0 -339
- solace_agent_mesh/gateway/http_sse/repository/entities/message.py +0 -41
- solace_agent_mesh/gateway/http_sse/repository/message_repository.py +0 -84
- solace_agent_mesh/gateway/http_sse/repository/models/message_model.py +0 -45
- /solace_agent_mesh/assets/docs/assets/js/{main.f67fc9f4.js.LICENSE.txt → main.0c149855.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,14 +8,16 @@ from ..shared.auth_utils import get_current_user
|
|
|
8
8
|
from ..shared.pagination import DataResponse, PaginatedResponse, PaginationParams
|
|
9
9
|
from ..shared.response_utils import create_data_response
|
|
10
10
|
from .dto.requests.session_requests import (
|
|
11
|
-
GetSessionHistoryRequest,
|
|
12
11
|
GetSessionRequest,
|
|
13
12
|
UpdateSessionRequest,
|
|
14
13
|
)
|
|
15
|
-
from .dto.
|
|
14
|
+
from .dto.requests.task_requests import SaveTaskRequest
|
|
15
|
+
from .dto.responses.session_responses import SessionResponse
|
|
16
|
+
from .dto.responses.task_responses import TaskResponse, TaskListResponse
|
|
16
17
|
|
|
17
18
|
router = APIRouter()
|
|
18
19
|
|
|
20
|
+
SESSION_NOT_FOUND_MSG = "Session not found."
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
@router.get("/sessions", response_model=PaginatedResponse[SessionResponse])
|
|
@@ -27,7 +29,6 @@ async def get_all_sessions(
|
|
|
27
29
|
session_service: SessionService = Depends(get_session_business_service),
|
|
28
30
|
):
|
|
29
31
|
user_id = user.get("id")
|
|
30
|
-
log.info(f"User '{user_id}' is listing sessions with pagination (page={page_number}, size={page_size})")
|
|
31
32
|
|
|
32
33
|
try:
|
|
33
34
|
pagination = PaginationParams(page_number=page_number, page_size=page_size)
|
|
@@ -52,7 +53,7 @@ async def get_all_sessions(
|
|
|
52
53
|
raise HTTPException(
|
|
53
54
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
54
55
|
detail="Failed to retrieve sessions",
|
|
55
|
-
)
|
|
56
|
+
) from e
|
|
56
57
|
|
|
57
58
|
|
|
58
59
|
@router.get("/sessions/{session_id}", response_model=DataResponse[SessionResponse])
|
|
@@ -63,7 +64,6 @@ async def get_session(
|
|
|
63
64
|
session_service: SessionService = Depends(get_session_business_service),
|
|
64
65
|
):
|
|
65
66
|
user_id = user.get("id")
|
|
66
|
-
log.info("User %s attempting to fetch session_id: %s", user_id, session_id)
|
|
67
67
|
|
|
68
68
|
try:
|
|
69
69
|
if (
|
|
@@ -72,7 +72,7 @@ async def get_session(
|
|
|
72
72
|
or session_id in ["null", "undefined"]
|
|
73
73
|
):
|
|
74
74
|
raise HTTPException(
|
|
75
|
-
status_code=status.HTTP_404_NOT_FOUND, detail=
|
|
75
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
76
76
|
)
|
|
77
77
|
|
|
78
78
|
request_dto = GetSessionRequest(session_id=session_id, user_id=user_id)
|
|
@@ -83,7 +83,7 @@ async def get_session(
|
|
|
83
83
|
|
|
84
84
|
if not session_domain:
|
|
85
85
|
raise HTTPException(
|
|
86
|
-
status_code=status.HTTP_404_NOT_FOUND, detail=
|
|
86
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
87
87
|
)
|
|
88
88
|
|
|
89
89
|
log.info("User %s authorized. Fetching session_id: %s", user_id, session_id)
|
|
@@ -111,19 +111,27 @@ async def get_session(
|
|
|
111
111
|
raise HTTPException(
|
|
112
112
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
113
113
|
detail="Failed to retrieve session",
|
|
114
|
-
)
|
|
114
|
+
) from e
|
|
115
115
|
|
|
116
116
|
|
|
117
|
-
@router.
|
|
118
|
-
async def
|
|
117
|
+
@router.post("/sessions/{session_id}/chat-tasks", response_model=TaskResponse)
|
|
118
|
+
async def save_task(
|
|
119
119
|
session_id: str,
|
|
120
|
+
request: SaveTaskRequest,
|
|
120
121
|
db: Session = Depends(get_db),
|
|
121
122
|
user: dict = Depends(get_current_user),
|
|
122
123
|
session_service: SessionService = Depends(get_session_business_service),
|
|
123
124
|
):
|
|
125
|
+
"""
|
|
126
|
+
Save a complete task interaction (upsert).
|
|
127
|
+
Creates a new task or updates an existing one.
|
|
128
|
+
"""
|
|
124
129
|
user_id = user.get("id")
|
|
125
130
|
log.info(
|
|
126
|
-
"User %s attempting to
|
|
131
|
+
"User %s attempting to save task %s for session %s",
|
|
132
|
+
user_id,
|
|
133
|
+
request.task_id,
|
|
134
|
+
session_id,
|
|
127
135
|
)
|
|
128
136
|
|
|
129
137
|
try:
|
|
@@ -133,44 +141,203 @@ async def get_session_history(
|
|
|
133
141
|
or session_id in ["null", "undefined"]
|
|
134
142
|
):
|
|
135
143
|
raise HTTPException(
|
|
136
|
-
status_code=status.HTTP_404_NOT_FOUND, detail=
|
|
144
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
137
145
|
)
|
|
138
146
|
|
|
139
|
-
|
|
147
|
+
# Check if task already exists to determine status code
|
|
148
|
+
from ..repository.chat_task_repository import ChatTaskRepository
|
|
149
|
+
|
|
150
|
+
task_repo = ChatTaskRepository(db)
|
|
151
|
+
existing_task = task_repo.find_by_id(request.task_id, user_id)
|
|
152
|
+
is_update = existing_task is not None
|
|
140
153
|
|
|
141
|
-
|
|
154
|
+
# Save the task - pass strings directly
|
|
155
|
+
saved_task = session_service.save_task(
|
|
142
156
|
db=db,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
157
|
+
task_id=request.task_id,
|
|
158
|
+
session_id=session_id,
|
|
159
|
+
user_id=user_id,
|
|
160
|
+
user_message=request.user_message,
|
|
161
|
+
message_bubbles=request.message_bubbles, # Already a string
|
|
162
|
+
task_metadata=request.task_metadata, # Already a string
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
log.info(
|
|
166
|
+
"Task %s %s successfully for session %s",
|
|
167
|
+
request.task_id,
|
|
168
|
+
"updated" if is_update else "created",
|
|
169
|
+
session_id,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Convert to response DTO
|
|
173
|
+
response = TaskResponse(
|
|
174
|
+
task_id=saved_task.id,
|
|
175
|
+
session_id=saved_task.session_id,
|
|
176
|
+
user_message=saved_task.user_message,
|
|
177
|
+
message_bubbles=saved_task.message_bubbles,
|
|
178
|
+
task_metadata=saved_task.task_metadata,
|
|
179
|
+
created_time=saved_task.created_time,
|
|
180
|
+
updated_time=saved_task.updated_time,
|
|
146
181
|
)
|
|
147
182
|
|
|
148
|
-
|
|
183
|
+
return response
|
|
184
|
+
|
|
185
|
+
except ValueError as e:
|
|
186
|
+
log.warning("Validation error saving task %s: %s", request.task_id, e)
|
|
187
|
+
raise HTTPException(
|
|
188
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e)
|
|
189
|
+
) from e
|
|
190
|
+
except HTTPException:
|
|
191
|
+
raise
|
|
192
|
+
except Exception as e:
|
|
193
|
+
log.error(
|
|
194
|
+
"Error saving task %s for session %s for user %s: %s",
|
|
195
|
+
request.task_id,
|
|
196
|
+
session_id,
|
|
197
|
+
user_id,
|
|
198
|
+
e,
|
|
199
|
+
)
|
|
200
|
+
raise HTTPException(
|
|
201
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
202
|
+
detail="Failed to save task",
|
|
203
|
+
) from e
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@router.get("/sessions/{session_id}/chat-tasks", response_model=TaskListResponse)
|
|
207
|
+
async def get_session_tasks(
|
|
208
|
+
session_id: str,
|
|
209
|
+
db: Session = Depends(get_db),
|
|
210
|
+
user: dict = Depends(get_current_user),
|
|
211
|
+
session_service: SessionService = Depends(get_session_business_service),
|
|
212
|
+
):
|
|
213
|
+
"""
|
|
214
|
+
Get all tasks for a session.
|
|
215
|
+
Returns tasks in chronological order.
|
|
216
|
+
"""
|
|
217
|
+
user_id = user.get("id")
|
|
218
|
+
log.info(
|
|
219
|
+
"User %s attempting to fetch tasks for session_id: %s", user_id, session_id
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
if (
|
|
224
|
+
not session_id
|
|
225
|
+
or session_id.strip() == ""
|
|
226
|
+
or session_id in ["null", "undefined"]
|
|
227
|
+
):
|
|
149
228
|
raise HTTPException(
|
|
150
|
-
status_code=status.HTTP_404_NOT_FOUND, detail=
|
|
229
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
151
230
|
)
|
|
152
231
|
|
|
232
|
+
# Get tasks from service
|
|
233
|
+
tasks = session_service.get_session_tasks(
|
|
234
|
+
db=db, session_id=session_id, user_id=user_id
|
|
235
|
+
)
|
|
236
|
+
|
|
153
237
|
log.info(
|
|
154
|
-
"User %s authorized.
|
|
238
|
+
"User %s authorized. Fetched %d tasks for session_id: %s",
|
|
155
239
|
user_id,
|
|
240
|
+
len(tasks),
|
|
241
|
+
session_id,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Convert to response DTOs
|
|
245
|
+
task_responses = []
|
|
246
|
+
for task in tasks:
|
|
247
|
+
task_response = TaskResponse(
|
|
248
|
+
task_id=task.id,
|
|
249
|
+
session_id=task.session_id,
|
|
250
|
+
user_message=task.user_message,
|
|
251
|
+
message_bubbles=task.message_bubbles,
|
|
252
|
+
task_metadata=task.task_metadata,
|
|
253
|
+
created_time=task.created_time,
|
|
254
|
+
updated_time=task.updated_time,
|
|
255
|
+
)
|
|
256
|
+
task_responses.append(task_response)
|
|
257
|
+
|
|
258
|
+
return TaskListResponse(tasks=task_responses)
|
|
259
|
+
|
|
260
|
+
except ValueError as e:
|
|
261
|
+
log.warning("Validation error fetching tasks for session %s: %s", session_id, e)
|
|
262
|
+
raise HTTPException(
|
|
263
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
264
|
+
) from e
|
|
265
|
+
except HTTPException:
|
|
266
|
+
raise
|
|
267
|
+
except Exception as e:
|
|
268
|
+
log.error(
|
|
269
|
+
"Error fetching tasks for session %s for user %s: %s",
|
|
156
270
|
session_id,
|
|
271
|
+
user_id,
|
|
272
|
+
e,
|
|
157
273
|
)
|
|
274
|
+
raise HTTPException(
|
|
275
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
276
|
+
detail="Failed to retrieve session tasks",
|
|
277
|
+
) from e
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
@router.get("/sessions/{session_id}/messages")
|
|
281
|
+
async def get_session_history(
|
|
282
|
+
session_id: str,
|
|
283
|
+
db: Session = Depends(get_db),
|
|
284
|
+
user: dict = Depends(get_current_user),
|
|
285
|
+
session_service: SessionService = Depends(get_session_business_service),
|
|
286
|
+
):
|
|
287
|
+
"""
|
|
288
|
+
Get session message history.
|
|
289
|
+
Loads from chat_tasks and flattens message_bubbles for backward compatibility.
|
|
290
|
+
"""
|
|
291
|
+
user_id = user.get("id")
|
|
292
|
+
log.info(
|
|
293
|
+
"User %s attempting to fetch history for session_id: %s", user_id, session_id
|
|
294
|
+
)
|
|
158
295
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
message_type=message_domain.message_type,
|
|
168
|
-
created_time=message_domain.created_time,
|
|
296
|
+
try:
|
|
297
|
+
if (
|
|
298
|
+
not session_id
|
|
299
|
+
or session_id.strip() == ""
|
|
300
|
+
or session_id in ["null", "undefined"]
|
|
301
|
+
):
|
|
302
|
+
raise HTTPException(
|
|
303
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
169
304
|
)
|
|
170
|
-
message_responses.append(message_response)
|
|
171
305
|
|
|
172
|
-
|
|
306
|
+
# Use task-based message retrieval (returns list of dicts)
|
|
307
|
+
messages = session_service.get_session_messages_from_tasks(
|
|
308
|
+
db=db, session_id=session_id, user_id=user_id
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
log.info(
|
|
312
|
+
"User %s authorized. Fetched %d messages for session_id: %s",
|
|
313
|
+
user_id,
|
|
314
|
+
len(messages),
|
|
315
|
+
session_id,
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
# Convert snake_case to camelCase for backwards compatibility
|
|
319
|
+
camel_case_messages = []
|
|
320
|
+
for msg in messages:
|
|
321
|
+
camel_msg = {
|
|
322
|
+
"id": msg["id"],
|
|
323
|
+
"sessionId": msg["session_id"],
|
|
324
|
+
"message": msg["message"],
|
|
325
|
+
"senderType": msg["sender_type"],
|
|
326
|
+
"senderName": msg["sender_name"],
|
|
327
|
+
"messageType": msg["message_type"],
|
|
328
|
+
"createdTime": msg["created_time"],
|
|
329
|
+
}
|
|
330
|
+
camel_case_messages.append(camel_msg)
|
|
331
|
+
|
|
332
|
+
return camel_case_messages
|
|
173
333
|
|
|
334
|
+
except ValueError as e:
|
|
335
|
+
log.warning(
|
|
336
|
+
"Validation error fetching history for session %s: %s", session_id, e
|
|
337
|
+
)
|
|
338
|
+
raise HTTPException(
|
|
339
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
340
|
+
) from e
|
|
174
341
|
except HTTPException:
|
|
175
342
|
raise
|
|
176
343
|
except Exception as e:
|
|
@@ -183,7 +350,7 @@ async def get_session_history(
|
|
|
183
350
|
raise HTTPException(
|
|
184
351
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
185
352
|
detail="Failed to retrieve session history",
|
|
186
|
-
)
|
|
353
|
+
) from e
|
|
187
354
|
|
|
188
355
|
|
|
189
356
|
@router.patch("/sessions/{session_id}", response_model=SessionResponse)
|
|
@@ -204,7 +371,7 @@ async def update_session_name(
|
|
|
204
371
|
or session_id in ["null", "undefined"]
|
|
205
372
|
):
|
|
206
373
|
raise HTTPException(
|
|
207
|
-
status_code=status.HTTP_404_NOT_FOUND, detail=
|
|
374
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
208
375
|
)
|
|
209
376
|
|
|
210
377
|
request_dto = UpdateSessionRequest(
|
|
@@ -220,7 +387,7 @@ async def update_session_name(
|
|
|
220
387
|
|
|
221
388
|
if not updated_domain:
|
|
222
389
|
raise HTTPException(
|
|
223
|
-
status_code=status.HTTP_404_NOT_FOUND, detail=
|
|
390
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
224
391
|
)
|
|
225
392
|
|
|
226
393
|
log.info("Session %s updated successfully", session_id)
|
|
@@ -240,7 +407,7 @@ async def update_session_name(
|
|
|
240
407
|
log.warning("Validation error updating session %s: %s", session_id, e)
|
|
241
408
|
raise HTTPException(
|
|
242
409
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e)
|
|
243
|
-
)
|
|
410
|
+
) from e
|
|
244
411
|
except Exception as e:
|
|
245
412
|
log.error(
|
|
246
413
|
"Error updating session %s for user %s: %s",
|
|
@@ -251,7 +418,7 @@ async def update_session_name(
|
|
|
251
418
|
raise HTTPException(
|
|
252
419
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
253
420
|
detail="Failed to update session",
|
|
254
|
-
)
|
|
421
|
+
) from e
|
|
255
422
|
|
|
256
423
|
|
|
257
424
|
@router.delete("/sessions/{session_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
@@ -265,20 +432,33 @@ async def delete_session(
|
|
|
265
432
|
log.info("User %s attempting to delete session %s", user_id, session_id)
|
|
266
433
|
|
|
267
434
|
try:
|
|
435
|
+
if (
|
|
436
|
+
not session_id
|
|
437
|
+
or session_id.strip() == ""
|
|
438
|
+
or session_id in ["null", "undefined"]
|
|
439
|
+
):
|
|
440
|
+
raise HTTPException(
|
|
441
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
442
|
+
)
|
|
443
|
+
|
|
268
444
|
deleted = session_service.delete_session_with_notifications(
|
|
269
445
|
db=db, session_id=session_id, user_id=user_id
|
|
270
446
|
)
|
|
271
447
|
|
|
272
448
|
if not deleted:
|
|
273
449
|
raise HTTPException(
|
|
274
|
-
status_code=status.HTTP_404_NOT_FOUND, detail=
|
|
450
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
275
451
|
)
|
|
276
452
|
|
|
277
453
|
log.info("Session %s deleted successfully", session_id)
|
|
278
454
|
|
|
455
|
+
except HTTPException:
|
|
456
|
+
raise
|
|
279
457
|
except ValueError as e:
|
|
280
458
|
log.warning("Validation error deleting session %s: %s", session_id, e)
|
|
281
|
-
raise HTTPException(
|
|
459
|
+
raise HTTPException(
|
|
460
|
+
status_code=status.HTTP_400_BAD_REQUEST, detail=str(e)
|
|
461
|
+
) from e
|
|
282
462
|
except Exception as e:
|
|
283
463
|
log.error(
|
|
284
464
|
"Error deleting session %s for user %s: %s",
|
|
@@ -289,4 +469,4 @@ async def delete_session(
|
|
|
289
469
|
raise HTTPException(
|
|
290
470
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
291
471
|
detail="Failed to delete session",
|
|
292
|
-
)
|
|
472
|
+
) from e
|
|
@@ -2,20 +2,28 @@
|
|
|
2
2
|
API Router for submitting and managing tasks to agents.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import yaml
|
|
6
|
+
from datetime import datetime
|
|
5
7
|
from fastapi import (
|
|
6
8
|
APIRouter,
|
|
7
9
|
Depends,
|
|
8
10
|
HTTPException,
|
|
9
11
|
Request as FastAPIRequest,
|
|
12
|
+
Response,
|
|
10
13
|
status,
|
|
11
14
|
)
|
|
12
|
-
from
|
|
15
|
+
from fastapi.exceptions import RequestValidationError
|
|
16
|
+
from typing import List, Optional, Union
|
|
13
17
|
|
|
14
18
|
from solace_ai_connector.common.log import log
|
|
15
19
|
|
|
16
20
|
from ....gateway.http_sse.session_manager import SessionManager
|
|
17
21
|
from ....gateway.http_sse.services.task_service import TaskService
|
|
18
22
|
from ....gateway.http_sse.services.session_service import SessionService
|
|
23
|
+
from ....gateway.http_sse.repository.interfaces import ITaskRepository
|
|
24
|
+
from ....gateway.http_sse.repository.entities import Task
|
|
25
|
+
from ....gateway.http_sse.shared.types import PaginationParams, UserId
|
|
26
|
+
from ..utils.stim_utils import create_stim_from_task_data
|
|
19
27
|
|
|
20
28
|
from a2a.types import (
|
|
21
29
|
CancelTaskRequest,
|
|
@@ -31,7 +39,12 @@ from ....gateway.http_sse.dependencies import (
|
|
|
31
39
|
get_sac_component,
|
|
32
40
|
get_task_service,
|
|
33
41
|
get_session_business_service,
|
|
42
|
+
get_task_repository,
|
|
43
|
+
get_user_id,
|
|
44
|
+
get_user_config,
|
|
45
|
+
get_session_business_service,
|
|
34
46
|
)
|
|
47
|
+
from ....gateway.http_sse.services.session_service import SessionService
|
|
35
48
|
|
|
36
49
|
from typing import TYPE_CHECKING
|
|
37
50
|
|
|
@@ -58,7 +71,7 @@ async def _submit_task(
|
|
|
58
71
|
|
|
59
72
|
if not agent_name:
|
|
60
73
|
raise HTTPException(
|
|
61
|
-
status_code=status.
|
|
74
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
62
75
|
detail="Missing 'agent_name' in request payload message metadata.",
|
|
63
76
|
)
|
|
64
77
|
|
|
@@ -120,10 +133,14 @@ async def _submit_task(
|
|
|
120
133
|
session_id=session_id,
|
|
121
134
|
)
|
|
122
135
|
db.commit()
|
|
123
|
-
log.info(
|
|
136
|
+
log.info(
|
|
137
|
+
"%sCreated session in database: %s", log_prefix, session_id
|
|
138
|
+
)
|
|
124
139
|
except Exception as e:
|
|
125
140
|
db.rollback()
|
|
126
|
-
log.warning(
|
|
141
|
+
log.warning(
|
|
142
|
+
"%sFailed to create session in database: %s", log_prefix, e
|
|
143
|
+
)
|
|
127
144
|
finally:
|
|
128
145
|
db.close()
|
|
129
146
|
|
|
@@ -131,43 +148,6 @@ async def _submit_task(
|
|
|
131
148
|
"%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
|
|
132
149
|
)
|
|
133
150
|
|
|
134
|
-
# Store message in persistence layer if available
|
|
135
|
-
if is_streaming and SessionLocal is not None and session_service is not None:
|
|
136
|
-
db = SessionLocal()
|
|
137
|
-
try:
|
|
138
|
-
from ....gateway.http_sse.shared.enums import SenderType
|
|
139
|
-
|
|
140
|
-
message_text = ""
|
|
141
|
-
if payload.params and payload.params.message:
|
|
142
|
-
parts = a2a.get_parts_from_message(payload.params.message)
|
|
143
|
-
for part in parts:
|
|
144
|
-
if hasattr(part, "text"):
|
|
145
|
-
message_text = part.text
|
|
146
|
-
break
|
|
147
|
-
|
|
148
|
-
session_service.add_message_to_session(
|
|
149
|
-
db=db,
|
|
150
|
-
session_id=session_id,
|
|
151
|
-
user_id=user_id,
|
|
152
|
-
message=message_text or "Task submitted",
|
|
153
|
-
sender_type=SenderType.USER,
|
|
154
|
-
sender_name=user_id or "user",
|
|
155
|
-
agent_id=agent_name,
|
|
156
|
-
)
|
|
157
|
-
db.commit()
|
|
158
|
-
except Exception as e:
|
|
159
|
-
db.rollback()
|
|
160
|
-
log.error(
|
|
161
|
-
"%sFailed to store message in session service: %s", log_prefix, e
|
|
162
|
-
)
|
|
163
|
-
finally:
|
|
164
|
-
db.close()
|
|
165
|
-
else:
|
|
166
|
-
log.debug(
|
|
167
|
-
"%sNo persistence available or non-streaming - skipping message storage",
|
|
168
|
-
log_prefix,
|
|
169
|
-
)
|
|
170
|
-
|
|
171
151
|
# Use the helper to get the unwrapped parts from the incoming message.
|
|
172
152
|
a2a_parts = a2a.get_parts_from_message(payload.params.message)
|
|
173
153
|
|
|
@@ -222,6 +202,146 @@ async def _submit_task(
|
|
|
222
202
|
)
|
|
223
203
|
|
|
224
204
|
|
|
205
|
+
@router.get("/tasks", response_model=List[Task], tags=["Tasks"])
|
|
206
|
+
async def search_tasks(
|
|
207
|
+
request: FastAPIRequest,
|
|
208
|
+
start_date: Optional[str] = None,
|
|
209
|
+
end_date: Optional[str] = None,
|
|
210
|
+
search: Optional[str] = None,
|
|
211
|
+
page: int = 1,
|
|
212
|
+
page_size: int = 20,
|
|
213
|
+
query_user_id: Optional[str] = None,
|
|
214
|
+
user_id: UserId = Depends(get_user_id),
|
|
215
|
+
user_config: dict = Depends(get_user_config),
|
|
216
|
+
repo: ITaskRepository = Depends(get_task_repository),
|
|
217
|
+
):
|
|
218
|
+
"""
|
|
219
|
+
Lists and searches for historical tasks.
|
|
220
|
+
- Regular users can only search their own tasks.
|
|
221
|
+
- Users with the 'tasks:read:all' scope can search for any user's tasks by providing `query_user_id`.
|
|
222
|
+
"""
|
|
223
|
+
log_prefix = f"[GET /api/v1/tasks] "
|
|
224
|
+
log.info("%sRequest from user %s", log_prefix, user_id)
|
|
225
|
+
|
|
226
|
+
target_user_id = user_id
|
|
227
|
+
can_query_all = user_config.get("scopes", {}).get("tasks:read:all", False)
|
|
228
|
+
|
|
229
|
+
if query_user_id:
|
|
230
|
+
if can_query_all:
|
|
231
|
+
target_user_id = query_user_id
|
|
232
|
+
log.info(
|
|
233
|
+
"%sAdmin user %s is querying for user %s",
|
|
234
|
+
log_prefix,
|
|
235
|
+
user_id,
|
|
236
|
+
target_user_id,
|
|
237
|
+
)
|
|
238
|
+
else:
|
|
239
|
+
raise HTTPException(
|
|
240
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
241
|
+
detail="You do not have permission to query for other users' tasks.",
|
|
242
|
+
)
|
|
243
|
+
elif can_query_all:
|
|
244
|
+
target_user_id = "*"
|
|
245
|
+
log.info("%sAdmin user %s is querying for all users.", log_prefix, user_id)
|
|
246
|
+
|
|
247
|
+
start_time_ms = None
|
|
248
|
+
if start_date:
|
|
249
|
+
try:
|
|
250
|
+
start_time_ms = int(datetime.fromisoformat(start_date).timestamp() * 1000)
|
|
251
|
+
except ValueError:
|
|
252
|
+
raise HTTPException(
|
|
253
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
254
|
+
detail="Invalid start_date format. Use ISO 8601 format.",
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
end_time_ms = None
|
|
258
|
+
if end_date:
|
|
259
|
+
try:
|
|
260
|
+
end_time_ms = int(datetime.fromisoformat(end_date).timestamp() * 1000)
|
|
261
|
+
except ValueError:
|
|
262
|
+
raise HTTPException(
|
|
263
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
264
|
+
detail="Invalid end_date format. Use ISO 8601 format.",
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
pagination = PaginationParams(page=page, page_size=page_size)
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
tasks = repo.search(
|
|
271
|
+
user_id=target_user_id,
|
|
272
|
+
start_date=start_time_ms,
|
|
273
|
+
end_date=end_time_ms,
|
|
274
|
+
search_query=search,
|
|
275
|
+
pagination=pagination,
|
|
276
|
+
)
|
|
277
|
+
return tasks
|
|
278
|
+
except Exception as e:
|
|
279
|
+
log.exception("%sError searching for tasks: %s", log_prefix, e)
|
|
280
|
+
raise HTTPException(
|
|
281
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
282
|
+
detail="An error occurred while searching for tasks.",
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
@router.get("/tasks/{task_id}", tags=["Tasks"])
|
|
287
|
+
async def get_task_as_stim_file(
|
|
288
|
+
task_id: str,
|
|
289
|
+
request: FastAPIRequest,
|
|
290
|
+
user_id: UserId = Depends(get_user_id),
|
|
291
|
+
user_config: dict = Depends(get_user_config),
|
|
292
|
+
repo: ITaskRepository = Depends(get_task_repository),
|
|
293
|
+
):
|
|
294
|
+
"""
|
|
295
|
+
Retrieves the complete event history for a single task and returns it as a `.stim` file.
|
|
296
|
+
"""
|
|
297
|
+
log_prefix = f"[GET /api/v1/tasks/{task_id}] "
|
|
298
|
+
log.info("%sRequest from user %s", log_prefix, user_id)
|
|
299
|
+
|
|
300
|
+
try:
|
|
301
|
+
result = repo.find_by_id_with_events(task_id)
|
|
302
|
+
if not result:
|
|
303
|
+
raise HTTPException(
|
|
304
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
305
|
+
detail=f"Task with ID '{task_id}' not found.",
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
task, events = result
|
|
309
|
+
|
|
310
|
+
can_read_all = user_config.get("scopes", {}).get("tasks:read:all", False)
|
|
311
|
+
if task.user_id != user_id and not can_read_all:
|
|
312
|
+
raise HTTPException(
|
|
313
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
314
|
+
detail="You do not have permission to view this task.",
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
# Format into .stim structure
|
|
318
|
+
stim_data = create_stim_from_task_data(task, events)
|
|
319
|
+
|
|
320
|
+
yaml_content = yaml.dump(
|
|
321
|
+
stim_data,
|
|
322
|
+
sort_keys=False,
|
|
323
|
+
allow_unicode=True,
|
|
324
|
+
indent=2,
|
|
325
|
+
default_flow_style=False,
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
return Response(
|
|
329
|
+
content=yaml_content,
|
|
330
|
+
media_type="application/x-yaml",
|
|
331
|
+
headers={"Content-Disposition": f'attachment; filename="{task_id}.stim"'},
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
except HTTPException:
|
|
335
|
+
# Re-raise HTTPExceptions (404, 403, etc.) without modification
|
|
336
|
+
raise
|
|
337
|
+
except Exception as e:
|
|
338
|
+
log.exception("%sError retrieving task: %s", log_prefix, e)
|
|
339
|
+
raise HTTPException(
|
|
340
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
341
|
+
detail="An error occurred while retrieving the task.",
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
|
|
225
345
|
@router.post("/message:send", response_model=SendMessageSuccessResponse)
|
|
226
346
|
async def send_task_to_agent(
|
|
227
347
|
request: FastAPIRequest,
|
|
@@ -278,6 +398,7 @@ async def cancel_agent_task(
|
|
|
278
398
|
"""
|
|
279
399
|
Sends a cancellation request for a specific task to the specified agent.
|
|
280
400
|
Returns 202 Accepted, as cancellation is asynchronous.
|
|
401
|
+
Returns 404 if the task context is not found.
|
|
281
402
|
"""
|
|
282
403
|
log_prefix = f"[POST /api/v1/tasks/{taskId}:cancel] "
|
|
283
404
|
log.info("%sReceived cancellation request.", log_prefix)
|
|
@@ -290,6 +411,11 @@ async def cancel_agent_task(
|
|
|
290
411
|
|
|
291
412
|
context = component.task_context_manager.get_context(taskId)
|
|
292
413
|
if not context:
|
|
414
|
+
log.warning(
|
|
415
|
+
"%sNo active task context found for task ID: %s",
|
|
416
|
+
log_prefix,
|
|
417
|
+
taskId,
|
|
418
|
+
)
|
|
293
419
|
raise HTTPException(
|
|
294
420
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
295
421
|
detail=f"No active task context found for task ID: {taskId}",
|
|
@@ -328,4 +454,4 @@ async def cancel_agent_task(
|
|
|
328
454
|
raise HTTPException(
|
|
329
455
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
330
456
|
detail=error_resp.model_dump(exclude_none=True),
|
|
331
|
-
)
|
|
457
|
+
)
|