solace-agent-mesh 1.7.1__py3-none-any.whl → 1.13.2__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/alembic/README +74 -0
- solace_agent_mesh/agent/adk/alembic/env.py +77 -0
- solace_agent_mesh/agent/adk/alembic/script.py.mako +28 -0
- solace_agent_mesh/agent/adk/alembic/versions/e2902798564d_adk_session_db_upgrade.py +52 -0
- solace_agent_mesh/agent/adk/alembic.ini +112 -0
- solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +164 -0
- solace_agent_mesh/agent/adk/artifacts/s3_artifact_service.py +163 -0
- solace_agent_mesh/agent/adk/callbacks.py +752 -127
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +99 -7
- solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +52 -5
- solace_agent_mesh/agent/adk/mcp_content_processor.py +1 -1
- solace_agent_mesh/agent/adk/models/lite_llm.py +34 -16
- solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +24 -137
- solace_agent_mesh/agent/adk/runner.py +66 -8
- solace_agent_mesh/agent/adk/schema_migration.py +88 -0
- solace_agent_mesh/agent/adk/services.py +41 -1
- solace_agent_mesh/agent/adk/setup.py +220 -32
- solace_agent_mesh/agent/adk/stream_parser.py +229 -40
- solace_agent_mesh/agent/protocol/event_handlers.py +219 -33
- solace_agent_mesh/agent/proxies/a2a/component.py +572 -75
- solace_agent_mesh/agent/proxies/a2a/config.py +80 -4
- solace_agent_mesh/agent/proxies/base/component.py +188 -22
- solace_agent_mesh/agent/proxies/base/proxy_task_context.py +3 -1
- solace_agent_mesh/agent/sac/app.py +37 -12
- solace_agent_mesh/agent/sac/component.py +322 -52
- solace_agent_mesh/agent/sac/patch_adk.py +8 -16
- solace_agent_mesh/agent/sac/task_execution_context.py +90 -0
- solace_agent_mesh/agent/tools/__init__.py +3 -0
- solace_agent_mesh/agent/tools/audio_tools.py +3 -3
- solace_agent_mesh/agent/tools/builtin_artifact_tools.py +698 -24
- solace_agent_mesh/agent/tools/deep_research_tools.py +2161 -0
- solace_agent_mesh/agent/tools/peer_agent_tool.py +82 -15
- solace_agent_mesh/agent/tools/time_tools.py +126 -0
- solace_agent_mesh/agent/tools/tool_config_types.py +54 -2
- solace_agent_mesh/agent/tools/web_search_tools.py +279 -0
- solace_agent_mesh/agent/tools/web_tools.py +125 -17
- solace_agent_mesh/agent/utils/artifact_helpers.py +243 -5
- solace_agent_mesh/agent/utils/context_helpers.py +17 -0
- solace_agent_mesh/assets/docs/404.html +6 -6
- solace_agent_mesh/assets/docs/assets/css/{styles.906a1503.css → styles.8162edfb.css} +1 -1
- solace_agent_mesh/assets/docs/assets/js/05749d90.19ac4f35.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.e186750d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15e40e79.434bb30f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/17896441.e612dfb4.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/{17896441.a5e82f9b.js.LICENSE.txt → 2279.550aa580.js.LICENSE.txt} +6 -0
- solace_agent_mesh/assets/docs/assets/js/240a0364.83e37aa8.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2e32b5e0.2f0db237.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3a6c6137.7e61915d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.7f7ab1c1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.e53c9b78.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/41adc471.0e95b87c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4667dc50.bf2ad456.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/49eed117.493d6f99.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{509e993c.4c7a1a6d.js → 509e993c.a1fbf45a.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/547e15cc.8e6da617.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55b7b518.29d6e75d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5b8d9c11.d4eb37b8.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.1ee87753.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/60702c0e.a8bdd79b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/64195356.09dbd087.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/66d4869e.30340bd3.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6aaedf65.7253541d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6d84eae0.fd23ba4a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/729898df.7249e9fd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7e294c01.7c5f6906.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8024126c.e3467286.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/81a99df0.7ed65d45.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/82fbfb93.161823a5.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/924ffdeb.975e428a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/94e8668d.16083b3f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9bb13469.4523ae20.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a7d42657.a956689d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a94703ab.3e5fbcb3.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e563275.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c93cbaa0.0e0d8baf.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cab03b5b.6a073091.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.07e170dd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e04b235d.06d23db6.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.deb2b62e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.1476f570.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e6f9706b.acc800d3.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e92d0134.c147a429.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ee0c2fe7.94d0a351.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.cc97854c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.d634009f.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.27bb82a7.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +68 -68
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +50 -50
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +42 -42
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +55 -55
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +75 -75
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/image-tools/index.html +81 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +67 -50
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/research-tools/index.html +136 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +178 -144
- solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +43 -42
- solace_agent_mesh/assets/docs/docs/documentation/components/index.html +20 -18
- solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +23 -23
- solace_agent_mesh/assets/docs/docs/documentation/components/platform-service/index.html +33 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +45 -45
- solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +98 -112
- solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +147 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +208 -125
- solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +52 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +28 -28
- solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +29 -29
- solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +14 -14
- solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/index.html +47 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/kubernetes-deployment-guide/index.html +197 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +67 -53
- solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +17 -17
- solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +49 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +38 -38
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +87 -87
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +67 -49
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +17 -17
- solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +51 -51
- solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +22 -22
- solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +27 -27
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +135 -135
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +66 -66
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +51 -51
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +50 -38
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +86 -86
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +51 -51
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +24 -24
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +30 -30
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +44 -44
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +115 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +50 -23
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +29 -24
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +21 -21
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +40 -37
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +324 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +96 -66
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +181 -181
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +75 -75
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +27 -27
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +44 -44
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +39 -38
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +30 -30
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +18 -18
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/vibe_coding/index.html +62 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +135 -114
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +37 -37
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +14 -14
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +27 -25
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +69 -69
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +72 -72
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +112 -112
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +28 -28
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +42 -42
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +20 -20
- solace_agent_mesh/assets/docs/docs/documentation/migrations/platform-service-split/index.html +85 -0
- solace_agent_mesh/assets/docs/lunr-index-1768329217460.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1768329217460.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/__init__.py +3 -1
- solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +6 -1
- solace_agent_mesh/cli/commands/add_cmd/proxy_cmd.py +100 -0
- solace_agent_mesh/cli/commands/eval_cmd.py +1 -1
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +15 -0
- solace_agent_mesh/cli/commands/init_cmd/directory_step.py +1 -1
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +30 -3
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +3 -4
- solace_agent_mesh/cli/commands/init_cmd/platform_service_step.py +85 -0
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +16 -3
- solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +2 -1
- solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +1 -0
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +3 -3
- solace_agent_mesh/cli/commands/run_cmd.py +64 -49
- solace_agent_mesh/cli/commands/tools_cmd.py +315 -0
- solace_agent_mesh/cli/main.py +15 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-tcIFZLis.js → authCallback-KnKMP_vb.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/client-DpBL2stg.js +25 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-Cd498TV2.js +435 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-rSf8Vu29.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{vendor-CINwxvwV.js → vendor-CGk8Suyh.js} +189 -94
- 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/client/webui/frontend/static/mockServiceWorker.js +336 -0
- solace_agent_mesh/client/webui/frontend/static/ui-version.json +6 -0
- solace_agent_mesh/common/a2a/types.py +1 -1
- solace_agent_mesh/common/agent_registry.py +38 -11
- solace_agent_mesh/common/data_parts.py +124 -0
- solace_agent_mesh/common/error_handlers.py +83 -0
- solace_agent_mesh/common/exceptions.py +24 -0
- solace_agent_mesh/common/oauth/__init__.py +17 -0
- solace_agent_mesh/common/oauth/oauth_client.py +408 -0
- solace_agent_mesh/common/oauth/utils.py +50 -0
- solace_agent_mesh/common/rag_dto.py +156 -0
- solace_agent_mesh/common/sac/sam_component_base.py +73 -1
- solace_agent_mesh/common/sam_events/event_service.py +2 -2
- solace_agent_mesh/common/utils/embeds/converter.py +1 -8
- solace_agent_mesh/common/utils/embeds/modifiers.py +2 -27
- solace_agent_mesh/common/utils/embeds/resolver.py +94 -25
- solace_agent_mesh/common/utils/embeds/types.py +1 -0
- solace_agent_mesh/common/utils/log_formatters.py +20 -0
- solace_agent_mesh/common/utils/mime_helpers.py +12 -5
- solace_agent_mesh/common/utils/rbac_utils.py +69 -0
- solace_agent_mesh/common/utils/templates/__init__.py +8 -0
- solace_agent_mesh/common/utils/templates/liquid_renderer.py +210 -0
- solace_agent_mesh/common/utils/templates/template_resolver.py +161 -0
- solace_agent_mesh/config_portal/backend/common.py +12 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-CljP4_mv.js +103 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{components-Rk0n-9cK.js → components-CaC6hG8d.js} +22 -22
- solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-mvZjNKiz.js → entry.client-H_TM0YBt.js} +3 -3
- solace_agent_mesh/config_portal/frontend/static/client/assets/{index-DzNKzXrc.js → index-CnFykb2v.js} +16 -16
- solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-f8439d40.js +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-BIMqslJB.css +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-mJmTIdIk.js +10 -0
- solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
- solace_agent_mesh/core_a2a/service.py +3 -2
- solace_agent_mesh/gateway/adapter/base.py +28 -1
- solace_agent_mesh/gateway/adapter/types.py +9 -0
- solace_agent_mesh/gateway/base/app.py +10 -0
- solace_agent_mesh/gateway/base/auth_interface.py +103 -0
- solace_agent_mesh/gateway/base/component.py +451 -10
- solace_agent_mesh/gateway/generic/component.py +274 -30
- solace_agent_mesh/gateway/http_sse/alembic/env.py +0 -7
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +2 -43
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +2 -2
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251108_create_prompt_tables_with_sharing.py +154 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251115_add_parent_task_id.py +32 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251126_add_background_task_fields.py +47 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251202_add_versioned_fields_to_prompts.py +52 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +0 -36
- solace_agent_mesh/gateway/http_sse/app.py +23 -6
- solace_agent_mesh/gateway/http_sse/component.py +158 -73
- solace_agent_mesh/gateway/http_sse/dependencies.py +50 -57
- solace_agent_mesh/gateway/http_sse/main.py +58 -482
- solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +2 -2
- solace_agent_mesh/gateway/http_sse/repository/entities/project.py +1 -1
- solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +1 -1
- solace_agent_mesh/gateway/http_sse/repository/entities/session.py +3 -2
- solace_agent_mesh/gateway/http_sse/repository/entities/task.py +7 -0
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +2 -2
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +2 -2
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +5 -0
- solace_agent_mesh/gateway/http_sse/repository/models/prompt_model.py +159 -0
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +1 -1
- solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +8 -1
- solace_agent_mesh/gateway/http_sse/repository/project_repository.py +1 -1
- solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +1 -1
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +12 -107
- solace_agent_mesh/gateway/http_sse/repository/task_repository.py +86 -2
- solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +38 -7
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +113 -7
- solace_agent_mesh/gateway/http_sse/routers/auth.py +69 -132
- solace_agent_mesh/gateway/http_sse/routers/config.py +235 -10
- solace_agent_mesh/gateway/http_sse/routers/dto/project_dto.py +69 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/prompt_dto.py +255 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/base_responses.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +1 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +3 -2
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/version_responses.py +31 -0
- solace_agent_mesh/gateway/http_sse/routers/feedback.py +2 -2
- solace_agent_mesh/gateway/http_sse/routers/people.py +2 -2
- solace_agent_mesh/gateway/http_sse/routers/projects.py +250 -24
- solace_agent_mesh/gateway/http_sse/routers/prompts.py +1416 -0
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +14 -5
- solace_agent_mesh/gateway/http_sse/routers/speech.py +355 -0
- solace_agent_mesh/gateway/http_sse/routers/sse.py +117 -4
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +509 -149
- solace_agent_mesh/gateway/http_sse/routers/users.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/version.py +343 -0
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +2 -1
- solace_agent_mesh/gateway/http_sse/services/audio_service.py +1227 -0
- solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +186 -0
- solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +1 -1
- solace_agent_mesh/gateway/http_sse/services/feedback_service.py +1 -1
- solace_agent_mesh/gateway/http_sse/services/project_service.py +539 -12
- solace_agent_mesh/gateway/http_sse/services/prompt_builder_assistant.py +303 -0
- solace_agent_mesh/gateway/http_sse/services/session_service.py +198 -21
- solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +354 -4
- solace_agent_mesh/gateway/http_sse/sse_manager.py +280 -169
- solace_agent_mesh/gateway/http_sse/utils/artifact_copy_utils.py +370 -0
- solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +41 -1
- solace_agent_mesh/services/__init__.py +0 -0
- solace_agent_mesh/services/platform/__init__.py +29 -0
- solace_agent_mesh/services/platform/alembic/env.py +85 -0
- solace_agent_mesh/services/platform/alembic/script.py.mako +28 -0
- solace_agent_mesh/services/platform/alembic.ini +109 -0
- solace_agent_mesh/services/platform/api/__init__.py +3 -0
- solace_agent_mesh/services/platform/api/dependencies.py +154 -0
- solace_agent_mesh/services/platform/api/main.py +314 -0
- solace_agent_mesh/services/platform/api/middleware.py +51 -0
- solace_agent_mesh/services/platform/api/routers/__init__.py +33 -0
- solace_agent_mesh/services/platform/api/routers/health_router.py +31 -0
- solace_agent_mesh/services/platform/app.py +215 -0
- solace_agent_mesh/services/platform/component.py +777 -0
- solace_agent_mesh/shared/__init__.py +14 -0
- solace_agent_mesh/shared/api/__init__.py +42 -0
- solace_agent_mesh/shared/auth/__init__.py +26 -0
- solace_agent_mesh/shared/auth/dependencies.py +204 -0
- solace_agent_mesh/shared/auth/middleware.py +347 -0
- solace_agent_mesh/shared/database/__init__.py +20 -0
- solace_agent_mesh/{gateway/http_sse/shared → shared/database}/base_repository.py +1 -1
- solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_exceptions.py +1 -1
- solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_helpers.py +1 -1
- solace_agent_mesh/shared/exceptions/__init__.py +36 -0
- solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exception_handlers.py +1 -1
- solace_agent_mesh/shared/utils/__init__.py +21 -0
- solace_agent_mesh/templates/logging_config_template.yaml +48 -0
- solace_agent_mesh/templates/main_orchestrator.yaml +12 -1
- solace_agent_mesh/templates/platform.yaml +49 -0
- solace_agent_mesh/templates/plugin_readme_template.md +3 -25
- solace_agent_mesh/templates/plugin_tool_config_template.yaml +109 -0
- solace_agent_mesh/templates/proxy_template.yaml +62 -0
- solace_agent_mesh/templates/webui.yaml +148 -6
- solace_agent_mesh/tools/web_search/__init__.py +18 -0
- solace_agent_mesh/tools/web_search/base.py +84 -0
- solace_agent_mesh/tools/web_search/google_search.py +247 -0
- solace_agent_mesh/tools/web_search/models.py +99 -0
- {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/METADATA +29 -8
- {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/RECORD +334 -313
- {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/WHEEL +1 -1
- solace_agent_mesh/agent/adk/adk_llm.txt +0 -226
- solace_agent_mesh/agent/adk/adk_llm_detail.txt +0 -566
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +0 -171
- solace_agent_mesh/agent/adk/models/models_llm.txt +0 -189
- solace_agent_mesh/agent/agent_llm.txt +0 -369
- solace_agent_mesh/agent/agent_llm_detail.txt +0 -1702
- solace_agent_mesh/agent/protocol/protocol_llm.txt +0 -81
- solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +0 -92
- solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +0 -190
- solace_agent_mesh/agent/proxies/base/base_llm.txt +0 -148
- solace_agent_mesh/agent/proxies/proxies_llm.txt +0 -283
- solace_agent_mesh/agent/sac/sac_llm.txt +0 -189
- solace_agent_mesh/agent/sac/sac_llm_detail.txt +0 -200
- solace_agent_mesh/agent/testing/testing_llm.txt +0 -58
- solace_agent_mesh/agent/testing/testing_llm_detail.txt +0 -68
- solace_agent_mesh/agent/tools/tools_llm.txt +0 -276
- solace_agent_mesh/agent/tools/tools_llm_detail.txt +0 -275
- solace_agent_mesh/agent/utils/utils_llm.txt +0 -152
- solace_agent_mesh/agent/utils/utils_llm_detail.txt +0 -149
- solace_agent_mesh/assets/docs/assets/js/05749d90.c70b2be9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/15e40e79.36003774.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/240a0364.c39f8388.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.e4870a49.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.b63ee53a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.45b32c2b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/66d4869e.830d443f.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/81a99df0.07034dd9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/82fbfb93.139a1a1f.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/94e8668d.09ed9234.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9bb13469.dd1c9b54.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/a94703ab.0438dbc2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ab9708a8.245ae0ef.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.f902fad8.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e04b235d.c9c50c7b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.d11c67a7.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e6f9706b.045d0fa1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.5099c51e.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.f213fe0c.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.d9606d6a.js +0 -1
- solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +0 -47
- solace_agent_mesh/assets/docs/lunr-index-1762283454666.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1762283454666.json +0 -1
- solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +0 -250
- solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +0 -365
- solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +0 -305
- solace_agent_mesh/client/webui/frontend/static/assets/client-CRYdKo2Q.js +0 -25
- solace_agent_mesh/client/webui/frontend/static/assets/main-CojeY_1w.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-ILja9MCG.js +0 -353
- solace_agent_mesh/common/a2a/a2a_llm.txt +0 -175
- solace_agent_mesh/common/a2a/a2a_llm_detail.txt +0 -193
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +0 -445
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +0 -736
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +0 -330
- solace_agent_mesh/common/common_llm.txt +0 -230
- solace_agent_mesh/common/common_llm_detail.txt +0 -2562
- solace_agent_mesh/common/middleware/middleware_llm.txt +0 -174
- solace_agent_mesh/common/middleware/middleware_llm_detail.txt +0 -185
- solace_agent_mesh/common/sac/sac_llm.txt +0 -71
- solace_agent_mesh/common/sac/sac_llm_detail.txt +0 -82
- solace_agent_mesh/common/sam_events/sam_events_llm.txt +0 -104
- solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +0 -115
- solace_agent_mesh/common/services/providers/providers_llm.txt +0 -81
- solace_agent_mesh/common/services/services_llm.txt +0 -368
- solace_agent_mesh/common/services/services_llm_detail.txt +0 -459
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +0 -220
- solace_agent_mesh/common/utils/utils_llm.txt +0 -335
- solace_agent_mesh/common/utils/utils_llm_detail.txt +0 -572
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +0 -98
- solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-61038fc6.js +0 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-BWvk5-gF.js +0 -10
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-DxRwaWiE.css +0 -1
- solace_agent_mesh/core_a2a/core_a2a_llm.txt +0 -90
- solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +0 -101
- solace_agent_mesh/gateway/base/base_llm.txt +0 -226
- solace_agent_mesh/gateway/base/base_llm_detail.txt +0 -235
- solace_agent_mesh/gateway/gateway_llm.txt +0 -369
- solace_agent_mesh/gateway/gateway_llm_detail.txt +0 -3885
- solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +0 -345
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_fulltext_search_indexes.py +0 -92
- solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +0 -161
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +0 -105
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +0 -299
- solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +0 -3278
- solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +0 -221
- solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +0 -257
- solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +0 -308
- solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +0 -450
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +0 -133
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +0 -123
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +0 -312
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +0 -303
- solace_agent_mesh/gateway/http_sse/shared/__init__.py +0 -146
- solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +0 -319
- solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +0 -47
- solace_agent_mesh/llm.txt +0 -228
- solace_agent_mesh/llm_detail.txt +0 -2835
- solace_agent_mesh/solace_agent_mesh_llm.txt +0 -362
- solace_agent_mesh/solace_agent_mesh_llm_detail.txt +0 -8599
- solace_agent_mesh/templates/logging_config_template.ini +0 -45
- solace_agent_mesh/templates/templates_llm.txt +0 -147
- /solace_agent_mesh/assets/docs/assets/js/{main.f213fe0c.js.LICENSE.txt → main.d634009f.js.LICENSE.txt} +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/auth_utils.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/pagination.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/response_utils.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/error_dto.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exceptions.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/enums.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/timestamp_utils.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/types.py +0 -0
- /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/utils.py +0 -0
- {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""
|
|
2
2
|
API Router for submitting and managing tasks to agents.
|
|
3
|
+
Includes background task status endpoints.
|
|
3
4
|
"""
|
|
5
|
+
from __future__ import annotations
|
|
4
6
|
|
|
5
7
|
import logging
|
|
6
|
-
from datetime import datetime, timezone
|
|
7
8
|
from typing import TYPE_CHECKING
|
|
8
9
|
|
|
9
10
|
import yaml
|
|
@@ -14,16 +15,15 @@ from a2a.types import (
|
|
|
14
15
|
SendStreamingMessageRequest,
|
|
15
16
|
SendStreamingMessageSuccessResponse,
|
|
16
17
|
)
|
|
17
|
-
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
|
18
|
+
from fastapi import APIRouter, Depends, HTTPException, Query, Response, status
|
|
18
19
|
from fastapi import Request as FastAPIRequest
|
|
20
|
+
from pydantic import BaseModel
|
|
19
21
|
from sqlalchemy.orm import Session as DBSession
|
|
20
22
|
|
|
21
23
|
from ....gateway.http_sse.services.project_service import ProjectService
|
|
22
24
|
|
|
23
25
|
from ....agent.utils.artifact_helpers import (
|
|
24
26
|
get_artifact_info_list,
|
|
25
|
-
load_artifact_content_or_metadata,
|
|
26
|
-
save_artifact_with_metadata,
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
from ....common import a2a
|
|
@@ -40,11 +40,12 @@ from ....gateway.http_sse.dependencies import (
|
|
|
40
40
|
)
|
|
41
41
|
from ....gateway.http_sse.repository.entities import Task
|
|
42
42
|
from ....gateway.http_sse.repository.interfaces import ITaskRepository
|
|
43
|
+
from ....gateway.http_sse.repository.task_repository import TaskRepository
|
|
43
44
|
from ....gateway.http_sse.services.session_service import SessionService
|
|
44
45
|
from ....gateway.http_sse.services.task_service import TaskService
|
|
45
46
|
from ....gateway.http_sse.session_manager import SessionManager
|
|
46
|
-
from
|
|
47
|
-
from
|
|
47
|
+
from solace_agent_mesh.shared.api.pagination import PaginationParams
|
|
48
|
+
from solace_agent_mesh.shared.utils.types import UserId
|
|
48
49
|
from ..utils.stim_utils import create_stim_from_task_data
|
|
49
50
|
|
|
50
51
|
if TYPE_CHECKING:
|
|
@@ -55,6 +56,108 @@ router = APIRouter()
|
|
|
55
56
|
log = logging.getLogger(__name__)
|
|
56
57
|
|
|
57
58
|
|
|
59
|
+
# Background Task Status Models and Endpoints
|
|
60
|
+
class TaskStatusResponse(BaseModel):
|
|
61
|
+
"""Response model for task status queries."""
|
|
62
|
+
task: Task
|
|
63
|
+
is_running: bool
|
|
64
|
+
is_background: bool
|
|
65
|
+
can_reconnect: bool
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@router.get("/tasks/{task_id}/status", response_model=TaskStatusResponse, tags=["Tasks"])
|
|
69
|
+
async def get_task_status(
|
|
70
|
+
task_id: str,
|
|
71
|
+
db: DBSession = Depends(get_db),
|
|
72
|
+
):
|
|
73
|
+
"""
|
|
74
|
+
Get the current status of a task.
|
|
75
|
+
Used by frontend to check if a background task is still running.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
task_id: The task ID to query
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Task status information including whether it's running and can be reconnected to
|
|
82
|
+
"""
|
|
83
|
+
log_prefix = f"[GET /api/v1/tasks/{task_id}/status] "
|
|
84
|
+
log.debug("%sQuerying task status", log_prefix)
|
|
85
|
+
|
|
86
|
+
repo = TaskRepository()
|
|
87
|
+
task = repo.find_by_id(db, task_id)
|
|
88
|
+
|
|
89
|
+
if not task:
|
|
90
|
+
raise HTTPException(status_code=404, detail=f"Task {task_id} not found")
|
|
91
|
+
|
|
92
|
+
# Determine if task is still running
|
|
93
|
+
is_running = task.status in [None, "running", "pending"] and task.end_time is None
|
|
94
|
+
|
|
95
|
+
# Check if it's a background task
|
|
96
|
+
is_background = task.background_execution_enabled or False
|
|
97
|
+
|
|
98
|
+
# Can reconnect if it's a background task and still running
|
|
99
|
+
can_reconnect = is_background and is_running
|
|
100
|
+
|
|
101
|
+
log.info(
|
|
102
|
+
"%sTask status: running=%s, background=%s, can_reconnect=%s",
|
|
103
|
+
log_prefix,
|
|
104
|
+
is_running,
|
|
105
|
+
is_background,
|
|
106
|
+
can_reconnect,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return TaskStatusResponse(
|
|
110
|
+
task=task,
|
|
111
|
+
is_running=is_running,
|
|
112
|
+
is_background=is_background,
|
|
113
|
+
can_reconnect=can_reconnect
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@router.get("/tasks/background/active", tags=["Tasks"])
|
|
118
|
+
async def get_active_background_tasks(
|
|
119
|
+
user_id: str = Query(..., description="User ID to filter tasks"),
|
|
120
|
+
db: DBSession = Depends(get_db),
|
|
121
|
+
):
|
|
122
|
+
"""
|
|
123
|
+
Get all active background tasks for a user.
|
|
124
|
+
Used by frontend on session load to detect running background tasks.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
user_id: The user ID to filter by
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
List of active background tasks
|
|
131
|
+
"""
|
|
132
|
+
log_prefix = "[GET /api/v1/tasks/background/active] "
|
|
133
|
+
log.debug("%sQuerying active background tasks for user %s", log_prefix, user_id)
|
|
134
|
+
|
|
135
|
+
repo = TaskRepository()
|
|
136
|
+
|
|
137
|
+
# Get all background tasks
|
|
138
|
+
all_background_tasks = repo.find_background_tasks_by_status(db, status=None)
|
|
139
|
+
|
|
140
|
+
# Filter by user and running status
|
|
141
|
+
active_tasks = [
|
|
142
|
+
task for task in all_background_tasks
|
|
143
|
+
if task.user_id == user_id
|
|
144
|
+
and task.status in [None, "running", "pending"]
|
|
145
|
+
and task.end_time is None
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
log.info("%sFound %d active background tasks for user %s", log_prefix, len(active_tasks), user_id)
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
"tasks": active_tasks,
|
|
152
|
+
"count": len(active_tasks)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# =============================================================================
|
|
157
|
+
# Project Context Injection Helper
|
|
158
|
+
# =============================================================================
|
|
159
|
+
|
|
160
|
+
|
|
58
161
|
async def _inject_project_context(
|
|
59
162
|
project_id: str,
|
|
60
163
|
message_text: str,
|
|
@@ -80,23 +183,31 @@ async def _inject_project_context(
|
|
|
80
183
|
return message_text
|
|
81
184
|
|
|
82
185
|
from ....gateway.http_sse.dependencies import SessionLocal
|
|
186
|
+
from ..utils.artifact_copy_utils import copy_project_artifacts_to_session
|
|
83
187
|
|
|
84
188
|
if SessionLocal is None:
|
|
85
|
-
log.warning(
|
|
189
|
+
log.warning(
|
|
190
|
+
"%sProject context injection skipped: database not configured", log_prefix
|
|
191
|
+
)
|
|
86
192
|
return message_text
|
|
87
193
|
|
|
88
194
|
db = SessionLocal()
|
|
195
|
+
artifact_service = None
|
|
196
|
+
should_clear_pending_flags = False
|
|
197
|
+
|
|
89
198
|
try:
|
|
90
199
|
project = project_service.get_project(db, project_id, user_id)
|
|
91
200
|
if not project:
|
|
92
201
|
return message_text
|
|
93
|
-
|
|
202
|
+
|
|
94
203
|
context_parts = []
|
|
95
204
|
|
|
96
205
|
# Only inject full context for new sessions
|
|
97
206
|
if inject_full_context:
|
|
98
207
|
# Start with clear workspace framing
|
|
99
|
-
context_parts.append(
|
|
208
|
+
context_parts.append(
|
|
209
|
+
f'You are working in the project workspace: "{project.name}"'
|
|
210
|
+
)
|
|
100
211
|
|
|
101
212
|
# Add system prompt if exists
|
|
102
213
|
if project.system_prompt and project.system_prompt.strip():
|
|
@@ -105,138 +216,74 @@ async def _inject_project_context(
|
|
|
105
216
|
# Add project description if exists
|
|
106
217
|
if project.description and project.description.strip():
|
|
107
218
|
context_parts.append(f"\nProject Description: {project.description.strip()}")
|
|
108
|
-
|
|
219
|
+
|
|
109
220
|
# Always copy project artifacts to session (for both new and existing sessions)
|
|
110
221
|
# This ensures new project files are available to existing sessions
|
|
111
222
|
artifact_service = component.get_shared_artifact_service()
|
|
112
223
|
if artifact_service:
|
|
113
|
-
try:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
user_id=source_user_id,
|
|
123
|
-
session_id=project_artifacts_session_id,
|
|
224
|
+
try:
|
|
225
|
+
artifacts_copied, new_artifact_names = await copy_project_artifacts_to_session(
|
|
226
|
+
project_id=project_id,
|
|
227
|
+
user_id=user_id,
|
|
228
|
+
session_id=session_id,
|
|
229
|
+
project_service=project_service,
|
|
230
|
+
component=component,
|
|
231
|
+
db=db,
|
|
232
|
+
log_prefix=log_prefix,
|
|
124
233
|
)
|
|
125
234
|
|
|
126
|
-
if
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
#
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
try:
|
|
165
|
-
# Load artifact content from project storage
|
|
166
|
-
loaded_artifact = await load_artifact_content_or_metadata(
|
|
167
|
-
artifact_service=artifact_service,
|
|
168
|
-
app_name=project_service.app_name,
|
|
169
|
-
user_id=source_user_id,
|
|
170
|
-
session_id=project_artifacts_session_id,
|
|
171
|
-
filename=artifact_info.filename,
|
|
172
|
-
return_raw_bytes=True,
|
|
173
|
-
version="latest"
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
# Load the full metadata separately
|
|
177
|
-
loaded_metadata = await load_artifact_content_or_metadata(
|
|
178
|
-
artifact_service=artifact_service,
|
|
179
|
-
app_name=project_service.app_name,
|
|
180
|
-
user_id=source_user_id,
|
|
181
|
-
session_id=project_artifacts_session_id,
|
|
182
|
-
filename=artifact_info.filename,
|
|
183
|
-
load_metadata_only=True,
|
|
184
|
-
version="latest"
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
# Save a copy to the current chat session
|
|
188
|
-
if loaded_artifact.get("status") == "success":
|
|
189
|
-
full_metadata = loaded_metadata.get("metadata", {}) if loaded_metadata.get("status") == "success" else {}
|
|
190
|
-
|
|
191
|
-
# Ensure the source is always set for copied project artifacts
|
|
192
|
-
full_metadata["source"] = "project"
|
|
193
|
-
|
|
194
|
-
await save_artifact_with_metadata(
|
|
195
|
-
artifact_service=artifact_service,
|
|
196
|
-
app_name=project_service.app_name,
|
|
197
|
-
user_id=user_id,
|
|
198
|
-
session_id=session_id,
|
|
199
|
-
filename=artifact_info.filename,
|
|
200
|
-
content_bytes=loaded_artifact.get("raw_bytes"),
|
|
201
|
-
mime_type=loaded_artifact.get("mime_type"),
|
|
202
|
-
metadata_dict=full_metadata,
|
|
203
|
-
timestamp=datetime.now(timezone.utc),
|
|
204
|
-
)
|
|
205
|
-
artifacts_copied += 1
|
|
206
|
-
log.info("%sSuccessfully copied artifact %s to session", log_prefix, artifact_info.filename)
|
|
207
|
-
else:
|
|
208
|
-
log.warning("%sFailed to load artifact %s: %s", log_prefix, artifact_info.filename, loaded_artifact.get("status"))
|
|
209
|
-
except Exception as e:
|
|
210
|
-
log.error("%sError copying artifact %s to session: %s", log_prefix, artifact_info.filename, e)
|
|
211
|
-
# Continue with other artifacts even if one fails
|
|
212
|
-
|
|
213
|
-
# Add artifact descriptions to context
|
|
214
|
-
if inject_full_context and all_artifact_descriptions:
|
|
215
|
-
# New session: show all project files
|
|
216
|
-
artifacts_context = (
|
|
217
|
-
"\nFiles in Session:\n"
|
|
218
|
-
"The following files are available in your session and can be viewed using your tools if required:\n"
|
|
219
|
-
+ "\n".join(all_artifact_descriptions)
|
|
220
|
-
)
|
|
221
|
-
context_parts.append(artifacts_context)
|
|
222
|
-
elif not inject_full_context and new_artifact_descriptions:
|
|
223
|
-
# Existing session: notify about newly added files
|
|
224
|
-
new_files_context = (
|
|
225
|
-
"\nNew Files Added to Project:\n"
|
|
226
|
-
"The following files have been added to the project and are now available in your session:\n"
|
|
227
|
-
+ "\n".join(new_artifact_descriptions)
|
|
235
|
+
if inject_full_context and artifacts_copied > 0:
|
|
236
|
+
# need to clear the pending flags even if injection fails
|
|
237
|
+
should_clear_pending_flags = True
|
|
238
|
+
|
|
239
|
+
# Get artifact descriptions for context injection
|
|
240
|
+
if artifacts_copied > 0 or inject_full_context:
|
|
241
|
+
source_user_id = project.user_id
|
|
242
|
+
project_artifacts_session_id = f"project-{project.id}"
|
|
243
|
+
|
|
244
|
+
project_artifacts = await get_artifact_info_list(
|
|
245
|
+
artifact_service=artifact_service,
|
|
246
|
+
app_name=project_service.app_name,
|
|
247
|
+
user_id=source_user_id,
|
|
248
|
+
session_id=project_artifacts_session_id,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
if project_artifacts:
|
|
252
|
+
# For new sessions - all files
|
|
253
|
+
all_artifact_descriptions = []
|
|
254
|
+
# For existing sessions - only new files
|
|
255
|
+
new_artifact_descriptions = []
|
|
256
|
+
|
|
257
|
+
for artifact_info in project_artifacts:
|
|
258
|
+
# Build description for all artifacts (for new sessions)
|
|
259
|
+
desc_str = f"- {artifact_info.filename}"
|
|
260
|
+
if artifact_info.description:
|
|
261
|
+
desc_str += f": {artifact_info.description}"
|
|
262
|
+
all_artifact_descriptions.append(desc_str)
|
|
263
|
+
|
|
264
|
+
# Track new artifacts for existing sessions
|
|
265
|
+
if artifact_info.filename in new_artifact_names:
|
|
266
|
+
new_artifact_descriptions.append(desc_str)
|
|
267
|
+
|
|
268
|
+
# Add artifact descriptions to context
|
|
269
|
+
files_added_header = (
|
|
270
|
+
"\nNew Files Added to Session:\n"
|
|
271
|
+
"The following files have been added to your session (in addition to any files already present):\n"
|
|
228
272
|
)
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
273
|
+
|
|
274
|
+
if inject_full_context and all_artifact_descriptions:
|
|
275
|
+
# New session: show all project files
|
|
276
|
+
artifacts_context = files_added_header + "\n".join(all_artifact_descriptions)
|
|
277
|
+
context_parts.append(artifacts_context)
|
|
278
|
+
elif not inject_full_context and new_artifact_descriptions:
|
|
279
|
+
# Existing session: notify about newly added files
|
|
280
|
+
new_files_context = files_added_header + "\n".join(new_artifact_descriptions)
|
|
281
|
+
context_parts.append(new_files_context)
|
|
237
282
|
|
|
238
283
|
except Exception as e:
|
|
239
|
-
log.warning(
|
|
284
|
+
log.warning(
|
|
285
|
+
"%sFailed to copy project artifacts to session: %s", log_prefix, e
|
|
286
|
+
)
|
|
240
287
|
# Do not fail the entire request, just log the warning
|
|
241
288
|
|
|
242
289
|
# Inject all gathered context into the message, ending with user query
|
|
@@ -245,10 +292,10 @@ async def _inject_project_context(
|
|
|
245
292
|
if context_parts:
|
|
246
293
|
project_context = "\n".join(context_parts)
|
|
247
294
|
modified_message_text = f"{project_context}\n\nUSER QUERY:\n{message_text}"
|
|
248
|
-
log.
|
|
295
|
+
log.debug("%sInjected full project context for project: %s", log_prefix, project_id)
|
|
249
296
|
else:
|
|
250
297
|
log.debug("%sSkipped full context injection for existing session, but ensured new artifacts are copied", log_prefix)
|
|
251
|
-
|
|
298
|
+
|
|
252
299
|
return modified_message_text
|
|
253
300
|
|
|
254
301
|
except Exception as e:
|
|
@@ -256,6 +303,22 @@ async def _inject_project_context(
|
|
|
256
303
|
# Continue without injection - don't fail the request
|
|
257
304
|
return message_text
|
|
258
305
|
finally:
|
|
306
|
+
# Clear the pending project context flags from all artifacts
|
|
307
|
+
if should_clear_pending_flags and artifact_service:
|
|
308
|
+
from ..utils.artifact_copy_utils import clear_pending_project_context
|
|
309
|
+
try:
|
|
310
|
+
await clear_pending_project_context(
|
|
311
|
+
user_id=user_id,
|
|
312
|
+
session_id=session_id,
|
|
313
|
+
artifact_service=artifact_service,
|
|
314
|
+
app_name=project_service.app_name,
|
|
315
|
+
db=db,
|
|
316
|
+
log_prefix=log_prefix,
|
|
317
|
+
)
|
|
318
|
+
log.debug("%sCleared pending project context flags", log_prefix)
|
|
319
|
+
except Exception as e:
|
|
320
|
+
log.warning("%sFailed to clear pending project context flags: %s", log_prefix, e)
|
|
321
|
+
|
|
259
322
|
db.close()
|
|
260
323
|
|
|
261
324
|
|
|
@@ -325,12 +388,21 @@ async def _submit_task(
|
|
|
325
388
|
if SessionLocal is not None:
|
|
326
389
|
db = SessionLocal()
|
|
327
390
|
try:
|
|
328
|
-
session_details = session_service.get_session_details(
|
|
391
|
+
session_details = session_service.get_session_details(
|
|
392
|
+
db, frontend_session_id, user_id
|
|
393
|
+
)
|
|
329
394
|
if session_details and session_details.project_id:
|
|
330
395
|
project_id = session_details.project_id
|
|
331
|
-
log.info(
|
|
396
|
+
log.info(
|
|
397
|
+
"%sFound project_id %s from session database for session %s",
|
|
398
|
+
log_prefix,
|
|
399
|
+
project_id,
|
|
400
|
+
frontend_session_id,
|
|
401
|
+
)
|
|
332
402
|
except Exception as e:
|
|
333
|
-
log.warning(
|
|
403
|
+
log.warning(
|
|
404
|
+
"%sFailed to lookup session project_id: %s", log_prefix, e
|
|
405
|
+
)
|
|
334
406
|
finally:
|
|
335
407
|
db.close()
|
|
336
408
|
|
|
@@ -384,15 +456,40 @@ async def _submit_task(
|
|
|
384
456
|
if hasattr(part, "text"):
|
|
385
457
|
message_text = part.text
|
|
386
458
|
break
|
|
387
|
-
|
|
459
|
+
|
|
388
460
|
# Project context injection - always inject for project sessions to ensure new files are available
|
|
389
461
|
# Skip if project_service is None (persistence disabled)
|
|
390
462
|
modified_message = payload.params.message
|
|
391
463
|
if project_service and project_id and message_text:
|
|
392
|
-
#
|
|
393
|
-
# For existing sessions, only copy new artifacts without re-injecting full context
|
|
464
|
+
# Determine if we should inject full context:
|
|
394
465
|
should_inject_full_context = not frontend_session_id
|
|
395
466
|
|
|
467
|
+
# Check if there are artifacts with pending project context
|
|
468
|
+
if frontend_session_id and not should_inject_full_context:
|
|
469
|
+
from ..utils.artifact_copy_utils import has_pending_project_context
|
|
470
|
+
from ....gateway.http_sse.dependencies import SessionLocal
|
|
471
|
+
|
|
472
|
+
artifact_service = component.get_shared_artifact_service()
|
|
473
|
+
if artifact_service and SessionLocal:
|
|
474
|
+
db = SessionLocal()
|
|
475
|
+
try:
|
|
476
|
+
has_pending = await has_pending_project_context(
|
|
477
|
+
user_id=client_id,
|
|
478
|
+
session_id=session_id,
|
|
479
|
+
artifact_service=artifact_service,
|
|
480
|
+
app_name=component.gateway_id,
|
|
481
|
+
db=db,
|
|
482
|
+
)
|
|
483
|
+
if has_pending:
|
|
484
|
+
should_inject_full_context = True
|
|
485
|
+
log.info(
|
|
486
|
+
"%sDetected pending project context for session %s, will inject full context",
|
|
487
|
+
log_prefix,
|
|
488
|
+
session_id,
|
|
489
|
+
)
|
|
490
|
+
finally:
|
|
491
|
+
db.close()
|
|
492
|
+
|
|
396
493
|
modified_message_text = await _inject_project_context(
|
|
397
494
|
project_id=project_id,
|
|
398
495
|
message_text=message_text,
|
|
@@ -426,7 +523,9 @@ async def _submit_task(
|
|
|
426
523
|
new_parts.insert(0, new_text_part)
|
|
427
524
|
|
|
428
525
|
# Update the message with the new parts
|
|
429
|
-
modified_message = a2a.update_message_parts(
|
|
526
|
+
modified_message = a2a.update_message_parts(
|
|
527
|
+
payload.params.message, new_parts
|
|
528
|
+
)
|
|
430
529
|
|
|
431
530
|
# Use the helper to get the unwrapped parts from the modified message (with project context if applied).
|
|
432
531
|
a2a_parts = a2a.get_parts_from_message(modified_message)
|
|
@@ -439,12 +538,24 @@ async def _submit_task(
|
|
|
439
538
|
"target_agent_name": agent_name,
|
|
440
539
|
}
|
|
441
540
|
|
|
541
|
+
# Extract additional metadata from the message (e.g., background execution settings)
|
|
542
|
+
# This metadata will be passed through to the A2A message for the task logger
|
|
543
|
+
additional_metadata = {}
|
|
544
|
+
if payload.params and payload.params.message and payload.params.message.metadata:
|
|
545
|
+
msg_metadata = payload.params.message.metadata
|
|
546
|
+
# Pass through background execution settings
|
|
547
|
+
if msg_metadata.get("backgroundExecutionEnabled"):
|
|
548
|
+
additional_metadata["backgroundExecutionEnabled"] = msg_metadata.get("backgroundExecutionEnabled")
|
|
549
|
+
if msg_metadata.get("maxExecutionTimeMs"):
|
|
550
|
+
additional_metadata["maxExecutionTimeMs"] = msg_metadata.get("maxExecutionTimeMs")
|
|
551
|
+
|
|
442
552
|
task_id = await component.submit_a2a_task(
|
|
443
553
|
target_agent_name=agent_name,
|
|
444
554
|
a2a_parts=a2a_parts,
|
|
445
555
|
external_request_context=external_req_ctx,
|
|
446
556
|
user_identity=user_identity,
|
|
447
557
|
is_streaming=is_streaming,
|
|
558
|
+
metadata=additional_metadata if additional_metadata else None,
|
|
448
559
|
)
|
|
449
560
|
|
|
450
561
|
log.info("%sTask submitted successfully. TaskID: %s", log_prefix, task_id)
|
|
@@ -563,8 +674,8 @@ async def search_tasks(
|
|
|
563
674
|
)
|
|
564
675
|
|
|
565
676
|
|
|
566
|
-
@router.get("/tasks/{task_id}", tags=["Tasks"])
|
|
567
|
-
async def
|
|
677
|
+
@router.get("/tasks/{task_id}/events", tags=["Tasks"])
|
|
678
|
+
async def get_task_events(
|
|
568
679
|
task_id: str,
|
|
569
680
|
request: FastAPIRequest,
|
|
570
681
|
db: DBSession = Depends(get_db),
|
|
@@ -573,9 +684,11 @@ async def get_task_as_stim_file(
|
|
|
573
684
|
repo: ITaskRepository = Depends(get_task_repository),
|
|
574
685
|
):
|
|
575
686
|
"""
|
|
576
|
-
Retrieves the complete event history for a
|
|
687
|
+
Retrieves the complete event history for a task and all its child tasks as JSON.
|
|
688
|
+
Returns events in the same format as the SSE stream for workflow visualization.
|
|
689
|
+
Recursively loads all descendant tasks to enable full workflow rendering.
|
|
577
690
|
"""
|
|
578
|
-
log_prefix = f"[GET /api/v1/tasks/{task_id}] "
|
|
691
|
+
log_prefix = f"[GET /api/v1/tasks/{task_id}/events] "
|
|
579
692
|
log.info("%sRequest from user %s", log_prefix, user_id)
|
|
580
693
|
|
|
581
694
|
try:
|
|
@@ -595,8 +708,255 @@ async def get_task_as_stim_file(
|
|
|
595
708
|
detail="You do not have permission to view this task.",
|
|
596
709
|
)
|
|
597
710
|
|
|
598
|
-
#
|
|
599
|
-
|
|
711
|
+
# Transform task events into A2AEventSSEPayload format for the frontend
|
|
712
|
+
# Need to reconstruct the SSE structure from stored data
|
|
713
|
+
formatted_events = []
|
|
714
|
+
|
|
715
|
+
for event in events:
|
|
716
|
+
# event.payload contains the raw A2A JSON-RPC message
|
|
717
|
+
# event.created_time is epoch milliseconds
|
|
718
|
+
# event.direction is simplified (request, response, status, error, etc)
|
|
719
|
+
|
|
720
|
+
# Convert timestamp from epoch milliseconds to ISO 8601
|
|
721
|
+
from datetime import datetime, timezone
|
|
722
|
+
timestamp_dt = datetime.fromtimestamp(event.created_time / 1000, tz=timezone.utc)
|
|
723
|
+
timestamp_iso = timestamp_dt.isoformat()
|
|
724
|
+
|
|
725
|
+
# Extract metadata from payload using similar logic to SSE component
|
|
726
|
+
payload = event.payload
|
|
727
|
+
message_id = payload.get("id")
|
|
728
|
+
source_entity = "unknown"
|
|
729
|
+
target_entity = "unknown"
|
|
730
|
+
method = "N/A"
|
|
731
|
+
|
|
732
|
+
# Parse based on direction
|
|
733
|
+
if event.direction == "request":
|
|
734
|
+
# It's a request - extract target from message metadata
|
|
735
|
+
method = payload.get("method", "N/A")
|
|
736
|
+
if "params" in payload and "message" in payload.get("params", {}):
|
|
737
|
+
message = payload["params"]["message"]
|
|
738
|
+
if isinstance(message, dict) and "metadata" in message:
|
|
739
|
+
target_entity = message["metadata"].get("agent_name", "unknown")
|
|
740
|
+
elif event.direction in ["status", "response", "error"]:
|
|
741
|
+
# It's a response - extract source from result metadata
|
|
742
|
+
if "result" in payload:
|
|
743
|
+
result = payload["result"]
|
|
744
|
+
if isinstance(result, dict):
|
|
745
|
+
# Check for agent_name in metadata
|
|
746
|
+
if "metadata" in result:
|
|
747
|
+
source_entity = result["metadata"].get("agent_name", "unknown")
|
|
748
|
+
# For status updates, check the message inside
|
|
749
|
+
if "message" in result:
|
|
750
|
+
message = result["message"]
|
|
751
|
+
if isinstance(message, dict) and "metadata" in message:
|
|
752
|
+
if source_entity == "unknown":
|
|
753
|
+
source_entity = message["metadata"].get("agent_name", "unknown")
|
|
754
|
+
|
|
755
|
+
# Map stored direction to SSE direction format
|
|
756
|
+
direction_map = {
|
|
757
|
+
"request": "request",
|
|
758
|
+
"response": "task",
|
|
759
|
+
"status": "status-update",
|
|
760
|
+
"error": "error_response",
|
|
761
|
+
}
|
|
762
|
+
sse_direction = direction_map.get(event.direction, event.direction)
|
|
763
|
+
|
|
764
|
+
# Build the A2AEventSSEPayload structure
|
|
765
|
+
formatted_event = {
|
|
766
|
+
"event_type": "a2a_message",
|
|
767
|
+
"timestamp": timestamp_iso,
|
|
768
|
+
"solace_topic": event.topic,
|
|
769
|
+
"direction": sse_direction,
|
|
770
|
+
"source_entity": source_entity,
|
|
771
|
+
"target_entity": target_entity,
|
|
772
|
+
"message_id": message_id,
|
|
773
|
+
"task_id": task_id,
|
|
774
|
+
"payload_summary": {
|
|
775
|
+
"method": method,
|
|
776
|
+
"params_preview": None,
|
|
777
|
+
},
|
|
778
|
+
"full_payload": payload,
|
|
779
|
+
}
|
|
780
|
+
formatted_events.append(formatted_event)
|
|
781
|
+
|
|
782
|
+
# Use database-level query to get all related tasks efficiently
|
|
783
|
+
related_task_ids = repo.find_all_by_parent_chain(db, task_id)
|
|
784
|
+
log.info(
|
|
785
|
+
"%sFound %d related tasks for task_id %s",
|
|
786
|
+
log_prefix,
|
|
787
|
+
len(related_task_ids),
|
|
788
|
+
task_id,
|
|
789
|
+
)
|
|
790
|
+
|
|
791
|
+
# Load and format all related tasks
|
|
792
|
+
all_tasks = {}
|
|
793
|
+
all_tasks[task_id] = {
|
|
794
|
+
"events": formatted_events,
|
|
795
|
+
"initial_request_text": task.initial_request_text or "",
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
# Load remaining related tasks
|
|
799
|
+
for tid in related_task_ids:
|
|
800
|
+
if tid == task_id:
|
|
801
|
+
continue # Already loaded
|
|
802
|
+
|
|
803
|
+
task_result = repo.find_by_id_with_events(db, tid)
|
|
804
|
+
if not task_result:
|
|
805
|
+
continue
|
|
806
|
+
|
|
807
|
+
related_task, related_events = task_result
|
|
808
|
+
|
|
809
|
+
# Check permissions for each related task
|
|
810
|
+
if related_task.user_id != user_id and not can_read_all:
|
|
811
|
+
log.warning(
|
|
812
|
+
"%sSkipping related task %s due to permission check",
|
|
813
|
+
log_prefix,
|
|
814
|
+
tid,
|
|
815
|
+
)
|
|
816
|
+
continue
|
|
817
|
+
|
|
818
|
+
# Format events for this related task
|
|
819
|
+
related_formatted_events = []
|
|
820
|
+
|
|
821
|
+
for event in related_events:
|
|
822
|
+
from datetime import datetime, timezone
|
|
823
|
+
|
|
824
|
+
timestamp_dt = datetime.fromtimestamp(
|
|
825
|
+
event.created_time / 1000, tz=timezone.utc
|
|
826
|
+
)
|
|
827
|
+
timestamp_iso = timestamp_dt.isoformat()
|
|
828
|
+
payload = event.payload
|
|
829
|
+
message_id = payload.get("id")
|
|
830
|
+
source_entity = "unknown"
|
|
831
|
+
target_entity = "unknown"
|
|
832
|
+
method = "N/A"
|
|
833
|
+
|
|
834
|
+
if event.direction == "request":
|
|
835
|
+
method = payload.get("method", "N/A")
|
|
836
|
+
if "params" in payload and "message" in payload.get("params", {}):
|
|
837
|
+
message = payload["params"]["message"]
|
|
838
|
+
if isinstance(message, dict) and "metadata" in message:
|
|
839
|
+
target_entity = message["metadata"].get(
|
|
840
|
+
"agent_name", "unknown"
|
|
841
|
+
)
|
|
842
|
+
elif event.direction in ["status", "response", "error"]:
|
|
843
|
+
if "result" in payload:
|
|
844
|
+
result = payload["result"]
|
|
845
|
+
if isinstance(result, dict):
|
|
846
|
+
if "metadata" in result:
|
|
847
|
+
source_entity = result["metadata"].get(
|
|
848
|
+
"agent_name", "unknown"
|
|
849
|
+
)
|
|
850
|
+
if "message" in result:
|
|
851
|
+
message = result["message"]
|
|
852
|
+
if isinstance(message, dict) and "metadata" in message:
|
|
853
|
+
if source_entity == "unknown":
|
|
854
|
+
source_entity = message["metadata"].get(
|
|
855
|
+
"agent_name", "unknown"
|
|
856
|
+
)
|
|
857
|
+
|
|
858
|
+
direction_map = {
|
|
859
|
+
"request": "request",
|
|
860
|
+
"response": "task",
|
|
861
|
+
"status": "status-update",
|
|
862
|
+
"error": "error_response",
|
|
863
|
+
}
|
|
864
|
+
sse_direction = direction_map.get(event.direction, event.direction)
|
|
865
|
+
|
|
866
|
+
formatted_event = {
|
|
867
|
+
"event_type": "a2a_message",
|
|
868
|
+
"timestamp": timestamp_iso,
|
|
869
|
+
"solace_topic": event.topic,
|
|
870
|
+
"direction": sse_direction,
|
|
871
|
+
"source_entity": source_entity,
|
|
872
|
+
"target_entity": target_entity,
|
|
873
|
+
"message_id": message_id,
|
|
874
|
+
"task_id": tid,
|
|
875
|
+
"payload_summary": {"method": method, "params_preview": None},
|
|
876
|
+
"full_payload": payload,
|
|
877
|
+
}
|
|
878
|
+
related_formatted_events.append(formatted_event)
|
|
879
|
+
|
|
880
|
+
all_tasks[tid] = {
|
|
881
|
+
"events": related_formatted_events,
|
|
882
|
+
"initial_request_text": related_task.initial_request_text or "",
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
# Return all tasks (parent + children) for the frontend to process
|
|
886
|
+
return {"tasks": all_tasks}
|
|
887
|
+
|
|
888
|
+
except HTTPException:
|
|
889
|
+
# Re-raise HTTPExceptions (404, 403, etc.) without modification
|
|
890
|
+
raise
|
|
891
|
+
except Exception as e:
|
|
892
|
+
log.exception("%sError retrieving task events: %s", log_prefix, e)
|
|
893
|
+
raise HTTPException(
|
|
894
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
895
|
+
detail="An error occurred while retrieving the task events.",
|
|
896
|
+
)
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
@router.get("/tasks/{task_id}", tags=["Tasks"])
|
|
900
|
+
async def get_task_as_stim_file(
|
|
901
|
+
task_id: str,
|
|
902
|
+
request: FastAPIRequest,
|
|
903
|
+
db: DBSession = Depends(get_db),
|
|
904
|
+
user_id: UserId = Depends(get_user_id),
|
|
905
|
+
user_config: dict = Depends(get_user_config),
|
|
906
|
+
repo: ITaskRepository = Depends(get_task_repository),
|
|
907
|
+
):
|
|
908
|
+
"""
|
|
909
|
+
Retrieves the complete event history for a task and all its child tasks, returning it as a `.stim` file.
|
|
910
|
+
"""
|
|
911
|
+
log_prefix = f"[GET /api/v1/tasks/{task_id}] "
|
|
912
|
+
log.info("%sRequest from user %s", log_prefix, user_id)
|
|
913
|
+
|
|
914
|
+
try:
|
|
915
|
+
# Find all related task IDs (parent chain + all children)
|
|
916
|
+
related_task_ids = repo.find_all_by_parent_chain(db, task_id)
|
|
917
|
+
|
|
918
|
+
if not related_task_ids:
|
|
919
|
+
raise HTTPException(
|
|
920
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
921
|
+
detail=f"Task with ID '{task_id}' not found.",
|
|
922
|
+
)
|
|
923
|
+
|
|
924
|
+
# Load all tasks and their events
|
|
925
|
+
tasks_dict = {}
|
|
926
|
+
events_dict = {}
|
|
927
|
+
can_read_all = user_config.get("scopes", {}).get("tasks:read:all", False)
|
|
928
|
+
|
|
929
|
+
for tid in related_task_ids:
|
|
930
|
+
result = repo.find_by_id_with_events(db, tid)
|
|
931
|
+
if result:
|
|
932
|
+
task, events = result
|
|
933
|
+
|
|
934
|
+
# Check permissions for each task
|
|
935
|
+
if task.user_id != user_id and not can_read_all:
|
|
936
|
+
raise HTTPException(
|
|
937
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
938
|
+
detail="You do not have permission to view this task.",
|
|
939
|
+
)
|
|
940
|
+
|
|
941
|
+
tasks_dict[tid] = task
|
|
942
|
+
events_dict[tid] = events
|
|
943
|
+
|
|
944
|
+
if task_id not in tasks_dict:
|
|
945
|
+
raise HTTPException(
|
|
946
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
947
|
+
detail=f"Task with ID '{task_id}' not found.",
|
|
948
|
+
)
|
|
949
|
+
|
|
950
|
+
# Determine the root task (the one without a parent)
|
|
951
|
+
root_task_id = task_id
|
|
952
|
+
for tid, task in tasks_dict.items():
|
|
953
|
+
if task.parent_task_id is None:
|
|
954
|
+
root_task_id = tid
|
|
955
|
+
break
|
|
956
|
+
|
|
957
|
+
# Format into .stim structure with all tasks
|
|
958
|
+
from ..utils.stim_utils import create_stim_from_task_hierarchy
|
|
959
|
+
stim_data = create_stim_from_task_hierarchy(tasks_dict, events_dict, root_task_id)
|
|
600
960
|
|
|
601
961
|
yaml_content = yaml.dump(
|
|
602
962
|
stim_data,
|
|
@@ -608,8 +968,8 @@ async def get_task_as_stim_file(
|
|
|
608
968
|
|
|
609
969
|
return Response(
|
|
610
970
|
content=yaml_content,
|
|
611
|
-
media_type="application/
|
|
612
|
-
headers={"Content-Disposition": f'attachment; filename="{
|
|
971
|
+
media_type="application/yaml",
|
|
972
|
+
headers={"Content-Disposition": f'attachment; filename="{root_task_id}.stim"'},
|
|
613
973
|
)
|
|
614
974
|
|
|
615
975
|
except HTTPException:
|