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
|
@@ -5,7 +5,7 @@ Manages Server-Sent Event (SSE) connections for streaming task updates.
|
|
|
5
5
|
import logging
|
|
6
6
|
import asyncio
|
|
7
7
|
import threading
|
|
8
|
-
from typing import Dict, List, Any
|
|
8
|
+
from typing import Dict, List, Any, Callable, Optional
|
|
9
9
|
import json
|
|
10
10
|
import datetime
|
|
11
11
|
import math
|
|
@@ -20,38 +20,21 @@ class SSEManager:
|
|
|
20
20
|
"""
|
|
21
21
|
Manages active SSE connections and distributes events based on task ID.
|
|
22
22
|
Uses asyncio Queues for buffering events per connection.
|
|
23
|
+
|
|
24
|
+
Note: This manager uses a threading.Lock to ensure thread-safety across
|
|
25
|
+
different event loops (e.g., FastAPI event loop and SAC component event loop).
|
|
23
26
|
"""
|
|
24
27
|
|
|
25
|
-
def __init__(self, max_queue_size: int, event_buffer: SSEEventBuffer):
|
|
28
|
+
def __init__(self, max_queue_size: int, event_buffer: SSEEventBuffer, session_factory: Optional[Callable] = None):
|
|
26
29
|
self._connections: Dict[str, List[asyncio.Queue]] = {}
|
|
27
30
|
self._event_buffer = event_buffer
|
|
28
|
-
|
|
29
|
-
self.
|
|
31
|
+
# Use a single threading lock for cross-event-loop synchronization
|
|
32
|
+
self._lock = threading.Lock()
|
|
30
33
|
self.log_identifier = "[SSEManager]"
|
|
31
34
|
self._max_queue_size = max_queue_size
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
try:
|
|
36
|
-
current_loop = asyncio.get_running_loop()
|
|
37
|
-
except RuntimeError:
|
|
38
|
-
log.error(
|
|
39
|
-
"%s _get_lock must be called from within an async context.",
|
|
40
|
-
self.log_identifier,
|
|
41
|
-
)
|
|
42
|
-
raise RuntimeError(
|
|
43
|
-
"SSEManager methods must be called from within an async context"
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
with self._locks_lock:
|
|
47
|
-
if current_loop not in self._locks:
|
|
48
|
-
self._locks[current_loop] = asyncio.Lock()
|
|
49
|
-
log.debug(
|
|
50
|
-
"%s Created new lock for event loop %s",
|
|
51
|
-
self.log_identifier,
|
|
52
|
-
id(current_loop),
|
|
53
|
-
)
|
|
54
|
-
return self._locks[current_loop]
|
|
35
|
+
self._session_factory = session_factory
|
|
36
|
+
self._background_task_cache: Dict[str, bool] = {} # Cache to avoid repeated DB queries
|
|
37
|
+
self._tasks_with_prior_connection: set = set() # Track tasks that have had at least one SSE connection
|
|
55
38
|
|
|
56
39
|
def _sanitize_json(self, obj):
|
|
57
40
|
if isinstance(obj, dict):
|
|
@@ -79,27 +62,40 @@ class SSEManager:
|
|
|
79
62
|
Returns:
|
|
80
63
|
An asyncio.Queue that the SSE endpoint can consume from.
|
|
81
64
|
"""
|
|
82
|
-
|
|
83
|
-
|
|
65
|
+
connection_queue = asyncio.Queue(maxsize=self._max_queue_size)
|
|
66
|
+
buffered_events = None
|
|
67
|
+
|
|
68
|
+
# Use threading lock for cross-event-loop synchronization
|
|
69
|
+
with self._lock:
|
|
84
70
|
if task_id not in self._connections:
|
|
85
71
|
self._connections[task_id] = []
|
|
86
72
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
# Flush any pending events from the buffer to the new connection
|
|
73
|
+
# Get buffered events atomically with adding the queue to connections
|
|
90
74
|
buffered_events = self._event_buffer.get_and_remove_buffer(task_id)
|
|
91
|
-
if buffered_events:
|
|
92
|
-
for event in buffered_events:
|
|
93
|
-
await connection_queue.put(event)
|
|
94
75
|
|
|
76
|
+
# Add queue to connections BEFORE releasing lock to ensure
|
|
77
|
+
# no events are buffered after we've retrieved the buffer
|
|
95
78
|
self._connections[task_id].append(connection_queue)
|
|
79
|
+
|
|
80
|
+
# Mark this task as having had at least one connection
|
|
81
|
+
# This is used to distinguish "no connection yet" from "had connection but disconnected"
|
|
82
|
+
self._tasks_with_prior_connection.add(task_id)
|
|
83
|
+
|
|
96
84
|
log.debug(
|
|
97
85
|
"%s Created SSE connection queue for Task ID: %s. Total queues for task: %d",
|
|
98
86
|
self.log_identifier,
|
|
99
87
|
task_id,
|
|
100
88
|
len(self._connections[task_id]),
|
|
101
89
|
)
|
|
102
|
-
|
|
90
|
+
|
|
91
|
+
# Put buffered events into queue AFTER releasing the lock
|
|
92
|
+
# This is safe because the queue is already registered in _connections,
|
|
93
|
+
# so any new events will go directly to the queue via send_event
|
|
94
|
+
if buffered_events:
|
|
95
|
+
for event in buffered_events:
|
|
96
|
+
await connection_queue.put(event)
|
|
97
|
+
|
|
98
|
+
return connection_queue
|
|
103
99
|
|
|
104
100
|
async def remove_sse_connection(
|
|
105
101
|
self, task_id: str, connection_queue: asyncio.Queue
|
|
@@ -111,8 +107,7 @@ class SSEManager:
|
|
|
111
107
|
task_id: The ID of the task.
|
|
112
108
|
connection_queue: The specific queue instance to remove.
|
|
113
109
|
"""
|
|
114
|
-
|
|
115
|
-
async with lock:
|
|
110
|
+
with self._lock:
|
|
116
111
|
if task_id in self._connections:
|
|
117
112
|
try:
|
|
118
113
|
self._connections[task_id].remove(connection_queue)
|
|
@@ -142,6 +137,49 @@ class SSEManager:
|
|
|
142
137
|
task_id,
|
|
143
138
|
)
|
|
144
139
|
|
|
140
|
+
def _is_background_task(self, task_id: str) -> bool:
|
|
141
|
+
"""
|
|
142
|
+
Check if a task is a background task by querying the database.
|
|
143
|
+
Uses caching to avoid repeated queries.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
task_id: The ID of the task to check
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
True if the task is a background task, False otherwise
|
|
150
|
+
"""
|
|
151
|
+
# Check cache first
|
|
152
|
+
if task_id in self._background_task_cache:
|
|
153
|
+
return self._background_task_cache[task_id]
|
|
154
|
+
|
|
155
|
+
# If no session factory, assume not a background task
|
|
156
|
+
if not self._session_factory:
|
|
157
|
+
return False
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
from .repository.task_repository import TaskRepository
|
|
161
|
+
|
|
162
|
+
db = self._session_factory()
|
|
163
|
+
try:
|
|
164
|
+
repo = TaskRepository()
|
|
165
|
+
task = repo.find_by_id(db, task_id)
|
|
166
|
+
is_background = task and task.background_execution_enabled
|
|
167
|
+
|
|
168
|
+
# Cache the result
|
|
169
|
+
self._background_task_cache[task_id] = is_background
|
|
170
|
+
|
|
171
|
+
return is_background
|
|
172
|
+
finally:
|
|
173
|
+
db.close()
|
|
174
|
+
except Exception as e:
|
|
175
|
+
log.warning(
|
|
176
|
+
"%s Failed to check if task %s is a background task: %s",
|
|
177
|
+
self.log_identifier,
|
|
178
|
+
task_id,
|
|
179
|
+
e,
|
|
180
|
+
)
|
|
181
|
+
return False
|
|
182
|
+
|
|
145
183
|
async def send_event(
|
|
146
184
|
self, task_id: str, event_data: Dict[str, Any], event_type: str = "message"
|
|
147
185
|
):
|
|
@@ -154,102 +192,130 @@ class SSEManager:
|
|
|
154
192
|
event_data: The dictionary representing the A2A event (e.g., TaskStatusUpdateEvent).
|
|
155
193
|
event_type: The type of the SSE event (default: "message").
|
|
156
194
|
"""
|
|
157
|
-
|
|
158
|
-
|
|
195
|
+
# Serialize data outside the lock
|
|
196
|
+
try:
|
|
197
|
+
serialized_data = json.dumps(
|
|
198
|
+
self._sanitize_json(event_data), allow_nan=False
|
|
199
|
+
)
|
|
200
|
+
except Exception as json_err:
|
|
201
|
+
log.error(
|
|
202
|
+
"%s Failed to JSON serialize event data for Task ID %s: %s",
|
|
203
|
+
self.log_identifier,
|
|
204
|
+
task_id,
|
|
205
|
+
json_err,
|
|
206
|
+
)
|
|
207
|
+
return
|
|
208
|
+
|
|
209
|
+
sse_payload = {"event": event_type, "data": serialized_data}
|
|
210
|
+
|
|
211
|
+
# Get queues and decide action under the lock
|
|
212
|
+
queues_copy = None
|
|
213
|
+
|
|
214
|
+
with self._lock:
|
|
159
215
|
queues = self._connections.get(task_id)
|
|
160
216
|
|
|
217
|
+
if not queues:
|
|
218
|
+
# Check if this is a background task (outside lock would be better,
|
|
219
|
+
# but we need the decision to be atomic with the buffering)
|
|
220
|
+
is_background_task = self._is_background_task(task_id)
|
|
221
|
+
|
|
222
|
+
# Check if this task has ever had a connection
|
|
223
|
+
has_had_connection = task_id in self._tasks_with_prior_connection
|
|
224
|
+
|
|
225
|
+
# Only drop events for background tasks that have HAD a connection before
|
|
226
|
+
# If no connection has ever been made, we must buffer so the first client gets the events
|
|
227
|
+
if is_background_task and has_had_connection:
|
|
228
|
+
# For background tasks where client disconnected, drop events to prevent buffer overflow
|
|
229
|
+
log.debug(
|
|
230
|
+
"%s No active SSE connections for background task %s (had prior connection). Dropping event to prevent buffer overflow.",
|
|
231
|
+
self.log_identifier,
|
|
232
|
+
task_id,
|
|
233
|
+
)
|
|
234
|
+
else:
|
|
235
|
+
log.debug(
|
|
236
|
+
"%s No active SSE connections for Task ID: %s. Buffering event.",
|
|
237
|
+
self.log_identifier,
|
|
238
|
+
task_id,
|
|
239
|
+
)
|
|
240
|
+
self._event_buffer.buffer_event(task_id, sse_payload)
|
|
241
|
+
return
|
|
242
|
+
else:
|
|
243
|
+
# Make a copy of queues to iterate outside the lock
|
|
244
|
+
queues_copy = list(queues)
|
|
245
|
+
|
|
246
|
+
# Log the payload outside the lock
|
|
247
|
+
if trace_logger.isEnabledFor(logging.DEBUG):
|
|
248
|
+
trace_logger.debug(
|
|
249
|
+
"%s Prepared SSE payload for Task ID %s: %s",
|
|
250
|
+
self.log_identifier,
|
|
251
|
+
task_id,
|
|
252
|
+
sse_payload,
|
|
253
|
+
)
|
|
254
|
+
else:
|
|
255
|
+
log.debug(
|
|
256
|
+
"%s Prepared SSE payload for Task ID %s",
|
|
257
|
+
self.log_identifier,
|
|
258
|
+
task_id,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
# Send to queues outside the lock (async operations)
|
|
262
|
+
queues_to_remove = []
|
|
263
|
+
for connection_queue in queues_copy:
|
|
161
264
|
try:
|
|
162
|
-
|
|
163
|
-
|
|
265
|
+
await asyncio.wait_for(
|
|
266
|
+
connection_queue.put(sse_payload), timeout=0.1
|
|
164
267
|
)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
"%s Failed to JSON serialize event data for Task ID %s: %s",
|
|
268
|
+
log.debug(
|
|
269
|
+
"%s Queued event for Task ID: %s to one connection.",
|
|
168
270
|
self.log_identifier,
|
|
169
271
|
task_id,
|
|
170
|
-
json_err,
|
|
171
272
|
)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if not queues:
|
|
177
|
-
log.debug(
|
|
178
|
-
"%s No active SSE connections for Task ID: %s. Buffering event.",
|
|
273
|
+
except asyncio.QueueFull:
|
|
274
|
+
log.warning(
|
|
275
|
+
"%s SSE connection queue full for Task ID: %s. Event dropped for one connection.",
|
|
179
276
|
self.log_identifier,
|
|
180
277
|
task_id,
|
|
181
278
|
)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
trace_logger.debug(
|
|
187
|
-
"%s Prepared SSE payload for Task ID %s: %s",
|
|
279
|
+
queues_to_remove.append(connection_queue)
|
|
280
|
+
except asyncio.TimeoutError:
|
|
281
|
+
log.warning(
|
|
282
|
+
"%s Timeout putting event onto SSE queue for Task ID: %s. Event dropped for one connection.",
|
|
188
283
|
self.log_identifier,
|
|
189
284
|
task_id,
|
|
190
|
-
sse_payload,
|
|
191
285
|
)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
286
|
+
queues_to_remove.append(connection_queue)
|
|
287
|
+
except Exception as e:
|
|
288
|
+
log.error(
|
|
289
|
+
"%s Error putting event onto queue for Task ID %s: %s",
|
|
195
290
|
self.log_identifier,
|
|
196
291
|
task_id,
|
|
292
|
+
e,
|
|
197
293
|
)
|
|
294
|
+
queues_to_remove.append(connection_queue)
|
|
198
295
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
"%s Timeout putting event onto SSE queue for Task ID: %s. Event dropped for one connection.",
|
|
220
|
-
self.log_identifier,
|
|
221
|
-
task_id,
|
|
222
|
-
)
|
|
223
|
-
queues_to_remove.append(connection_queue)
|
|
224
|
-
except Exception as e:
|
|
225
|
-
log.error(
|
|
226
|
-
"%s Error putting event onto queue for Task ID %s: %s",
|
|
227
|
-
self.log_identifier,
|
|
228
|
-
task_id,
|
|
229
|
-
e,
|
|
230
|
-
)
|
|
231
|
-
queues_to_remove.append(connection_queue)
|
|
232
|
-
|
|
233
|
-
if queues_to_remove and task_id in self._connections:
|
|
234
|
-
current_queues = self._connections[task_id]
|
|
235
|
-
for q in queues_to_remove:
|
|
236
|
-
try:
|
|
237
|
-
current_queues.remove(q)
|
|
238
|
-
log.warning(
|
|
239
|
-
"%s Removed potentially broken/full SSE queue for Task ID: %s",
|
|
296
|
+
# Remove broken queues under the lock
|
|
297
|
+
if queues_to_remove:
|
|
298
|
+
with self._lock:
|
|
299
|
+
if task_id in self._connections:
|
|
300
|
+
current_queues = self._connections[task_id]
|
|
301
|
+
for q in queues_to_remove:
|
|
302
|
+
try:
|
|
303
|
+
current_queues.remove(q)
|
|
304
|
+
log.warning(
|
|
305
|
+
"%s Removed potentially broken/full SSE queue for Task ID: %s",
|
|
306
|
+
self.log_identifier,
|
|
307
|
+
task_id,
|
|
308
|
+
)
|
|
309
|
+
except ValueError:
|
|
310
|
+
pass
|
|
311
|
+
|
|
312
|
+
if not current_queues:
|
|
313
|
+
del self._connections[task_id]
|
|
314
|
+
log.debug(
|
|
315
|
+
"%s Removed Task ID entry: %s after cleaning queues.",
|
|
240
316
|
self.log_identifier,
|
|
241
317
|
task_id,
|
|
242
318
|
)
|
|
243
|
-
except ValueError:
|
|
244
|
-
pass
|
|
245
|
-
|
|
246
|
-
if not current_queues:
|
|
247
|
-
del self._connections[task_id]
|
|
248
|
-
log.debug(
|
|
249
|
-
"%s Removed Task ID entry: %s after cleaning queues.",
|
|
250
|
-
self.log_identifier,
|
|
251
|
-
task_id,
|
|
252
|
-
)
|
|
253
319
|
|
|
254
320
|
async def close_connection(self, task_id: str, connection_queue: asyncio.Queue):
|
|
255
321
|
"""
|
|
@@ -285,54 +351,58 @@ class SSEManager:
|
|
|
285
351
|
finally:
|
|
286
352
|
await self.remove_sse_connection(task_id, connection_queue)
|
|
287
353
|
|
|
354
|
+
async def drain_buffer_for_background_task(self, task_id: str):
|
|
355
|
+
"""
|
|
356
|
+
Drains the event buffer for a background task when a client disconnects.
|
|
357
|
+
This prevents buffer overflow warnings when background tasks continue
|
|
358
|
+
generating events with no active consumers.
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
task_id: The ID of the background task
|
|
362
|
+
"""
|
|
363
|
+
log.info(
|
|
364
|
+
"%s Draining event buffer for background task: %s",
|
|
365
|
+
self.log_identifier,
|
|
366
|
+
task_id,
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
# Remove any buffered events to prevent overflow
|
|
370
|
+
buffered_events = self._event_buffer.get_and_remove_buffer(task_id)
|
|
371
|
+
if buffered_events:
|
|
372
|
+
log.info(
|
|
373
|
+
"%s Drained %d buffered events for background task: %s",
|
|
374
|
+
self.log_identifier,
|
|
375
|
+
len(buffered_events),
|
|
376
|
+
task_id,
|
|
377
|
+
)
|
|
378
|
+
else:
|
|
379
|
+
log.debug(
|
|
380
|
+
"%s No buffered events to drain for background task: %s",
|
|
381
|
+
self.log_identifier,
|
|
382
|
+
task_id,
|
|
383
|
+
)
|
|
384
|
+
|
|
288
385
|
async def close_all_for_task(self, task_id: str):
|
|
289
386
|
"""
|
|
290
387
|
Closes all SSE connections associated with a specific task.
|
|
291
388
|
If a connection existed, it also cleans up the event buffer.
|
|
292
389
|
If no connection ever existed, the buffer is left for a late-connecting client.
|
|
293
390
|
"""
|
|
294
|
-
|
|
295
|
-
|
|
391
|
+
queues_to_close = None
|
|
392
|
+
should_remove_buffer = False
|
|
393
|
+
|
|
394
|
+
with self._lock:
|
|
296
395
|
if task_id in self._connections:
|
|
297
396
|
# This is the "normal" case: a client is or was connected.
|
|
298
397
|
# It's safe to clean up everything.
|
|
299
398
|
queues_to_close = self._connections.pop(task_id)
|
|
399
|
+
should_remove_buffer = True
|
|
300
400
|
log.debug(
|
|
301
401
|
"%s Closing %d SSE connections for Task ID: %s and cleaning up buffer.",
|
|
302
402
|
self.log_identifier,
|
|
303
403
|
len(queues_to_close),
|
|
304
404
|
task_id,
|
|
305
405
|
)
|
|
306
|
-
for q in queues_to_close:
|
|
307
|
-
try:
|
|
308
|
-
await asyncio.wait_for(q.put(None), timeout=0.1)
|
|
309
|
-
except asyncio.QueueFull:
|
|
310
|
-
log.warning(
|
|
311
|
-
"%s Could not put None (close signal) on full queue during close_all for Task ID: %s.",
|
|
312
|
-
self.log_identifier,
|
|
313
|
-
task_id,
|
|
314
|
-
)
|
|
315
|
-
except asyncio.TimeoutError:
|
|
316
|
-
log.warning(
|
|
317
|
-
"%s Timeout putting None (close signal) on queue during close_all for Task ID: %s.",
|
|
318
|
-
self.log_identifier,
|
|
319
|
-
task_id,
|
|
320
|
-
)
|
|
321
|
-
except Exception as e:
|
|
322
|
-
log.error(
|
|
323
|
-
"%s Error putting None (close signal) on queue during close_all for Task ID %s: %s",
|
|
324
|
-
self.log_identifier,
|
|
325
|
-
task_id,
|
|
326
|
-
e,
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
# Since a connection existed, the buffer is no longer needed.
|
|
330
|
-
self._event_buffer.remove_buffer(task_id)
|
|
331
|
-
log.debug(
|
|
332
|
-
"%s Removed Task ID entry: %s and signaled queues to close.",
|
|
333
|
-
self.log_identifier,
|
|
334
|
-
task_id,
|
|
335
|
-
)
|
|
336
406
|
else:
|
|
337
407
|
# This is the "race condition" case: no client has connected yet.
|
|
338
408
|
# We MUST leave the buffer intact for the late-connecting client.
|
|
@@ -342,39 +412,80 @@ class SSEManager:
|
|
|
342
412
|
task_id,
|
|
343
413
|
)
|
|
344
414
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
415
|
+
# Close queues outside the lock (async operations)
|
|
416
|
+
if queues_to_close:
|
|
417
|
+
for q in queues_to_close:
|
|
418
|
+
try:
|
|
419
|
+
await asyncio.wait_for(q.put(None), timeout=0.1)
|
|
420
|
+
except asyncio.QueueFull:
|
|
421
|
+
log.warning(
|
|
422
|
+
"%s Could not put None (close signal) on full queue during close_all for Task ID: %s.",
|
|
423
|
+
self.log_identifier,
|
|
424
|
+
task_id,
|
|
425
|
+
)
|
|
426
|
+
except asyncio.TimeoutError:
|
|
427
|
+
log.warning(
|
|
428
|
+
"%s Timeout putting None (close signal) on queue during close_all for Task ID: %s.",
|
|
429
|
+
self.log_identifier,
|
|
430
|
+
task_id,
|
|
431
|
+
)
|
|
432
|
+
except Exception as e:
|
|
433
|
+
log.error(
|
|
434
|
+
"%s Error putting None (close signal) on queue during close_all for Task ID %s: %s",
|
|
435
|
+
self.log_identifier,
|
|
436
|
+
task_id,
|
|
437
|
+
e,
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
# Since a connection existed, the buffer is no longer needed.
|
|
441
|
+
# This is safe to do without lock since we already removed the task from _connections
|
|
442
|
+
if should_remove_buffer:
|
|
443
|
+
self._event_buffer.remove_buffer(task_id)
|
|
444
|
+
|
|
445
|
+
# Clean up the connection tracking
|
|
446
|
+
with self._lock:
|
|
447
|
+
self._tasks_with_prior_connection.discard(task_id)
|
|
448
|
+
|
|
351
449
|
log.debug(
|
|
352
|
-
"%s
|
|
450
|
+
"%s Removed Task ID entry: %s and signaled queues to close.",
|
|
353
451
|
self.log_identifier,
|
|
354
|
-
|
|
452
|
+
task_id,
|
|
355
453
|
)
|
|
356
454
|
|
|
455
|
+
def cleanup_old_locks(self):
|
|
456
|
+
"""Legacy method - no longer needed with single threading lock.
|
|
457
|
+
Kept for API compatibility but does nothing."""
|
|
458
|
+
pass
|
|
459
|
+
|
|
357
460
|
async def close_all(self):
|
|
358
461
|
"""Closes all active SSE connections managed by this instance."""
|
|
359
462
|
self.cleanup_old_locks()
|
|
360
|
-
|
|
361
|
-
|
|
463
|
+
|
|
464
|
+
# Collect all queues to close under the lock
|
|
465
|
+
all_queues_to_close = []
|
|
466
|
+
all_task_ids = []
|
|
467
|
+
|
|
468
|
+
with self._lock:
|
|
362
469
|
log.debug("%s Closing all active SSE connections...", self.log_identifier)
|
|
363
470
|
all_task_ids = list(self._connections.keys())
|
|
364
|
-
closed_count = 0
|
|
365
471
|
for task_id in all_task_ids:
|
|
366
472
|
if task_id in self._connections:
|
|
367
473
|
queues = self._connections.pop(task_id)
|
|
368
|
-
|
|
369
|
-
for q in queues:
|
|
370
|
-
try:
|
|
371
|
-
await asyncio.wait_for(q.put(None), timeout=0.1)
|
|
372
|
-
except Exception:
|
|
373
|
-
pass
|
|
374
|
-
log.debug(
|
|
375
|
-
"%s Closed %d connections for tasks: %s",
|
|
376
|
-
self.log_identifier,
|
|
377
|
-
closed_count,
|
|
378
|
-
all_task_ids,
|
|
379
|
-
)
|
|
474
|
+
all_queues_to_close.extend(queues)
|
|
380
475
|
self._connections.clear()
|
|
476
|
+
self._tasks_with_prior_connection.clear()
|
|
477
|
+
|
|
478
|
+
# Close queues outside the lock (async operations)
|
|
479
|
+
closed_count = len(all_queues_to_close)
|
|
480
|
+
for q in all_queues_to_close:
|
|
481
|
+
try:
|
|
482
|
+
await asyncio.wait_for(q.put(None), timeout=0.1)
|
|
483
|
+
except Exception:
|
|
484
|
+
pass
|
|
485
|
+
|
|
486
|
+
log.debug(
|
|
487
|
+
"%s Closed %d connections for tasks: %s",
|
|
488
|
+
self.log_identifier,
|
|
489
|
+
closed_count,
|
|
490
|
+
all_task_ids,
|
|
491
|
+
)
|