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
|
@@ -0,0 +1,777 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Platform Service Component for Solace Agent Mesh.
|
|
3
|
+
Hosts the FastAPI REST API server for platform configuration management.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
import threading
|
|
8
|
+
import json
|
|
9
|
+
from typing import Any, Dict
|
|
10
|
+
|
|
11
|
+
import uvicorn
|
|
12
|
+
from solace_ai_connector.common.message import Message as SolaceMessage
|
|
13
|
+
from solace_agent_mesh.common.sac.sam_component_base import SamComponentBase
|
|
14
|
+
from solace_agent_mesh.common.middleware.config_resolver import ConfigResolver
|
|
15
|
+
from solace_agent_mesh.core_a2a.service import CoreA2AService
|
|
16
|
+
from solace_agent_mesh.common import a2a
|
|
17
|
+
from solace_agent_mesh.common.constants import (
|
|
18
|
+
HEALTH_CHECK_INTERVAL_SECONDS,
|
|
19
|
+
HEALTH_CHECK_TTL_SECONDS,
|
|
20
|
+
)
|
|
21
|
+
from a2a.types import AgentCard
|
|
22
|
+
|
|
23
|
+
log = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class _StubSessionManager:
|
|
27
|
+
"""
|
|
28
|
+
Minimal stub for SessionManager to satisfy legacy router dependencies.
|
|
29
|
+
|
|
30
|
+
Platform service doesn't have chat sessions, but webui_backend routers
|
|
31
|
+
(originally designed for WebUI gateway) expect a SessionManager.
|
|
32
|
+
This stub provides minimal compatibility.
|
|
33
|
+
"""
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
info = {
|
|
38
|
+
"class_name": "PlatformServiceComponent",
|
|
39
|
+
"description": (
|
|
40
|
+
"Platform Service Component - REST API for platform management (agents, connectors, deployments). "
|
|
41
|
+
"This is a SERVICE, not a gateway - services provide internal platform functionality, "
|
|
42
|
+
"while gateways handle external communication channels."
|
|
43
|
+
),
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class PlatformServiceComponent(SamComponentBase):
|
|
48
|
+
"""
|
|
49
|
+
Platform Service Component - Management plane for SAM platform.
|
|
50
|
+
|
|
51
|
+
Architecture distinction:
|
|
52
|
+
- SERVICE: Provides internal platform functionality (this component)
|
|
53
|
+
- GATEWAY: Handles external communication channels (http_sse, slack, webhook, etc.)
|
|
54
|
+
|
|
55
|
+
Responsibilities:
|
|
56
|
+
- REST API for platform configuration management
|
|
57
|
+
- Agent Builder CRUD operations
|
|
58
|
+
- Connector management
|
|
59
|
+
- Deployment orchestration
|
|
60
|
+
- Deployer heartbeat monitoring
|
|
61
|
+
- Background deployment status checking
|
|
62
|
+
|
|
63
|
+
Key characteristics:
|
|
64
|
+
- No user chat sessions (services don't interact with end users)
|
|
65
|
+
- Uses direct messaging (publishes commands to deployer, receives heartbeats)
|
|
66
|
+
- Has agent registry (for deployment monitoring, not chat orchestration)
|
|
67
|
+
- Independent from WebUI gateway
|
|
68
|
+
- NOT A2A communication (deployer is a service, not an agent)
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
HEALTH_CHECK_TIMER_ID = "platform_agent_health_check"
|
|
72
|
+
|
|
73
|
+
def get_config(self, key: str, default: Any = None) -> Any:
|
|
74
|
+
"""
|
|
75
|
+
Override get_config to look inside nested 'app_config' dictionary.
|
|
76
|
+
|
|
77
|
+
PlatformServiceApp places configuration in component_config['app_config'],
|
|
78
|
+
following the same pattern as BaseGatewayApp.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
key: Configuration key to retrieve
|
|
82
|
+
default: Default value if key not found
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Configuration value or default
|
|
86
|
+
"""
|
|
87
|
+
if "app_config" in self.component_config:
|
|
88
|
+
value = self.component_config["app_config"].get(key)
|
|
89
|
+
if value is not None:
|
|
90
|
+
return value
|
|
91
|
+
|
|
92
|
+
return super().get_config(key, default)
|
|
93
|
+
|
|
94
|
+
def __init__(self, **kwargs):
|
|
95
|
+
"""
|
|
96
|
+
Initialize the PlatformServiceComponent.
|
|
97
|
+
|
|
98
|
+
Retrieves configuration, initializes FastAPI server state,
|
|
99
|
+
and starts the FastAPI/Uvicorn server.
|
|
100
|
+
"""
|
|
101
|
+
# Initialize SamComponentBase (provides namespace, max_message_size, async loop)
|
|
102
|
+
super().__init__(info, **kwargs)
|
|
103
|
+
log.info("%s Initializing Platform Service Component...", self.log_identifier)
|
|
104
|
+
|
|
105
|
+
# Note: self.namespace is already set by SamComponentBase
|
|
106
|
+
# Note: self.max_message_size_bytes is already set by SamComponentBase
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
# Retrieve Platform Service specific configuration
|
|
110
|
+
self.database_url = self.get_config("database_url")
|
|
111
|
+
self.fastapi_host = self.get_config("fastapi_host", "127.0.0.1")
|
|
112
|
+
self.fastapi_port = int(self.get_config("fastapi_port", 8001))
|
|
113
|
+
self.fastapi_https_port = int(self.get_config("fastapi_https_port", 8444))
|
|
114
|
+
self.ssl_keyfile = self.get_config("ssl_keyfile", "")
|
|
115
|
+
self.ssl_certfile = self.get_config("ssl_certfile", "")
|
|
116
|
+
self.ssl_keyfile_password = self.get_config("ssl_keyfile_password", "")
|
|
117
|
+
self.cors_allowed_origins = self.get_config("cors_allowed_origins", ["*"])
|
|
118
|
+
self.cors_allowed_origin_regex = self.get_config("cors_allowed_origin_regex", "")
|
|
119
|
+
|
|
120
|
+
# OAuth2 configuration (enterprise feature - defaults to community mode)
|
|
121
|
+
self.external_auth_service_url = self.get_config("external_auth_service_url", "")
|
|
122
|
+
self.external_auth_provider = self.get_config("external_auth_provider", "generic")
|
|
123
|
+
|
|
124
|
+
# Background task configuration
|
|
125
|
+
self.deployment_timeout_minutes = self.get_config("deployment_timeout_minutes", 5)
|
|
126
|
+
self.heartbeat_timeout_seconds = self.get_config("heartbeat_timeout_seconds", 90)
|
|
127
|
+
self.deployment_check_interval_seconds = self.get_config("deployment_check_interval_seconds", 60)
|
|
128
|
+
|
|
129
|
+
# Agent health check configuration (for removing expired agents from registry)
|
|
130
|
+
self.health_check_interval_seconds = self.get_config(
|
|
131
|
+
"health_check_interval_seconds", HEALTH_CHECK_INTERVAL_SECONDS
|
|
132
|
+
)
|
|
133
|
+
self.health_check_ttl_seconds = self.get_config(
|
|
134
|
+
"health_check_ttl_seconds", HEALTH_CHECK_TTL_SECONDS
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
log.info(
|
|
138
|
+
"%s Platform service configuration retrieved (Host: %s, Port: %d, Auth: %s).",
|
|
139
|
+
self.log_identifier,
|
|
140
|
+
self.fastapi_host,
|
|
141
|
+
self.fastapi_port,
|
|
142
|
+
"enabled" if self.get_config("frontend_use_authorization", False) else "disabled",
|
|
143
|
+
)
|
|
144
|
+
except Exception as e:
|
|
145
|
+
log.error("%s Failed to retrieve configuration: %s", self.log_identifier, e)
|
|
146
|
+
raise ValueError(f"Configuration retrieval error: {e}") from e
|
|
147
|
+
|
|
148
|
+
# FastAPI server state (initialized later)
|
|
149
|
+
self.fastapi_app = None
|
|
150
|
+
self.uvicorn_server = None
|
|
151
|
+
self.fastapi_thread = None
|
|
152
|
+
|
|
153
|
+
# Config resolver (permissive default - allows all features/scopes)
|
|
154
|
+
self.config_resolver = ConfigResolver()
|
|
155
|
+
|
|
156
|
+
# Legacy router compatibility
|
|
157
|
+
# webui_backend routers were originally designed for WebUI gateway context
|
|
158
|
+
# but now work with Platform Service via dependency abstraction
|
|
159
|
+
self.session_manager = _StubSessionManager()
|
|
160
|
+
|
|
161
|
+
# Agent discovery (like BaseGatewayComponent)
|
|
162
|
+
# Initialize here so CoreA2AService can use it
|
|
163
|
+
from solace_agent_mesh.common.agent_registry import AgentRegistry
|
|
164
|
+
self.agent_registry = AgentRegistry()
|
|
165
|
+
self.core_a2a_service = CoreA2AService(
|
|
166
|
+
agent_registry=self.agent_registry,
|
|
167
|
+
namespace=self.namespace,
|
|
168
|
+
component_id="Platform"
|
|
169
|
+
)
|
|
170
|
+
log.info("%s Agent discovery service initialized", self.log_identifier)
|
|
171
|
+
|
|
172
|
+
# Background task state (for heartbeat monitoring and deployment status checking)
|
|
173
|
+
# Note: agent_registry already initialized above
|
|
174
|
+
self.heartbeat_tracker = None
|
|
175
|
+
self.heartbeat_listener = None
|
|
176
|
+
self.background_scheduler = None
|
|
177
|
+
self.background_tasks_thread = None
|
|
178
|
+
|
|
179
|
+
self.direct_publisher = None
|
|
180
|
+
|
|
181
|
+
log.info("%s Running database migrations...", self.log_identifier)
|
|
182
|
+
self._run_database_migrations()
|
|
183
|
+
log.info("%s Database migrations completed", self.log_identifier)
|
|
184
|
+
|
|
185
|
+
log.info("%s Platform Service Component initialized.", self.log_identifier)
|
|
186
|
+
|
|
187
|
+
def _run_database_migrations(self):
|
|
188
|
+
"""Run database migrations synchronously during __init__."""
|
|
189
|
+
try:
|
|
190
|
+
from .api.main import _setup_database
|
|
191
|
+
_setup_database(self.database_url)
|
|
192
|
+
except Exception as e:
|
|
193
|
+
log.error(
|
|
194
|
+
"%s Failed to run database migrations: %s",
|
|
195
|
+
self.log_identifier,
|
|
196
|
+
e,
|
|
197
|
+
exc_info=True
|
|
198
|
+
)
|
|
199
|
+
raise RuntimeError(f"Database migration failed during component initialization: {e}") from e
|
|
200
|
+
|
|
201
|
+
def _late_init(self):
|
|
202
|
+
"""
|
|
203
|
+
Late initialization called by SamComponentBase.run() after broker is ready.
|
|
204
|
+
|
|
205
|
+
This is the proper place to initialize services that require broker connectivity:
|
|
206
|
+
- FastAPI server (with startup event for background tasks)
|
|
207
|
+
- Direct message publisher (for deployer commands)
|
|
208
|
+
- Agent health check timer (for removing expired agents from registry)
|
|
209
|
+
"""
|
|
210
|
+
log.info("%s Starting late initialization (broker-dependent services)...", self.log_identifier)
|
|
211
|
+
|
|
212
|
+
# Initialize direct message publisher for deployer commands
|
|
213
|
+
self._init_direct_publisher()
|
|
214
|
+
|
|
215
|
+
# Start FastAPI server (background tasks started via FastAPI startup event)
|
|
216
|
+
self._start_fastapi_server()
|
|
217
|
+
|
|
218
|
+
# Schedule agent health checks to remove expired agents from registry
|
|
219
|
+
self._schedule_agent_health_check()
|
|
220
|
+
|
|
221
|
+
log.info("%s Late initialization complete", self.log_identifier)
|
|
222
|
+
|
|
223
|
+
def _start_fastapi_server(self):
|
|
224
|
+
"""
|
|
225
|
+
Start the FastAPI/Uvicorn server in a separate background thread.
|
|
226
|
+
|
|
227
|
+
This method:
|
|
228
|
+
1. Runs enterprise platform migrations if available
|
|
229
|
+
2. Imports the FastAPI app and setup function
|
|
230
|
+
3. Calls setup_dependencies to initialize DB, middleware, and routers
|
|
231
|
+
4. Creates uvicorn.Config and uvicorn.Server
|
|
232
|
+
5. Starts the server in a daemon thread
|
|
233
|
+
"""
|
|
234
|
+
log.info(
|
|
235
|
+
"%s Attempting to start FastAPI/Uvicorn server...",
|
|
236
|
+
self.log_identifier,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
if self.fastapi_thread and self.fastapi_thread.is_alive():
|
|
240
|
+
log.warning(
|
|
241
|
+
"%s FastAPI server thread already started.", self.log_identifier
|
|
242
|
+
)
|
|
243
|
+
return
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
# Import FastAPI app and setup function
|
|
247
|
+
from .api.main import app as fastapi_app_instance
|
|
248
|
+
from .api.main import setup_dependencies
|
|
249
|
+
|
|
250
|
+
self.fastapi_app = fastapi_app_instance
|
|
251
|
+
|
|
252
|
+
setup_dependencies(self)
|
|
253
|
+
|
|
254
|
+
# Register startup event for background tasks
|
|
255
|
+
@self.fastapi_app.on_event("startup")
|
|
256
|
+
async def start_background_tasks():
|
|
257
|
+
try:
|
|
258
|
+
from solace_agent_mesh_enterprise.init_enterprise import start_platform_background_tasks
|
|
259
|
+
|
|
260
|
+
log.info("%s Starting enterprise platform background tasks...", self.log_identifier)
|
|
261
|
+
await start_platform_background_tasks(self)
|
|
262
|
+
log.info("%s Enterprise platform background tasks started", self.log_identifier)
|
|
263
|
+
except ImportError:
|
|
264
|
+
log.info(
|
|
265
|
+
"%s Enterprise package not available - no background tasks to start",
|
|
266
|
+
self.log_identifier
|
|
267
|
+
)
|
|
268
|
+
except Exception as e:
|
|
269
|
+
log.error(
|
|
270
|
+
"%s Failed to start enterprise background tasks: %s",
|
|
271
|
+
self.log_identifier,
|
|
272
|
+
e,
|
|
273
|
+
exc_info=True
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
# Determine port based on SSL configuration
|
|
277
|
+
port = (
|
|
278
|
+
self.fastapi_https_port
|
|
279
|
+
if self.ssl_keyfile and self.ssl_certfile
|
|
280
|
+
else self.fastapi_port
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# Create uvicorn configuration with SSL support
|
|
284
|
+
config = uvicorn.Config(
|
|
285
|
+
app=self.fastapi_app,
|
|
286
|
+
host=self.fastapi_host,
|
|
287
|
+
port=port,
|
|
288
|
+
log_level="warning",
|
|
289
|
+
lifespan="on",
|
|
290
|
+
ssl_keyfile=self.ssl_keyfile if self.ssl_keyfile else None,
|
|
291
|
+
ssl_certfile=self.ssl_certfile if self.ssl_certfile else None,
|
|
292
|
+
ssl_keyfile_password=self.ssl_keyfile_password if self.ssl_keyfile_password else None,
|
|
293
|
+
log_config=None,
|
|
294
|
+
)
|
|
295
|
+
self.uvicorn_server = uvicorn.Server(config)
|
|
296
|
+
|
|
297
|
+
# Start server in background thread
|
|
298
|
+
self.fastapi_thread = threading.Thread(
|
|
299
|
+
target=self.uvicorn_server.run,
|
|
300
|
+
daemon=True,
|
|
301
|
+
name="PlatformService_FastAPI_Thread",
|
|
302
|
+
)
|
|
303
|
+
self.fastapi_thread.start()
|
|
304
|
+
|
|
305
|
+
# Log with correct protocol
|
|
306
|
+
protocol = "https" if self.ssl_keyfile and self.ssl_certfile else "http"
|
|
307
|
+
log.info(
|
|
308
|
+
"%s FastAPI/Uvicorn server starting in background thread on %s://%s:%d",
|
|
309
|
+
self.log_identifier,
|
|
310
|
+
protocol,
|
|
311
|
+
self.fastapi_host,
|
|
312
|
+
port,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
except Exception as e:
|
|
316
|
+
log.error(
|
|
317
|
+
"%s Failed to start FastAPI/Uvicorn server: %s",
|
|
318
|
+
self.log_identifier,
|
|
319
|
+
e,
|
|
320
|
+
)
|
|
321
|
+
raise
|
|
322
|
+
|
|
323
|
+
def _init_direct_publisher(self):
|
|
324
|
+
"""
|
|
325
|
+
Initialize direct message publisher for deployer communication.
|
|
326
|
+
|
|
327
|
+
Platform Service sends deployment commands directly to deployer:
|
|
328
|
+
- {namespace}/deployer/agent/{id}/deploy
|
|
329
|
+
- {namespace}/deployer/agent/{id}/update
|
|
330
|
+
- {namespace}/deployer/agent/{id}/undeploy
|
|
331
|
+
|
|
332
|
+
Uses direct publishing (not A2A protocol) since deployer is a
|
|
333
|
+
standalone service, not an A2A agent.
|
|
334
|
+
|
|
335
|
+
Called from _late_init() and lazily from publish_a2a() if needed.
|
|
336
|
+
Uses SAC's existing broker connection via the BrokerOutput component.
|
|
337
|
+
"""
|
|
338
|
+
try:
|
|
339
|
+
main_app = self.get_app()
|
|
340
|
+
if not main_app or not main_app.flows:
|
|
341
|
+
log.info(
|
|
342
|
+
"%s App flows not yet available - direct publisher will be initialized later",
|
|
343
|
+
self.log_identifier
|
|
344
|
+
)
|
|
345
|
+
return
|
|
346
|
+
|
|
347
|
+
# Find BrokerOutput component in the flow (same pattern as App.send_message)
|
|
348
|
+
broker_output = None
|
|
349
|
+
flow = main_app.flows[0]
|
|
350
|
+
if flow.component_groups:
|
|
351
|
+
for group in reversed(flow.component_groups):
|
|
352
|
+
if group:
|
|
353
|
+
comp = group[0]
|
|
354
|
+
if comp.module_info.get("class_name") == "BrokerOutput":
|
|
355
|
+
broker_output = comp
|
|
356
|
+
break
|
|
357
|
+
|
|
358
|
+
if not broker_output or not hasattr(broker_output, 'messaging_service'):
|
|
359
|
+
log.info(
|
|
360
|
+
"%s BrokerOutput component not ready - direct publisher will be initialized later",
|
|
361
|
+
self.log_identifier
|
|
362
|
+
)
|
|
363
|
+
return
|
|
364
|
+
|
|
365
|
+
self._messaging_service = broker_output.messaging_service.messaging_service
|
|
366
|
+
self.direct_publisher = self._messaging_service.create_direct_message_publisher_builder().build()
|
|
367
|
+
self.direct_publisher.start()
|
|
368
|
+
|
|
369
|
+
log.info("%s Direct message publisher initialized for deployer commands", self.log_identifier)
|
|
370
|
+
|
|
371
|
+
except Exception as e:
|
|
372
|
+
log.warning(
|
|
373
|
+
"%s Could not initialize direct publisher: %s (deployment commands will not work)",
|
|
374
|
+
self.log_identifier,
|
|
375
|
+
e
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
async def _handle_message_async(self, message, topic: str) -> None:
|
|
379
|
+
"""
|
|
380
|
+
Handle incoming broker messages asynchronously (required by SamComponentBase).
|
|
381
|
+
|
|
382
|
+
Processes agent discovery messages and updates AgentRegistry.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
message: The broker message
|
|
386
|
+
topic: The topic the message was received on
|
|
387
|
+
"""
|
|
388
|
+
log.debug(
|
|
389
|
+
"%s Received async message on topic: %s",
|
|
390
|
+
self.log_identifier,
|
|
391
|
+
topic,
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
processed_successfully = False
|
|
395
|
+
|
|
396
|
+
try:
|
|
397
|
+
if a2a.topic_matches_subscription(
|
|
398
|
+
topic, a2a.get_discovery_topic(self.namespace)
|
|
399
|
+
):
|
|
400
|
+
payload = message.get_payload()
|
|
401
|
+
|
|
402
|
+
# Parse JSON if payload is string/bytes (defensive coding)
|
|
403
|
+
if isinstance(payload, bytes):
|
|
404
|
+
payload = json.loads(payload.decode('utf-8'))
|
|
405
|
+
elif isinstance(payload, str):
|
|
406
|
+
payload = json.loads(payload)
|
|
407
|
+
# else: payload is already a dict (SAC framework auto-parses)
|
|
408
|
+
|
|
409
|
+
processed_successfully = self._handle_discovery_message(payload)
|
|
410
|
+
else:
|
|
411
|
+
log.debug(
|
|
412
|
+
"%s Ignoring message on non-discovery topic: %s",
|
|
413
|
+
self.log_identifier,
|
|
414
|
+
topic,
|
|
415
|
+
)
|
|
416
|
+
processed_successfully = True
|
|
417
|
+
|
|
418
|
+
except Exception as e:
|
|
419
|
+
log.error(
|
|
420
|
+
"%s Error handling async message on topic %s: %s",
|
|
421
|
+
self.log_identifier,
|
|
422
|
+
topic,
|
|
423
|
+
e,
|
|
424
|
+
exc_info=True
|
|
425
|
+
)
|
|
426
|
+
processed_successfully = False
|
|
427
|
+
finally:
|
|
428
|
+
# Acknowledge message (like BaseGatewayComponent pattern)
|
|
429
|
+
if hasattr(message, 'call_acknowledgements'):
|
|
430
|
+
try:
|
|
431
|
+
if processed_successfully:
|
|
432
|
+
message.call_acknowledgements()
|
|
433
|
+
else:
|
|
434
|
+
message.call_negative_acknowledgements()
|
|
435
|
+
except Exception as ack_error:
|
|
436
|
+
log.warning(
|
|
437
|
+
"%s Error acknowledging message: %s",
|
|
438
|
+
self.log_identifier,
|
|
439
|
+
ack_error
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
def _handle_discovery_message(self, payload: Dict) -> bool:
|
|
443
|
+
"""
|
|
444
|
+
Handle incoming agent discovery messages.
|
|
445
|
+
|
|
446
|
+
Follows the same pattern as BaseGatewayComponent for consistency.
|
|
447
|
+
|
|
448
|
+
Args:
|
|
449
|
+
payload: The message payload dictionary
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
True if processed successfully, False otherwise
|
|
453
|
+
"""
|
|
454
|
+
try:
|
|
455
|
+
agent_card = AgentCard(**payload)
|
|
456
|
+
self.core_a2a_service.process_discovery_message(agent_card)
|
|
457
|
+
log.debug(
|
|
458
|
+
"%s Processed agent discovery: %s",
|
|
459
|
+
self.log_identifier,
|
|
460
|
+
agent_card.name
|
|
461
|
+
)
|
|
462
|
+
return True
|
|
463
|
+
except Exception as e:
|
|
464
|
+
log.error(
|
|
465
|
+
"%s Failed to process discovery message: %s. Payload: %s",
|
|
466
|
+
self.log_identifier,
|
|
467
|
+
e,
|
|
468
|
+
payload,
|
|
469
|
+
exc_info=True
|
|
470
|
+
)
|
|
471
|
+
return False
|
|
472
|
+
|
|
473
|
+
def _get_component_id(self) -> str:
|
|
474
|
+
"""
|
|
475
|
+
Return unique identifier for this component (required by SamComponentBase).
|
|
476
|
+
|
|
477
|
+
Returns:
|
|
478
|
+
Component identifier string
|
|
479
|
+
"""
|
|
480
|
+
return "platform_service"
|
|
481
|
+
|
|
482
|
+
def _get_component_type(self) -> str:
|
|
483
|
+
"""
|
|
484
|
+
Return component type (required by SamComponentBase).
|
|
485
|
+
|
|
486
|
+
Returns:
|
|
487
|
+
Component type string
|
|
488
|
+
"""
|
|
489
|
+
return "service"
|
|
490
|
+
|
|
491
|
+
def _pre_async_cleanup(self) -> None:
|
|
492
|
+
"""
|
|
493
|
+
Cleanup before async operations stop (required by SamComponentBase).
|
|
494
|
+
|
|
495
|
+
Platform Service doesn't have async-specific resources to clean up here.
|
|
496
|
+
Main cleanup happens in cleanup() method.
|
|
497
|
+
"""
|
|
498
|
+
pass
|
|
499
|
+
|
|
500
|
+
def cleanup(self):
|
|
501
|
+
"""
|
|
502
|
+
Gracefully shut down the Platform Service Component.
|
|
503
|
+
|
|
504
|
+
This method:
|
|
505
|
+
1. Stops direct message publisher
|
|
506
|
+
2. Stops background tasks (heartbeat listener, deployment checker)
|
|
507
|
+
3. Stops agent registry
|
|
508
|
+
4. Signals the uvicorn server to exit
|
|
509
|
+
5. Waits for the FastAPI thread to finish
|
|
510
|
+
6. Calls parent cleanup
|
|
511
|
+
"""
|
|
512
|
+
log.info("%s Cleaning up Platform Service Component...", self.log_identifier)
|
|
513
|
+
|
|
514
|
+
# Stop direct publisher
|
|
515
|
+
if self.direct_publisher:
|
|
516
|
+
try:
|
|
517
|
+
self.direct_publisher.terminate()
|
|
518
|
+
log.info("%s Direct message publisher stopped", self.log_identifier)
|
|
519
|
+
except Exception as e:
|
|
520
|
+
log.warning("%s Error stopping direct publisher: %s", self.log_identifier, e)
|
|
521
|
+
|
|
522
|
+
# Stop background scheduler
|
|
523
|
+
if self.background_scheduler:
|
|
524
|
+
try:
|
|
525
|
+
import asyncio
|
|
526
|
+
loop = asyncio.new_event_loop()
|
|
527
|
+
asyncio.set_event_loop(loop)
|
|
528
|
+
loop.run_until_complete(self.background_scheduler.stop())
|
|
529
|
+
log.info("%s Background scheduler stopped", self.log_identifier)
|
|
530
|
+
except Exception as e:
|
|
531
|
+
log.warning("%s Error stopping background scheduler: %s", self.log_identifier, e)
|
|
532
|
+
|
|
533
|
+
# Stop heartbeat listener
|
|
534
|
+
if self.heartbeat_listener:
|
|
535
|
+
try:
|
|
536
|
+
self.heartbeat_listener.stop()
|
|
537
|
+
log.info("%s Heartbeat listener stopped", self.log_identifier)
|
|
538
|
+
except Exception as e:
|
|
539
|
+
log.warning("%s Error stopping heartbeat listener: %s", self.log_identifier, e)
|
|
540
|
+
|
|
541
|
+
# Cancel health check timer before clearing registry
|
|
542
|
+
self.cancel_timer(self.HEALTH_CHECK_TIMER_ID)
|
|
543
|
+
log.info("%s Health check timer cancelled", self.log_identifier)
|
|
544
|
+
|
|
545
|
+
# Stop agent registry
|
|
546
|
+
if self.agent_registry:
|
|
547
|
+
try:
|
|
548
|
+
self.agent_registry.clear()
|
|
549
|
+
log.info("%s Agent registry stopped", self.log_identifier)
|
|
550
|
+
except Exception as e:
|
|
551
|
+
log.warning("%s Error stopping agent registry: %s", self.log_identifier, e)
|
|
552
|
+
|
|
553
|
+
# Signal uvicorn to shutdown
|
|
554
|
+
if self.uvicorn_server:
|
|
555
|
+
self.uvicorn_server.should_exit = True
|
|
556
|
+
|
|
557
|
+
# Wait for FastAPI thread to exit
|
|
558
|
+
if self.fastapi_thread and self.fastapi_thread.is_alive():
|
|
559
|
+
log.info(
|
|
560
|
+
"%s Waiting for FastAPI server thread to exit...", self.log_identifier
|
|
561
|
+
)
|
|
562
|
+
self.fastapi_thread.join(timeout=10)
|
|
563
|
+
if self.fastapi_thread.is_alive():
|
|
564
|
+
log.warning(
|
|
565
|
+
"%s FastAPI server thread did not exit gracefully.",
|
|
566
|
+
self.log_identifier,
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
# Call SamComponentBase cleanup (stops async loop and threads)
|
|
570
|
+
super().cleanup()
|
|
571
|
+
log.info("%s Platform Service Component cleanup finished.", self.log_identifier)
|
|
572
|
+
|
|
573
|
+
def get_cors_origins(self) -> list[str]:
|
|
574
|
+
"""
|
|
575
|
+
Return the configured CORS allowed origins.
|
|
576
|
+
|
|
577
|
+
Returns:
|
|
578
|
+
List of allowed origin strings.
|
|
579
|
+
"""
|
|
580
|
+
return self.cors_allowed_origins
|
|
581
|
+
|
|
582
|
+
def get_cors_origin_regex(self) -> str:
|
|
583
|
+
"""
|
|
584
|
+
Return the configured CORS allowed origin regex pattern.
|
|
585
|
+
|
|
586
|
+
Returns:
|
|
587
|
+
Regex pattern string, or empty string if not configured.
|
|
588
|
+
"""
|
|
589
|
+
return self.cors_allowed_origin_regex
|
|
590
|
+
|
|
591
|
+
def get_namespace(self) -> str:
|
|
592
|
+
"""
|
|
593
|
+
Return the component's namespace.
|
|
594
|
+
|
|
595
|
+
Returns:
|
|
596
|
+
Namespace string.
|
|
597
|
+
"""
|
|
598
|
+
return self.namespace
|
|
599
|
+
|
|
600
|
+
def get_config_resolver(self) -> ConfigResolver:
|
|
601
|
+
"""
|
|
602
|
+
Return the ConfigResolver instance.
|
|
603
|
+
|
|
604
|
+
The default ConfigResolver is permissive and allows all features/scopes.
|
|
605
|
+
This enables webui_backend routers (which use ValidatedUserConfig) to work
|
|
606
|
+
in platform mode without custom authorization logic.
|
|
607
|
+
|
|
608
|
+
Returns:
|
|
609
|
+
ConfigResolver instance.
|
|
610
|
+
"""
|
|
611
|
+
return self.config_resolver
|
|
612
|
+
|
|
613
|
+
def get_session_manager(self) -> _StubSessionManager:
|
|
614
|
+
"""
|
|
615
|
+
Return the stub SessionManager.
|
|
616
|
+
|
|
617
|
+
Platform service doesn't have real session management, but returns a
|
|
618
|
+
minimal stub to satisfy gateway dependencies that expect SessionManager.
|
|
619
|
+
|
|
620
|
+
Returns:
|
|
621
|
+
Stub SessionManager instance.
|
|
622
|
+
"""
|
|
623
|
+
return self.session_manager
|
|
624
|
+
|
|
625
|
+
def get_heartbeat_tracker(self):
|
|
626
|
+
"""
|
|
627
|
+
Return the heartbeat tracker instance.
|
|
628
|
+
|
|
629
|
+
Used by deployer status endpoint to check if deployer is online.
|
|
630
|
+
|
|
631
|
+
Returns:
|
|
632
|
+
HeartbeatTracker instance if initialized, None otherwise.
|
|
633
|
+
"""
|
|
634
|
+
return self.heartbeat_tracker
|
|
635
|
+
|
|
636
|
+
def get_agent_registry(self):
|
|
637
|
+
"""
|
|
638
|
+
Return the agent registry instance.
|
|
639
|
+
|
|
640
|
+
Used for deployment status monitoring.
|
|
641
|
+
|
|
642
|
+
Returns:
|
|
643
|
+
AgentRegistry instance if initialized, None otherwise.
|
|
644
|
+
"""
|
|
645
|
+
return self.agent_registry
|
|
646
|
+
|
|
647
|
+
def _schedule_agent_health_check(self):
|
|
648
|
+
"""
|
|
649
|
+
Schedule periodic agent health checks to remove expired agents from registry.
|
|
650
|
+
|
|
651
|
+
This is essential for deployment status checking - when an agent is undeployed,
|
|
652
|
+
the deployment status checker needs to see the agent removed from the registry
|
|
653
|
+
to mark the undeploy as successful.
|
|
654
|
+
"""
|
|
655
|
+
if self.health_check_interval_seconds > 0:
|
|
656
|
+
log.info(
|
|
657
|
+
"%s Scheduling agent health check every %d seconds (TTL: %d seconds)",
|
|
658
|
+
self.log_identifier,
|
|
659
|
+
self.health_check_interval_seconds,
|
|
660
|
+
self.health_check_ttl_seconds,
|
|
661
|
+
)
|
|
662
|
+
self.add_timer(
|
|
663
|
+
delay_ms=self.health_check_interval_seconds * 1000,
|
|
664
|
+
timer_id=self.HEALTH_CHECK_TIMER_ID,
|
|
665
|
+
interval_ms=self.health_check_interval_seconds * 1000,
|
|
666
|
+
callback=lambda timer_data: self._check_agent_health(),
|
|
667
|
+
)
|
|
668
|
+
else:
|
|
669
|
+
log.warning(
|
|
670
|
+
"%s Agent health check disabled (interval=%d). "
|
|
671
|
+
"Agents will not be automatically removed from registry when they stop sending heartbeats.",
|
|
672
|
+
self.log_identifier,
|
|
673
|
+
self.health_check_interval_seconds,
|
|
674
|
+
)
|
|
675
|
+
|
|
676
|
+
def _check_agent_health(self):
|
|
677
|
+
"""
|
|
678
|
+
Check agent health and remove expired agents from registry.
|
|
679
|
+
|
|
680
|
+
Called periodically by the health check timer. Iterates through all
|
|
681
|
+
registered agents and removes any whose TTL has expired (i.e., they
|
|
682
|
+
haven't sent a heartbeat recently).
|
|
683
|
+
"""
|
|
684
|
+
log.debug("%s Performing agent health check...", self.log_identifier)
|
|
685
|
+
|
|
686
|
+
agent_names = self.agent_registry.get_agent_names()
|
|
687
|
+
total_agents = len(agent_names)
|
|
688
|
+
agents_removed = 0
|
|
689
|
+
|
|
690
|
+
for agent_name in agent_names:
|
|
691
|
+
is_expired, time_since_last_seen = self.agent_registry.check_ttl_expired(
|
|
692
|
+
agent_name, self.health_check_ttl_seconds
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
if is_expired:
|
|
696
|
+
log.warning(
|
|
697
|
+
"%s Agent '%s' TTL expired (last seen: %d seconds ago, TTL: %d seconds). Removing from registry.",
|
|
698
|
+
self.log_identifier,
|
|
699
|
+
agent_name,
|
|
700
|
+
time_since_last_seen,
|
|
701
|
+
self.health_check_ttl_seconds,
|
|
702
|
+
)
|
|
703
|
+
self.agent_registry.remove_agent(agent_name)
|
|
704
|
+
agents_removed += 1
|
|
705
|
+
|
|
706
|
+
if agents_removed > 0:
|
|
707
|
+
log.info(
|
|
708
|
+
"%s Agent health check complete: %d/%d agents removed",
|
|
709
|
+
self.log_identifier,
|
|
710
|
+
agents_removed,
|
|
711
|
+
total_agents,
|
|
712
|
+
)
|
|
713
|
+
else:
|
|
714
|
+
log.debug(
|
|
715
|
+
"%s Agent health check complete: %d agents, all healthy",
|
|
716
|
+
self.log_identifier,
|
|
717
|
+
total_agents,
|
|
718
|
+
)
|
|
719
|
+
|
|
720
|
+
def publish_a2a(
|
|
721
|
+
self, topic: str, payload: dict, user_properties: dict | None = None
|
|
722
|
+
):
|
|
723
|
+
"""
|
|
724
|
+
Publish direct message to deployer (not A2A protocol).
|
|
725
|
+
|
|
726
|
+
Platform Service sends deployment commands directly to deployer service.
|
|
727
|
+
This is service-to-service communication, not agent-to-agent protocol.
|
|
728
|
+
|
|
729
|
+
Commands sent to:
|
|
730
|
+
- {namespace}/deployer/agent/{agent_id}/deploy
|
|
731
|
+
- {namespace}/deployer/agent/{agent_id}/update
|
|
732
|
+
- {namespace}/deployer/agent/{agent_id}/undeploy
|
|
733
|
+
|
|
734
|
+
Args:
|
|
735
|
+
topic: Message topic
|
|
736
|
+
payload: Message payload dictionary (will be JSON-serialized)
|
|
737
|
+
user_properties: Optional user properties (not used by deployer)
|
|
738
|
+
|
|
739
|
+
Raises:
|
|
740
|
+
Exception: If publishing fails
|
|
741
|
+
"""
|
|
742
|
+
import json
|
|
743
|
+
from solace.messaging.resources.topic import Topic
|
|
744
|
+
|
|
745
|
+
log.debug("%s Publishing deployer command to topic: %s", self.log_identifier, topic)
|
|
746
|
+
|
|
747
|
+
try:
|
|
748
|
+
if not self.direct_publisher:
|
|
749
|
+
self._init_direct_publisher()
|
|
750
|
+
if not self.direct_publisher:
|
|
751
|
+
raise RuntimeError("Direct publisher not initialized")
|
|
752
|
+
|
|
753
|
+
# Serialize payload to JSON and convert to bytearray
|
|
754
|
+
message_body = json.dumps(payload)
|
|
755
|
+
message_bytes = bytearray(message_body.encode("utf-8"))
|
|
756
|
+
|
|
757
|
+
# Publish directly to topic
|
|
758
|
+
self.direct_publisher.publish(
|
|
759
|
+
message=message_bytes,
|
|
760
|
+
destination=Topic.of(topic)
|
|
761
|
+
)
|
|
762
|
+
|
|
763
|
+
log.debug(
|
|
764
|
+
"%s Successfully published deployer command to topic: %s (payload size: %d bytes)",
|
|
765
|
+
self.log_identifier,
|
|
766
|
+
topic,
|
|
767
|
+
len(message_body)
|
|
768
|
+
)
|
|
769
|
+
|
|
770
|
+
except Exception as e:
|
|
771
|
+
log.error(
|
|
772
|
+
"%s Failed to publish deployer command: %s",
|
|
773
|
+
self.log_identifier,
|
|
774
|
+
e,
|
|
775
|
+
exc_info=True
|
|
776
|
+
)
|
|
777
|
+
raise
|