solace-agent-mesh 1.6.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/app_llm_agent.py +26 -0
- solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +165 -1
- solace_agent_mesh/agent/adk/artifacts/s3_artifact_service.py +163 -0
- solace_agent_mesh/agent/adk/callbacks.py +852 -109
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +234 -36
- 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 +77 -21
- solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +24 -137
- solace_agent_mesh/agent/adk/runner.py +85 -20
- solace_agent_mesh/agent/adk/schema_migration.py +88 -0
- solace_agent_mesh/agent/adk/services.py +94 -18
- solace_agent_mesh/agent/adk/setup.py +281 -65
- solace_agent_mesh/agent/adk/stream_parser.py +231 -37
- solace_agent_mesh/agent/adk/tool_wrapper.py +3 -0
- solace_agent_mesh/agent/protocol/event_handlers.py +472 -137
- solace_agent_mesh/agent/proxies/a2a/app.py +3 -2
- 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/app.py +3 -2
- 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 +91 -3
- solace_agent_mesh/agent/sac/component.py +591 -157
- solace_agent_mesh/agent/sac/patch_adk.py +8 -16
- solace_agent_mesh/agent/sac/task_execution_context.py +146 -4
- 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 +710 -171
- solace_agent_mesh/agent/tools/deep_research_tools.py +2161 -0
- solace_agent_mesh/agent/tools/dynamic_tool.py +2 -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 +57 -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 +248 -6
- 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/2987107d.a80604f9.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/631738c7.fa471607.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/6a520c9d.b6e3f2ce.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6aaedf65.7253541d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.a5b36a60.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6d84eae0.fd23ba4a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/71da7b71.374b9d54.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/8b032486.91a91afc.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/ad87452a.9d73dad6.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/da0b5bad.b62f7b08.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd817ffc.c37a755e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd81e2b8.b682e9c2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/de915948.44a432bc.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/ff4d71f2.74710fc1.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 +82 -68
- 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 +182 -0
- 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 -49
- solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +29 -30
- 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 +90 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +17 -16
- 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 +162 -171
- 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 +86 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +67 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +23 -19
- 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 +112 -87
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +440 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +87 -64
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +62 -0
- 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 -37
- 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 +311 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +39 -42
- 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 +251 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +88 -0
- 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/docs_cmd.py +4 -1
- 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-BTf6dqwp.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-CGk8Suyh.js +565 -0
- 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/events.py +2 -1
- solace_agent_mesh/common/a2a/protocol.py +5 -0
- solace_agent_mesh/common/a2a/types.py +2 -1
- solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +23 -6
- solace_agent_mesh/common/a2a_spec/schemas/feedback_event.json +51 -0
- solace_agent_mesh/common/agent_registry.py +38 -11
- solace_agent_mesh/common/data_parts.py +144 -4
- 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 +97 -19
- solace_agent_mesh/common/sam_events/event_service.py +2 -2
- solace_agent_mesh/common/services/employee_service.py +1 -1
- solace_agent_mesh/common/utils/embeds/constants.py +1 -0
- solace_agent_mesh/common/utils/embeds/converter.py +1 -8
- solace_agent_mesh/common/utils/embeds/modifiers.py +4 -28
- solace_agent_mesh/common/utils/embeds/resolver.py +152 -31
- solace_agent_mesh/common/utils/embeds/types.py +9 -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/pydantic_utils.py +90 -3
- 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/__init__.py +1 -0
- solace_agent_mesh/gateway/adapter/base.py +170 -0
- solace_agent_mesh/gateway/adapter/types.py +230 -0
- solace_agent_mesh/gateway/base/app.py +39 -2
- solace_agent_mesh/gateway/base/auth_interface.py +103 -0
- solace_agent_mesh/gateway/base/component.py +1027 -151
- solace_agent_mesh/gateway/generic/__init__.py +1 -0
- solace_agent_mesh/gateway/generic/app.py +50 -0
- solace_agent_mesh/gateway/generic/component.py +894 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +0 -7
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_project_users_table.py +72 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +109 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +26 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_projects_table.py +135 -0
- 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 +40 -11
- solace_agent_mesh/gateway/http_sse/component.py +285 -160
- solace_agent_mesh/gateway/http_sse/dependencies.py +149 -114
- solace_agent_mesh/gateway/http_sse/main.py +68 -450
- solace_agent_mesh/gateway/http_sse/repository/__init__.py +19 -1
- solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +2 -2
- solace_agent_mesh/gateway/http_sse/repository/entities/project.py +81 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +47 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session.py +26 -3
- solace_agent_mesh/gateway/http_sse/repository/entities/task.py +7 -0
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +47 -0
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +114 -6
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +13 -0
- solace_agent_mesh/gateway/http_sse/repository/models/project_model.py +51 -0
- solace_agent_mesh/gateway/http_sse/repository/models/project_user_model.py +75 -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 +8 -2
- solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +8 -1
- solace_agent_mesh/gateway/http_sse/repository/project_repository.py +172 -0
- solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +186 -0
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +177 -11
- 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 +256 -58
- solace_agent_mesh/gateway/http_sse/routers/auth.py +168 -134
- solace_agent_mesh/gateway/http_sse/routers/config.py +302 -8
- 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/project_requests.py +48 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +14 -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 +31 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +5 -2
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/version_responses.py +31 -0
- solace_agent_mesh/gateway/http_sse/routers/feedback.py +133 -2
- solace_agent_mesh/gateway/http_sse/routers/people.py +2 -2
- solace_agent_mesh/gateway/http_sse/routers/projects.py +768 -0
- solace_agent_mesh/gateway/http_sse/routers/prompts.py +1416 -0
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +167 -7
- solace_agent_mesh/gateway/http_sse/routers/speech.py +355 -0
- solace_agent_mesh/gateway/http_sse/routers/sse.py +131 -8
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +670 -18
- 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 +92 -9
- 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 +930 -0
- solace_agent_mesh/gateway/http_sse/services/prompt_builder_assistant.py +303 -0
- solace_agent_mesh/gateway/http_sse/services/session_service.py +361 -12
- solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +354 -4
- solace_agent_mesh/gateway/http_sse/session_manager.py +15 -15
- solace_agent_mesh/gateway/http_sse/sse_manager.py +286 -166
- 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 +19 -5
- 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.6.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/METADATA +31 -12
- solace_agent_mesh-1.13.2.dist-info/RECORD +591 -0
- {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/WHEEL +1 -1
- solace_agent_mesh/agent/adk/adk_llm.txt +0 -232
- 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 -142
- solace_agent_mesh/agent/agent_llm.txt +0 -378
- 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/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 -57
- solace_agent_mesh/agent/testing/testing_llm_detail.txt +0 -68
- solace_agent_mesh/agent/tools/tools_llm.txt +0 -263
- solace_agent_mesh/agent/tools/tools_llm_detail.txt +0 -274
- solace_agent_mesh/agent/utils/utils_llm.txt +0 -138
- solace_agent_mesh/agent/utils/utils_llm_detail.txt +0 -149
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/240a0364.7eac6021.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.76654dd9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/631738c7.a8b1ef8b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/71da7b71.38583438.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/8024126c.56e59919.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.b5ddb7a1.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.3e6dd091.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/da0b5bad.d08a9466.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.6b9493d0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e6f9706b.e74a984d.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e92d0134.cf6d6522.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.42f59cdd.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.b12eac43.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.e268214e.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1761248203150.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1761248203150.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-CaY59VuC.js +0 -25
- solace_agent_mesh/client/webui/frontend/static/assets/main-B32noGmR.js +0 -342
- solace_agent_mesh/client/webui/frontend/static/assets/main-DHJKSW1S.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-BEmvJSYz.js +0 -405
- solace_agent_mesh/common/a2a/a2a_llm.txt +0 -182
- solace_agent_mesh/common/a2a/a2a_llm_detail.txt +0 -193
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +0 -407
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +0 -736
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +0 -313
- solace_agent_mesh/common/common_llm.txt +0 -251
- 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 -80
- solace_agent_mesh/common/services/services_llm.txt +0 -363
- 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 -336
- 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 -224
- solace_agent_mesh/gateway/base/base_llm_detail.txt +0 -235
- solace_agent_mesh/gateway/gateway_llm.txt +0 -373
- solace_agent_mesh/gateway/gateway_llm_detail.txt +0 -3885
- solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +0 -295
- solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +0 -155
- 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 -263
- solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +0 -266
- solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +0 -340
- solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +0 -346
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +0 -83
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +0 -107
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +0 -314
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +0 -297
- solace_agent_mesh/gateway/http_sse/shared/__init__.py +0 -146
- solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +0 -285
- 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-1.6.1.dist-info/RECORD +0 -525
- /solace_agent_mesh/assets/docs/assets/js/{main.b12eac43.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.6.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.6.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
|
|
@@ -13,43 +13,28 @@ import math
|
|
|
13
13
|
from .sse_event_buffer import SSEEventBuffer
|
|
14
14
|
|
|
15
15
|
log = logging.getLogger(__name__)
|
|
16
|
+
trace_logger = logging.getLogger("sam_trace")
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
class SSEManager:
|
|
18
20
|
"""
|
|
19
21
|
Manages active SSE connections and distributes events based on task ID.
|
|
20
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).
|
|
21
26
|
"""
|
|
22
27
|
|
|
23
|
-
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):
|
|
24
29
|
self._connections: Dict[str, List[asyncio.Queue]] = {}
|
|
25
30
|
self._event_buffer = event_buffer
|
|
26
|
-
|
|
27
|
-
self.
|
|
31
|
+
# Use a single threading lock for cross-event-loop synchronization
|
|
32
|
+
self._lock = threading.Lock()
|
|
28
33
|
self.log_identifier = "[SSEManager]"
|
|
29
34
|
self._max_queue_size = max_queue_size
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
try:
|
|
34
|
-
current_loop = asyncio.get_running_loop()
|
|
35
|
-
except RuntimeError:
|
|
36
|
-
log.error(
|
|
37
|
-
"%s _get_lock must be called from within an async context.",
|
|
38
|
-
self.log_identifier,
|
|
39
|
-
)
|
|
40
|
-
raise RuntimeError(
|
|
41
|
-
"SSEManager methods must be called from within an async context"
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
with self._locks_lock:
|
|
45
|
-
if current_loop not in self._locks:
|
|
46
|
-
self._locks[current_loop] = asyncio.Lock()
|
|
47
|
-
log.debug(
|
|
48
|
-
"%s Created new lock for event loop %s",
|
|
49
|
-
self.log_identifier,
|
|
50
|
-
id(current_loop),
|
|
51
|
-
)
|
|
52
|
-
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
|
|
53
38
|
|
|
54
39
|
def _sanitize_json(self, obj):
|
|
55
40
|
if isinstance(obj, dict):
|
|
@@ -77,27 +62,40 @@ class SSEManager:
|
|
|
77
62
|
Returns:
|
|
78
63
|
An asyncio.Queue that the SSE endpoint can consume from.
|
|
79
64
|
"""
|
|
80
|
-
|
|
81
|
-
|
|
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:
|
|
82
70
|
if task_id not in self._connections:
|
|
83
71
|
self._connections[task_id] = []
|
|
84
72
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
# Flush any pending events from the buffer to the new connection
|
|
73
|
+
# Get buffered events atomically with adding the queue to connections
|
|
88
74
|
buffered_events = self._event_buffer.get_and_remove_buffer(task_id)
|
|
89
|
-
if buffered_events:
|
|
90
|
-
for event in buffered_events:
|
|
91
|
-
await connection_queue.put(event)
|
|
92
75
|
|
|
76
|
+
# Add queue to connections BEFORE releasing lock to ensure
|
|
77
|
+
# no events are buffered after we've retrieved the buffer
|
|
93
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
|
+
|
|
94
84
|
log.debug(
|
|
95
85
|
"%s Created SSE connection queue for Task ID: %s. Total queues for task: %d",
|
|
96
86
|
self.log_identifier,
|
|
97
87
|
task_id,
|
|
98
88
|
len(self._connections[task_id]),
|
|
99
89
|
)
|
|
100
|
-
|
|
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
|
|
101
99
|
|
|
102
100
|
async def remove_sse_connection(
|
|
103
101
|
self, task_id: str, connection_queue: asyncio.Queue
|
|
@@ -109,8 +107,7 @@ class SSEManager:
|
|
|
109
107
|
task_id: The ID of the task.
|
|
110
108
|
connection_queue: The specific queue instance to remove.
|
|
111
109
|
"""
|
|
112
|
-
|
|
113
|
-
async with lock:
|
|
110
|
+
with self._lock:
|
|
114
111
|
if task_id in self._connections:
|
|
115
112
|
try:
|
|
116
113
|
self._connections[task_id].remove(connection_queue)
|
|
@@ -140,6 +137,49 @@ class SSEManager:
|
|
|
140
137
|
task_id,
|
|
141
138
|
)
|
|
142
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
|
+
|
|
143
183
|
async def send_event(
|
|
144
184
|
self, task_id: str, event_data: Dict[str, Any], event_type: str = "message"
|
|
145
185
|
):
|
|
@@ -152,95 +192,130 @@ class SSEManager:
|
|
|
152
192
|
event_data: The dictionary representing the A2A event (e.g., TaskStatusUpdateEvent).
|
|
153
193
|
event_type: The type of the SSE event (default: "message").
|
|
154
194
|
"""
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
|
158
208
|
|
|
159
|
-
|
|
160
|
-
serialized_data = json.dumps(
|
|
161
|
-
self._sanitize_json(event_data), allow_nan=False
|
|
162
|
-
)
|
|
163
|
-
except Exception as json_err:
|
|
164
|
-
log.error(
|
|
165
|
-
"%s Failed to JSON serialize event data for Task ID %s: %s",
|
|
166
|
-
self.log_identifier,
|
|
167
|
-
task_id,
|
|
168
|
-
json_err,
|
|
169
|
-
)
|
|
170
|
-
return
|
|
209
|
+
sse_payload = {"event": event_type, "data": serialized_data}
|
|
171
210
|
|
|
172
|
-
|
|
211
|
+
# Get queues and decide action under the lock
|
|
212
|
+
queues_copy = None
|
|
213
|
+
|
|
214
|
+
with self._lock:
|
|
215
|
+
queues = self._connections.get(task_id)
|
|
173
216
|
|
|
174
217
|
if not queues:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
task_id,
|
|
179
|
-
)
|
|
180
|
-
self._event_buffer.buffer_event(task_id, sse_payload)
|
|
181
|
-
return
|
|
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)
|
|
182
221
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
self.log_identifier,
|
|
186
|
-
task_id,
|
|
187
|
-
sse_payload,
|
|
188
|
-
)
|
|
222
|
+
# Check if this task has ever had a connection
|
|
223
|
+
has_had_connection = task_id in self._tasks_with_prior_connection
|
|
189
224
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
connection_queue.put(sse_payload), timeout=0.1
|
|
195
|
-
)
|
|
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
|
|
196
229
|
log.debug(
|
|
197
|
-
"%s
|
|
230
|
+
"%s No active SSE connections for background task %s (had prior connection). Dropping event to prevent buffer overflow.",
|
|
198
231
|
self.log_identifier,
|
|
199
232
|
task_id,
|
|
200
233
|
)
|
|
201
|
-
|
|
202
|
-
log.
|
|
203
|
-
"%s
|
|
204
|
-
self.log_identifier,
|
|
205
|
-
task_id,
|
|
206
|
-
)
|
|
207
|
-
queues_to_remove.append(connection_queue)
|
|
208
|
-
except asyncio.TimeoutError:
|
|
209
|
-
log.warning(
|
|
210
|
-
"%s Timeout putting event onto SSE queue for Task ID: %s. Event dropped for one connection.",
|
|
211
|
-
self.log_identifier,
|
|
212
|
-
task_id,
|
|
213
|
-
)
|
|
214
|
-
queues_to_remove.append(connection_queue)
|
|
215
|
-
except Exception as e:
|
|
216
|
-
log.error(
|
|
217
|
-
"%s Error putting event onto queue for Task ID %s: %s",
|
|
234
|
+
else:
|
|
235
|
+
log.debug(
|
|
236
|
+
"%s No active SSE connections for Task ID: %s. Buffering event.",
|
|
218
237
|
self.log_identifier,
|
|
219
238
|
task_id,
|
|
220
|
-
e,
|
|
221
239
|
)
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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:
|
|
264
|
+
try:
|
|
265
|
+
await asyncio.wait_for(
|
|
266
|
+
connection_queue.put(sse_payload), timeout=0.1
|
|
267
|
+
)
|
|
268
|
+
log.debug(
|
|
269
|
+
"%s Queued event for Task ID: %s to one connection.",
|
|
270
|
+
self.log_identifier,
|
|
271
|
+
task_id,
|
|
272
|
+
)
|
|
273
|
+
except asyncio.QueueFull:
|
|
274
|
+
log.warning(
|
|
275
|
+
"%s SSE connection queue full for Task ID: %s. Event dropped for one connection.",
|
|
276
|
+
self.log_identifier,
|
|
277
|
+
task_id,
|
|
278
|
+
)
|
|
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.",
|
|
283
|
+
self.log_identifier,
|
|
284
|
+
task_id,
|
|
285
|
+
)
|
|
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",
|
|
290
|
+
self.log_identifier,
|
|
291
|
+
task_id,
|
|
292
|
+
e,
|
|
293
|
+
)
|
|
294
|
+
queues_to_remove.append(connection_queue)
|
|
295
|
+
|
|
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.",
|
|
231
316
|
self.log_identifier,
|
|
232
317
|
task_id,
|
|
233
318
|
)
|
|
234
|
-
except ValueError:
|
|
235
|
-
pass
|
|
236
|
-
|
|
237
|
-
if not current_queues:
|
|
238
|
-
del self._connections[task_id]
|
|
239
|
-
log.debug(
|
|
240
|
-
"%s Removed Task ID entry: %s after cleaning queues.",
|
|
241
|
-
self.log_identifier,
|
|
242
|
-
task_id,
|
|
243
|
-
)
|
|
244
319
|
|
|
245
320
|
async def close_connection(self, task_id: str, connection_queue: asyncio.Queue):
|
|
246
321
|
"""
|
|
@@ -276,54 +351,58 @@ class SSEManager:
|
|
|
276
351
|
finally:
|
|
277
352
|
await self.remove_sse_connection(task_id, connection_queue)
|
|
278
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
|
+
|
|
279
385
|
async def close_all_for_task(self, task_id: str):
|
|
280
386
|
"""
|
|
281
387
|
Closes all SSE connections associated with a specific task.
|
|
282
388
|
If a connection existed, it also cleans up the event buffer.
|
|
283
389
|
If no connection ever existed, the buffer is left for a late-connecting client.
|
|
284
390
|
"""
|
|
285
|
-
|
|
286
|
-
|
|
391
|
+
queues_to_close = None
|
|
392
|
+
should_remove_buffer = False
|
|
393
|
+
|
|
394
|
+
with self._lock:
|
|
287
395
|
if task_id in self._connections:
|
|
288
396
|
# This is the "normal" case: a client is or was connected.
|
|
289
397
|
# It's safe to clean up everything.
|
|
290
398
|
queues_to_close = self._connections.pop(task_id)
|
|
399
|
+
should_remove_buffer = True
|
|
291
400
|
log.debug(
|
|
292
401
|
"%s Closing %d SSE connections for Task ID: %s and cleaning up buffer.",
|
|
293
402
|
self.log_identifier,
|
|
294
403
|
len(queues_to_close),
|
|
295
404
|
task_id,
|
|
296
405
|
)
|
|
297
|
-
for q in queues_to_close:
|
|
298
|
-
try:
|
|
299
|
-
await asyncio.wait_for(q.put(None), timeout=0.1)
|
|
300
|
-
except asyncio.QueueFull:
|
|
301
|
-
log.warning(
|
|
302
|
-
"%s Could not put None (close signal) on full queue during close_all for Task ID: %s.",
|
|
303
|
-
self.log_identifier,
|
|
304
|
-
task_id,
|
|
305
|
-
)
|
|
306
|
-
except asyncio.TimeoutError:
|
|
307
|
-
log.warning(
|
|
308
|
-
"%s Timeout putting None (close signal) on queue during close_all for Task ID: %s.",
|
|
309
|
-
self.log_identifier,
|
|
310
|
-
task_id,
|
|
311
|
-
)
|
|
312
|
-
except Exception as e:
|
|
313
|
-
log.error(
|
|
314
|
-
"%s Error putting None (close signal) on queue during close_all for Task ID %s: %s",
|
|
315
|
-
self.log_identifier,
|
|
316
|
-
task_id,
|
|
317
|
-
e,
|
|
318
|
-
)
|
|
319
|
-
|
|
320
|
-
# Since a connection existed, the buffer is no longer needed.
|
|
321
|
-
self._event_buffer.remove_buffer(task_id)
|
|
322
|
-
log.debug(
|
|
323
|
-
"%s Removed Task ID entry: %s and signaled queues to close.",
|
|
324
|
-
self.log_identifier,
|
|
325
|
-
task_id,
|
|
326
|
-
)
|
|
327
406
|
else:
|
|
328
407
|
# This is the "race condition" case: no client has connected yet.
|
|
329
408
|
# We MUST leave the buffer intact for the late-connecting client.
|
|
@@ -333,39 +412,80 @@ class SSEManager:
|
|
|
333
412
|
task_id,
|
|
334
413
|
)
|
|
335
414
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
+
|
|
342
449
|
log.debug(
|
|
343
|
-
"%s
|
|
450
|
+
"%s Removed Task ID entry: %s and signaled queues to close.",
|
|
344
451
|
self.log_identifier,
|
|
345
|
-
|
|
452
|
+
task_id,
|
|
346
453
|
)
|
|
347
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
|
+
|
|
348
460
|
async def close_all(self):
|
|
349
461
|
"""Closes all active SSE connections managed by this instance."""
|
|
350
462
|
self.cleanup_old_locks()
|
|
351
|
-
|
|
352
|
-
|
|
463
|
+
|
|
464
|
+
# Collect all queues to close under the lock
|
|
465
|
+
all_queues_to_close = []
|
|
466
|
+
all_task_ids = []
|
|
467
|
+
|
|
468
|
+
with self._lock:
|
|
353
469
|
log.debug("%s Closing all active SSE connections...", self.log_identifier)
|
|
354
470
|
all_task_ids = list(self._connections.keys())
|
|
355
|
-
closed_count = 0
|
|
356
471
|
for task_id in all_task_ids:
|
|
357
472
|
if task_id in self._connections:
|
|
358
473
|
queues = self._connections.pop(task_id)
|
|
359
|
-
|
|
360
|
-
for q in queues:
|
|
361
|
-
try:
|
|
362
|
-
await asyncio.wait_for(q.put(None), timeout=0.1)
|
|
363
|
-
except Exception:
|
|
364
|
-
pass
|
|
365
|
-
log.debug(
|
|
366
|
-
"%s Closed %d connections for tasks: %s",
|
|
367
|
-
self.log_identifier,
|
|
368
|
-
closed_count,
|
|
369
|
-
all_task_ids,
|
|
370
|
-
)
|
|
474
|
+
all_queues_to_close.extend(queues)
|
|
371
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
|
+
)
|