solace-agent-mesh 1.11.2__py3-none-any.whl → 1.12.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- solace_agent_mesh/agent/adk/callbacks.py +177 -10
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +3 -0
- solace_agent_mesh/agent/adk/models/lite_llm.py +34 -16
- solace_agent_mesh/agent/adk/runner.py +66 -8
- solace_agent_mesh/agent/adk/setup.py +61 -26
- solace_agent_mesh/agent/protocol/event_handlers.py +48 -0
- solace_agent_mesh/agent/proxies/a2a/component.py +27 -0
- solace_agent_mesh/agent/sac/component.py +84 -2
- solace_agent_mesh/agent/tools/builtin_artifact_tools.py +41 -22
- solace_agent_mesh/agent/tools/peer_agent_tool.py +19 -12
- solace_agent_mesh/agent/tools/tool_config_types.py +21 -1
- solace_agent_mesh/agent/utils/artifact_helpers.py +54 -0
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.e186750d.js +1 -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.28b7c67b.js → 3ac1795d.dc006e20.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.f08618fb.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4667dc50.bf2ad456.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/547e15cc.8e6da617.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/64195356.09dbd087.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/66d4869e.30340bd3.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.95be65d4.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/ab9708a8.3e563275.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/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.08fab659.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.b241af3e.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.4ca7d2e2.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +4 -4
- 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 +14 -12
- solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +30 -9
- solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/index.html +6 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +4 -4
- 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 +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deploying/{kubernetes-deployment → kubernetes}/index.html +6 -6
- 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 +11 -6
- solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +23 -5
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +17 -8
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +6 -5
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +4 -4
- 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 +25 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/migrations/platform-service-split/index.html +85 -0
- solace_agent_mesh/assets/docs/lunr-index-1767712284328.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1767712284328.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/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 +29 -2
- solace_agent_mesh/cli/commands/init_cmd/platform_service_step.py +85 -0
- solace_agent_mesh/cli/commands/tools_cmd.py +315 -0
- solace_agent_mesh/cli/main.py +2 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-Dj3JtK42.js → authCallback-8Nihi8rv.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-ZKk9kEJ5.js → client-DYtZN8p-.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-BYGUHQMk.js +435 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-D2CSH1bp.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{vendor-BNV4kZN0.js → vendor-XBWAmrun.js} +106 -101
- 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/ui-version.json +1 -1
- 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 +28 -0
- solace_agent_mesh/common/error_handlers.py +83 -0
- solace_agent_mesh/common/sam_events/event_service.py +2 -2
- solace_agent_mesh/config_portal/backend/common.py +2 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ZV-jX48T.js +103 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-ba77705e.js → manifest-ce5bc5da.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
- 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/auth_interface.py +103 -0
- solace_agent_mesh/gateway/base/component.py +68 -1
- solace_agent_mesh/gateway/generic/component.py +195 -30
- solace_agent_mesh/gateway/http_sse/app.py +23 -6
- solace_agent_mesh/gateway/http_sse/component.py +9 -61
- solace_agent_mesh/gateway/http_sse/dependencies.py +9 -51
- solace_agent_mesh/gateway/http_sse/main.py +28 -418
- 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 +2 -2
- 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/prompt_model.py +1 -1
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +1 -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 +4 -4
- solace_agent_mesh/gateway/http_sse/repository/task_repository.py +2 -2
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +16 -15
- solace_agent_mesh/gateway/http_sse/routers/auth.py +61 -132
- solace_agent_mesh/gateway/http_sse/routers/config.py +12 -8
- 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/session_responses.py +2 -2
- 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 +2 -1
- solace_agent_mesh/gateway/http_sse/routers/prompts.py +2 -1
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +3 -3
- solace_agent_mesh/gateway/http_sse/routers/speech.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +3 -2
- solace_agent_mesh/gateway/http_sse/routers/users.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +2 -1
- solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +1 -1
- 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/session_service.py +4 -4
- solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +1 -1
- solace_agent_mesh/services/platform/__init__.py +23 -12
- solace_agent_mesh/services/platform/api/dependencies.py +23 -16
- solace_agent_mesh/services/platform/api/main.py +118 -43
- solace_agent_mesh/services/platform/api/routers/__init__.py +12 -3
- solace_agent_mesh/services/platform/api/routers/health_router.py +31 -0
- solace_agent_mesh/services/platform/app.py +101 -7
- solace_agent_mesh/services/platform/component.py +552 -33
- 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 +291 -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/platform.yaml +49 -0
- solace_agent_mesh/templates/webui.yaml +12 -3
- {solace_agent_mesh-1.11.2.dist-info → solace_agent_mesh-1.12.0.dist-info}/METADATA +2 -1
- {solace_agent_mesh-1.11.2.dist-info → solace_agent_mesh-1.12.0.dist-info}/RECORD +214 -258
- 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/15ba94aa.92fea363.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/240a0364.9ad94d1b.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/3ff0015d.2ddc75c0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.90a87880.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/66d4869e.b77431fc.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/81a99df0.2484b8d9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9bb13469.b2333011.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ab9708a8.245ae0ef.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e04b235d.52cb25ed.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.b1068f9b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e6f9706b.4488e34c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.250993bf.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.7acf7ace.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.9e0813a2.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1765810064709.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1765810064709.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/main-BcUaNZ-Q.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-vjch4RYc.js +0 -435
- 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-DiOiAjzL.js +0 -103
- 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/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/templates_llm.txt +0 -147
- /solace_agent_mesh/assets/docs/assets/js/{main.7acf7ace.js.LICENSE.txt → main.b241af3e.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.11.2.dist-info → solace_agent_mesh-1.12.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.11.2.dist-info → solace_agent_mesh-1.12.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.11.2.dist-info → solace_agent_mesh-1.12.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,44 +5,92 @@ Hosts the FastAPI REST API server for platform configuration management.
|
|
|
5
5
|
|
|
6
6
|
import logging
|
|
7
7
|
import threading
|
|
8
|
+
import json
|
|
9
|
+
from typing import Any, Dict
|
|
8
10
|
|
|
9
11
|
import uvicorn
|
|
10
|
-
from solace_ai_connector.
|
|
12
|
+
from solace_ai_connector.common.message import Message as SolaceMessage
|
|
13
|
+
from solace_agent_mesh.common.sac.sam_component_base import SamComponentBase
|
|
11
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
|
|
12
22
|
|
|
13
23
|
log = logging.getLogger(__name__)
|
|
14
24
|
|
|
15
25
|
|
|
16
26
|
class _StubSessionManager:
|
|
17
27
|
"""
|
|
18
|
-
Minimal stub for SessionManager to satisfy
|
|
28
|
+
Minimal stub for SessionManager to satisfy legacy router dependencies.
|
|
19
29
|
|
|
20
|
-
Platform service doesn't have sessions, but webui_backend routers
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
request.state.user.
|
|
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.
|
|
24
33
|
"""
|
|
25
|
-
|
|
26
|
-
self.use_authorization = use_authorization
|
|
34
|
+
pass
|
|
27
35
|
|
|
28
36
|
|
|
29
37
|
info = {
|
|
30
38
|
"class_name": "PlatformServiceComponent",
|
|
31
39
|
"description": (
|
|
32
|
-
"Platform Service Component - REST API for platform
|
|
33
|
-
"
|
|
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."
|
|
34
43
|
),
|
|
35
44
|
}
|
|
36
45
|
|
|
37
46
|
|
|
38
|
-
class PlatformServiceComponent(
|
|
47
|
+
class PlatformServiceComponent(SamComponentBase):
|
|
39
48
|
"""
|
|
40
|
-
Platform Service Component
|
|
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
|
|
41
62
|
|
|
42
63
|
Key characteristics:
|
|
43
|
-
-
|
|
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)
|
|
44
69
|
"""
|
|
45
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
|
+
|
|
46
94
|
def __init__(self, **kwargs):
|
|
47
95
|
"""
|
|
48
96
|
Initialize the PlatformServiceComponent.
|
|
@@ -50,28 +98,47 @@ class PlatformServiceComponent(ComponentBase):
|
|
|
50
98
|
Retrieves configuration, initializes FastAPI server state,
|
|
51
99
|
and starts the FastAPI/Uvicorn server.
|
|
52
100
|
"""
|
|
101
|
+
# Initialize SamComponentBase (provides namespace, max_message_size, async loop)
|
|
53
102
|
super().__init__(info, **kwargs)
|
|
54
103
|
log.info("%s Initializing Platform Service Component...", self.log_identifier)
|
|
55
104
|
|
|
105
|
+
# Note: self.namespace is already set by SamComponentBase
|
|
106
|
+
# Note: self.max_message_size_bytes is already set by SamComponentBase
|
|
107
|
+
|
|
56
108
|
try:
|
|
57
|
-
# Retrieve configuration
|
|
58
|
-
self.namespace = self.get_config("namespace")
|
|
109
|
+
# Retrieve Platform Service specific configuration
|
|
59
110
|
self.database_url = self.get_config("database_url")
|
|
60
111
|
self.fastapi_host = self.get_config("fastapi_host", "127.0.0.1")
|
|
61
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", "")
|
|
62
117
|
self.cors_allowed_origins = self.get_config("cors_allowed_origins", ["*"])
|
|
63
118
|
|
|
64
|
-
# OAuth2 configuration
|
|
65
|
-
self.external_auth_service_url = self.get_config("external_auth_service_url")
|
|
66
|
-
self.external_auth_provider = self.get_config("external_auth_provider", "
|
|
67
|
-
|
|
119
|
+
# OAuth2 configuration (enterprise feature - defaults to community mode)
|
|
120
|
+
self.external_auth_service_url = self.get_config("external_auth_service_url", "")
|
|
121
|
+
self.external_auth_provider = self.get_config("external_auth_provider", "generic")
|
|
122
|
+
|
|
123
|
+
# Background task configuration
|
|
124
|
+
self.deployment_timeout_minutes = self.get_config("deployment_timeout_minutes", 5)
|
|
125
|
+
self.heartbeat_timeout_seconds = self.get_config("heartbeat_timeout_seconds", 90)
|
|
126
|
+
self.deployment_check_interval_seconds = self.get_config("deployment_check_interval_seconds", 60)
|
|
127
|
+
|
|
128
|
+
# Agent health check configuration (for removing expired agents from registry)
|
|
129
|
+
self.health_check_interval_seconds = self.get_config(
|
|
130
|
+
"health_check_interval_seconds", HEALTH_CHECK_INTERVAL_SECONDS
|
|
131
|
+
)
|
|
132
|
+
self.health_check_ttl_seconds = self.get_config(
|
|
133
|
+
"health_check_ttl_seconds", HEALTH_CHECK_TTL_SECONDS
|
|
134
|
+
)
|
|
68
135
|
|
|
69
136
|
log.info(
|
|
70
137
|
"%s Platform service configuration retrieved (Host: %s, Port: %d, Auth: %s).",
|
|
71
138
|
self.log_identifier,
|
|
72
139
|
self.fastapi_host,
|
|
73
140
|
self.fastapi_port,
|
|
74
|
-
"enabled" if self.
|
|
141
|
+
"enabled" if self.get_config("frontend_use_authorization", False) else "disabled",
|
|
75
142
|
)
|
|
76
143
|
except Exception as e:
|
|
77
144
|
log.error("%s Failed to retrieve configuration: %s", self.log_identifier, e)
|
|
@@ -85,16 +152,59 @@ class PlatformServiceComponent(ComponentBase):
|
|
|
85
152
|
# Config resolver (permissive default - allows all features/scopes)
|
|
86
153
|
self.config_resolver = ConfigResolver()
|
|
87
154
|
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
self.session_manager = _StubSessionManager(
|
|
155
|
+
# Legacy router compatibility
|
|
156
|
+
# webui_backend routers were originally designed for WebUI gateway context
|
|
157
|
+
# but now work with Platform Service via dependency abstraction
|
|
158
|
+
self.session_manager = _StubSessionManager()
|
|
159
|
+
|
|
160
|
+
# Agent discovery (like BaseGatewayComponent)
|
|
161
|
+
# Initialize here so CoreA2AService can use it
|
|
162
|
+
from solace_agent_mesh.common.agent_registry import AgentRegistry
|
|
163
|
+
self.agent_registry = AgentRegistry()
|
|
164
|
+
self.core_a2a_service = CoreA2AService(
|
|
165
|
+
agent_registry=self.agent_registry,
|
|
166
|
+
namespace=self.namespace,
|
|
167
|
+
component_id="Platform"
|
|
168
|
+
)
|
|
169
|
+
log.info("%s Agent discovery service initialized", self.log_identifier)
|
|
170
|
+
|
|
171
|
+
# Background task state (for heartbeat monitoring and deployment status checking)
|
|
172
|
+
# Note: agent_registry already initialized above
|
|
173
|
+
self.heartbeat_tracker = None
|
|
174
|
+
self.heartbeat_listener = None
|
|
175
|
+
self.background_scheduler = None
|
|
176
|
+
self.background_tasks_thread = None
|
|
177
|
+
|
|
178
|
+
# Direct message publisher for deployer commands
|
|
179
|
+
self.direct_publisher = None
|
|
92
180
|
|
|
93
181
|
log.info("%s Platform Service Component initialized.", self.log_identifier)
|
|
94
182
|
|
|
95
|
-
#
|
|
183
|
+
# Note: FastAPI server, direct publisher, and background tasks are started
|
|
184
|
+
# in _late_init() after SamComponentBase.run() is called and broker is ready
|
|
185
|
+
|
|
186
|
+
def _late_init(self):
|
|
187
|
+
"""
|
|
188
|
+
Late initialization called by SamComponentBase.run() after broker is ready.
|
|
189
|
+
|
|
190
|
+
This is the proper place to initialize services that require broker connectivity:
|
|
191
|
+
- FastAPI server (with startup event for background tasks)
|
|
192
|
+
- Direct message publisher (for deployer commands)
|
|
193
|
+
- Agent health check timer (for removing expired agents from registry)
|
|
194
|
+
"""
|
|
195
|
+
log.info("%s Starting late initialization (broker-dependent services)...", self.log_identifier)
|
|
196
|
+
|
|
197
|
+
# Initialize direct message publisher for deployer commands
|
|
198
|
+
self._init_direct_publisher()
|
|
199
|
+
|
|
200
|
+
# Start FastAPI server (background tasks started via FastAPI startup event)
|
|
96
201
|
self._start_fastapi_server()
|
|
97
202
|
|
|
203
|
+
# Schedule agent health checks to remove expired agents from registry
|
|
204
|
+
self._schedule_agent_health_check()
|
|
205
|
+
|
|
206
|
+
log.info("%s Late initialization complete", self.log_identifier)
|
|
207
|
+
|
|
98
208
|
def _start_fastapi_server(self):
|
|
99
209
|
"""
|
|
100
210
|
Start the FastAPI/Uvicorn server in a separate background thread.
|
|
@@ -127,13 +237,45 @@ class PlatformServiceComponent(ComponentBase):
|
|
|
127
237
|
# Setup dependencies (idempotent - safe to call multiple times)
|
|
128
238
|
setup_dependencies(self, self.database_url)
|
|
129
239
|
|
|
130
|
-
#
|
|
240
|
+
# Register startup event for background tasks
|
|
241
|
+
@self.fastapi_app.on_event("startup")
|
|
242
|
+
async def start_background_tasks():
|
|
243
|
+
try:
|
|
244
|
+
from solace_agent_mesh_enterprise.init_enterprise import start_platform_background_tasks
|
|
245
|
+
|
|
246
|
+
log.info("%s Starting enterprise platform background tasks...", self.log_identifier)
|
|
247
|
+
await start_platform_background_tasks(self)
|
|
248
|
+
log.info("%s Enterprise platform background tasks started", self.log_identifier)
|
|
249
|
+
except ImportError:
|
|
250
|
+
log.info(
|
|
251
|
+
"%s Enterprise package not available - no background tasks to start",
|
|
252
|
+
self.log_identifier
|
|
253
|
+
)
|
|
254
|
+
except Exception as e:
|
|
255
|
+
log.error(
|
|
256
|
+
"%s Failed to start enterprise background tasks: %s",
|
|
257
|
+
self.log_identifier,
|
|
258
|
+
e,
|
|
259
|
+
exc_info=True
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# Determine port based on SSL configuration
|
|
263
|
+
port = (
|
|
264
|
+
self.fastapi_https_port
|
|
265
|
+
if self.ssl_keyfile and self.ssl_certfile
|
|
266
|
+
else self.fastapi_port
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# Create uvicorn configuration with SSL support
|
|
131
270
|
config = uvicorn.Config(
|
|
132
271
|
app=self.fastapi_app,
|
|
133
272
|
host=self.fastapi_host,
|
|
134
|
-
port=
|
|
273
|
+
port=port,
|
|
135
274
|
log_level="warning",
|
|
136
275
|
lifespan="on",
|
|
276
|
+
ssl_keyfile=self.ssl_keyfile if self.ssl_keyfile else None,
|
|
277
|
+
ssl_certfile=self.ssl_certfile if self.ssl_certfile else None,
|
|
278
|
+
ssl_keyfile_password=self.ssl_keyfile_password if self.ssl_keyfile_password else None,
|
|
137
279
|
log_config=None,
|
|
138
280
|
)
|
|
139
281
|
self.uvicorn_server = uvicorn.Server(config)
|
|
@@ -145,11 +287,15 @@ class PlatformServiceComponent(ComponentBase):
|
|
|
145
287
|
name="PlatformService_FastAPI_Thread",
|
|
146
288
|
)
|
|
147
289
|
self.fastapi_thread.start()
|
|
290
|
+
|
|
291
|
+
# Log with correct protocol
|
|
292
|
+
protocol = "https" if self.ssl_keyfile and self.ssl_certfile else "http"
|
|
148
293
|
log.info(
|
|
149
|
-
"%s FastAPI/Uvicorn server starting in background thread on
|
|
294
|
+
"%s FastAPI/Uvicorn server starting in background thread on %s://%s:%d",
|
|
150
295
|
self.log_identifier,
|
|
296
|
+
protocol,
|
|
151
297
|
self.fastapi_host,
|
|
152
|
-
|
|
298
|
+
port,
|
|
153
299
|
)
|
|
154
300
|
|
|
155
301
|
except Exception as e:
|
|
@@ -160,17 +306,236 @@ class PlatformServiceComponent(ComponentBase):
|
|
|
160
306
|
)
|
|
161
307
|
raise
|
|
162
308
|
|
|
309
|
+
def _init_direct_publisher(self):
|
|
310
|
+
"""
|
|
311
|
+
Initialize direct message publisher for deployer communication.
|
|
312
|
+
|
|
313
|
+
Platform Service sends deployment commands directly to deployer:
|
|
314
|
+
- {namespace}/deployer/agent/{id}/deploy
|
|
315
|
+
- {namespace}/deployer/agent/{id}/update
|
|
316
|
+
- {namespace}/deployer/agent/{id}/undeploy
|
|
317
|
+
|
|
318
|
+
Uses direct publishing (not A2A protocol) since deployer is a
|
|
319
|
+
standalone service, not an A2A agent.
|
|
320
|
+
|
|
321
|
+
Called from _late_init() and lazily from publish_a2a() if needed.
|
|
322
|
+
Uses SAC's existing broker connection via the BrokerOutput component.
|
|
323
|
+
"""
|
|
324
|
+
try:
|
|
325
|
+
main_app = self.get_app()
|
|
326
|
+
if not main_app or not main_app.flows:
|
|
327
|
+
log.info(
|
|
328
|
+
"%s App flows not yet available - direct publisher will be initialized later",
|
|
329
|
+
self.log_identifier
|
|
330
|
+
)
|
|
331
|
+
return
|
|
332
|
+
|
|
333
|
+
# Find BrokerOutput component in the flow (same pattern as App.send_message)
|
|
334
|
+
broker_output = None
|
|
335
|
+
flow = main_app.flows[0]
|
|
336
|
+
if flow.component_groups:
|
|
337
|
+
for group in reversed(flow.component_groups):
|
|
338
|
+
if group:
|
|
339
|
+
comp = group[0]
|
|
340
|
+
if comp.module_info.get("class_name") == "BrokerOutput":
|
|
341
|
+
broker_output = comp
|
|
342
|
+
break
|
|
343
|
+
|
|
344
|
+
if not broker_output or not hasattr(broker_output, 'messaging_service'):
|
|
345
|
+
log.info(
|
|
346
|
+
"%s BrokerOutput component not ready - direct publisher will be initialized later",
|
|
347
|
+
self.log_identifier
|
|
348
|
+
)
|
|
349
|
+
return
|
|
350
|
+
|
|
351
|
+
self._messaging_service = broker_output.messaging_service.messaging_service
|
|
352
|
+
self.direct_publisher = self._messaging_service.create_direct_message_publisher_builder().build()
|
|
353
|
+
self.direct_publisher.start()
|
|
354
|
+
|
|
355
|
+
log.info("%s Direct message publisher initialized for deployer commands", self.log_identifier)
|
|
356
|
+
|
|
357
|
+
except Exception as e:
|
|
358
|
+
log.warning(
|
|
359
|
+
"%s Could not initialize direct publisher: %s (deployment commands will not work)",
|
|
360
|
+
self.log_identifier,
|
|
361
|
+
e
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
async def _handle_message_async(self, message, topic: str) -> None:
|
|
365
|
+
"""
|
|
366
|
+
Handle incoming broker messages asynchronously (required by SamComponentBase).
|
|
367
|
+
|
|
368
|
+
Processes agent discovery messages and updates AgentRegistry.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
message: The broker message
|
|
372
|
+
topic: The topic the message was received on
|
|
373
|
+
"""
|
|
374
|
+
log.debug(
|
|
375
|
+
"%s Received async message on topic: %s",
|
|
376
|
+
self.log_identifier,
|
|
377
|
+
topic,
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
processed_successfully = False
|
|
381
|
+
|
|
382
|
+
try:
|
|
383
|
+
if a2a.topic_matches_subscription(
|
|
384
|
+
topic, a2a.get_discovery_topic(self.namespace)
|
|
385
|
+
):
|
|
386
|
+
payload = message.get_payload()
|
|
387
|
+
|
|
388
|
+
# Parse JSON if payload is string/bytes (defensive coding)
|
|
389
|
+
if isinstance(payload, bytes):
|
|
390
|
+
payload = json.loads(payload.decode('utf-8'))
|
|
391
|
+
elif isinstance(payload, str):
|
|
392
|
+
payload = json.loads(payload)
|
|
393
|
+
# else: payload is already a dict (SAC framework auto-parses)
|
|
394
|
+
|
|
395
|
+
processed_successfully = self._handle_discovery_message(payload)
|
|
396
|
+
else:
|
|
397
|
+
log.debug(
|
|
398
|
+
"%s Ignoring message on non-discovery topic: %s",
|
|
399
|
+
self.log_identifier,
|
|
400
|
+
topic,
|
|
401
|
+
)
|
|
402
|
+
processed_successfully = True
|
|
403
|
+
|
|
404
|
+
except Exception as e:
|
|
405
|
+
log.error(
|
|
406
|
+
"%s Error handling async message on topic %s: %s",
|
|
407
|
+
self.log_identifier,
|
|
408
|
+
topic,
|
|
409
|
+
e,
|
|
410
|
+
exc_info=True
|
|
411
|
+
)
|
|
412
|
+
processed_successfully = False
|
|
413
|
+
finally:
|
|
414
|
+
# Acknowledge message (like BaseGatewayComponent pattern)
|
|
415
|
+
if hasattr(message, 'call_acknowledgements'):
|
|
416
|
+
try:
|
|
417
|
+
if processed_successfully:
|
|
418
|
+
message.call_acknowledgements()
|
|
419
|
+
else:
|
|
420
|
+
message.call_negative_acknowledgements()
|
|
421
|
+
except Exception as ack_error:
|
|
422
|
+
log.warning(
|
|
423
|
+
"%s Error acknowledging message: %s",
|
|
424
|
+
self.log_identifier,
|
|
425
|
+
ack_error
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
def _handle_discovery_message(self, payload: Dict) -> bool:
|
|
429
|
+
"""
|
|
430
|
+
Handle incoming agent discovery messages.
|
|
431
|
+
|
|
432
|
+
Follows the same pattern as BaseGatewayComponent for consistency.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
payload: The message payload dictionary
|
|
436
|
+
|
|
437
|
+
Returns:
|
|
438
|
+
True if processed successfully, False otherwise
|
|
439
|
+
"""
|
|
440
|
+
try:
|
|
441
|
+
agent_card = AgentCard(**payload)
|
|
442
|
+
self.core_a2a_service.process_discovery_message(agent_card)
|
|
443
|
+
log.debug(
|
|
444
|
+
"%s Processed agent discovery: %s",
|
|
445
|
+
self.log_identifier,
|
|
446
|
+
agent_card.name
|
|
447
|
+
)
|
|
448
|
+
return True
|
|
449
|
+
except Exception as e:
|
|
450
|
+
log.error(
|
|
451
|
+
"%s Failed to process discovery message: %s. Payload: %s",
|
|
452
|
+
self.log_identifier,
|
|
453
|
+
e,
|
|
454
|
+
payload,
|
|
455
|
+
exc_info=True
|
|
456
|
+
)
|
|
457
|
+
return False
|
|
458
|
+
|
|
459
|
+
def _get_component_id(self) -> str:
|
|
460
|
+
"""
|
|
461
|
+
Return unique identifier for this component (required by SamComponentBase).
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
Component identifier string
|
|
465
|
+
"""
|
|
466
|
+
return "platform_service"
|
|
467
|
+
|
|
468
|
+
def _get_component_type(self) -> str:
|
|
469
|
+
"""
|
|
470
|
+
Return component type (required by SamComponentBase).
|
|
471
|
+
|
|
472
|
+
Returns:
|
|
473
|
+
Component type string
|
|
474
|
+
"""
|
|
475
|
+
return "service"
|
|
476
|
+
|
|
477
|
+
def _pre_async_cleanup(self) -> None:
|
|
478
|
+
"""
|
|
479
|
+
Cleanup before async operations stop (required by SamComponentBase).
|
|
480
|
+
|
|
481
|
+
Platform Service doesn't have async-specific resources to clean up here.
|
|
482
|
+
Main cleanup happens in cleanup() method.
|
|
483
|
+
"""
|
|
484
|
+
pass
|
|
485
|
+
|
|
163
486
|
def cleanup(self):
|
|
164
487
|
"""
|
|
165
488
|
Gracefully shut down the Platform Service Component.
|
|
166
489
|
|
|
167
490
|
This method:
|
|
168
|
-
1.
|
|
169
|
-
2.
|
|
170
|
-
3.
|
|
491
|
+
1. Stops direct message publisher
|
|
492
|
+
2. Stops background tasks (heartbeat listener, deployment checker)
|
|
493
|
+
3. Stops agent registry
|
|
494
|
+
4. Signals the uvicorn server to exit
|
|
495
|
+
5. Waits for the FastAPI thread to finish
|
|
496
|
+
6. Calls parent cleanup
|
|
171
497
|
"""
|
|
172
498
|
log.info("%s Cleaning up Platform Service Component...", self.log_identifier)
|
|
173
499
|
|
|
500
|
+
# Stop direct publisher
|
|
501
|
+
if self.direct_publisher:
|
|
502
|
+
try:
|
|
503
|
+
self.direct_publisher.terminate()
|
|
504
|
+
log.info("%s Direct message publisher stopped", self.log_identifier)
|
|
505
|
+
except Exception as e:
|
|
506
|
+
log.warning("%s Error stopping direct publisher: %s", self.log_identifier, e)
|
|
507
|
+
|
|
508
|
+
# Stop background scheduler
|
|
509
|
+
if self.background_scheduler:
|
|
510
|
+
try:
|
|
511
|
+
import asyncio
|
|
512
|
+
loop = asyncio.new_event_loop()
|
|
513
|
+
asyncio.set_event_loop(loop)
|
|
514
|
+
loop.run_until_complete(self.background_scheduler.stop())
|
|
515
|
+
log.info("%s Background scheduler stopped", self.log_identifier)
|
|
516
|
+
except Exception as e:
|
|
517
|
+
log.warning("%s Error stopping background scheduler: %s", self.log_identifier, e)
|
|
518
|
+
|
|
519
|
+
# Stop heartbeat listener
|
|
520
|
+
if self.heartbeat_listener:
|
|
521
|
+
try:
|
|
522
|
+
self.heartbeat_listener.stop()
|
|
523
|
+
log.info("%s Heartbeat listener stopped", self.log_identifier)
|
|
524
|
+
except Exception as e:
|
|
525
|
+
log.warning("%s Error stopping heartbeat listener: %s", self.log_identifier, e)
|
|
526
|
+
|
|
527
|
+
# Cancel health check timer before clearing registry
|
|
528
|
+
self.cancel_timer(self.HEALTH_CHECK_TIMER_ID)
|
|
529
|
+
log.info("%s Health check timer cancelled", self.log_identifier)
|
|
530
|
+
|
|
531
|
+
# Stop agent registry
|
|
532
|
+
if self.agent_registry:
|
|
533
|
+
try:
|
|
534
|
+
self.agent_registry.clear()
|
|
535
|
+
log.info("%s Agent registry stopped", self.log_identifier)
|
|
536
|
+
except Exception as e:
|
|
537
|
+
log.warning("%s Error stopping agent registry: %s", self.log_identifier, e)
|
|
538
|
+
|
|
174
539
|
# Signal uvicorn to shutdown
|
|
175
540
|
if self.uvicorn_server:
|
|
176
541
|
self.uvicorn_server.should_exit = True
|
|
@@ -187,7 +552,7 @@ class PlatformServiceComponent(ComponentBase):
|
|
|
187
552
|
self.log_identifier,
|
|
188
553
|
)
|
|
189
554
|
|
|
190
|
-
# Call
|
|
555
|
+
# Call SamComponentBase cleanup (stops async loop and threads)
|
|
191
556
|
super().cleanup()
|
|
192
557
|
log.info("%s Platform Service Component cleanup finished.", self.log_identifier)
|
|
193
558
|
|
|
@@ -233,3 +598,157 @@ class PlatformServiceComponent(ComponentBase):
|
|
|
233
598
|
Stub SessionManager instance.
|
|
234
599
|
"""
|
|
235
600
|
return self.session_manager
|
|
601
|
+
|
|
602
|
+
def get_heartbeat_tracker(self):
|
|
603
|
+
"""
|
|
604
|
+
Return the heartbeat tracker instance.
|
|
605
|
+
|
|
606
|
+
Used by deployer status endpoint to check if deployer is online.
|
|
607
|
+
|
|
608
|
+
Returns:
|
|
609
|
+
HeartbeatTracker instance if initialized, None otherwise.
|
|
610
|
+
"""
|
|
611
|
+
return self.heartbeat_tracker
|
|
612
|
+
|
|
613
|
+
def get_agent_registry(self):
|
|
614
|
+
"""
|
|
615
|
+
Return the agent registry instance.
|
|
616
|
+
|
|
617
|
+
Used for deployment status monitoring.
|
|
618
|
+
|
|
619
|
+
Returns:
|
|
620
|
+
AgentRegistry instance if initialized, None otherwise.
|
|
621
|
+
"""
|
|
622
|
+
return self.agent_registry
|
|
623
|
+
|
|
624
|
+
def _schedule_agent_health_check(self):
|
|
625
|
+
"""
|
|
626
|
+
Schedule periodic agent health checks to remove expired agents from registry.
|
|
627
|
+
|
|
628
|
+
This is essential for deployment status checking - when an agent is undeployed,
|
|
629
|
+
the deployment status checker needs to see the agent removed from the registry
|
|
630
|
+
to mark the undeploy as successful.
|
|
631
|
+
"""
|
|
632
|
+
if self.health_check_interval_seconds > 0:
|
|
633
|
+
log.info(
|
|
634
|
+
"%s Scheduling agent health check every %d seconds (TTL: %d seconds)",
|
|
635
|
+
self.log_identifier,
|
|
636
|
+
self.health_check_interval_seconds,
|
|
637
|
+
self.health_check_ttl_seconds,
|
|
638
|
+
)
|
|
639
|
+
self.add_timer(
|
|
640
|
+
delay_ms=self.health_check_interval_seconds * 1000,
|
|
641
|
+
timer_id=self.HEALTH_CHECK_TIMER_ID,
|
|
642
|
+
interval_ms=self.health_check_interval_seconds * 1000,
|
|
643
|
+
callback=lambda timer_data: self._check_agent_health(),
|
|
644
|
+
)
|
|
645
|
+
else:
|
|
646
|
+
log.warning(
|
|
647
|
+
"%s Agent health check disabled (interval=%d). "
|
|
648
|
+
"Agents will not be automatically removed from registry when they stop sending heartbeats.",
|
|
649
|
+
self.log_identifier,
|
|
650
|
+
self.health_check_interval_seconds,
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
def _check_agent_health(self):
|
|
654
|
+
"""
|
|
655
|
+
Check agent health and remove expired agents from registry.
|
|
656
|
+
|
|
657
|
+
Called periodically by the health check timer. Iterates through all
|
|
658
|
+
registered agents and removes any whose TTL has expired (i.e., they
|
|
659
|
+
haven't sent a heartbeat recently).
|
|
660
|
+
"""
|
|
661
|
+
log.debug("%s Performing agent health check...", self.log_identifier)
|
|
662
|
+
|
|
663
|
+
agent_names = self.agent_registry.get_agent_names()
|
|
664
|
+
total_agents = len(agent_names)
|
|
665
|
+
agents_removed = 0
|
|
666
|
+
|
|
667
|
+
for agent_name in agent_names:
|
|
668
|
+
is_expired, time_since_last_seen = self.agent_registry.check_ttl_expired(
|
|
669
|
+
agent_name, self.health_check_ttl_seconds
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
if is_expired:
|
|
673
|
+
log.warning(
|
|
674
|
+
"%s Agent '%s' TTL expired (last seen: %d seconds ago, TTL: %d seconds). Removing from registry.",
|
|
675
|
+
self.log_identifier,
|
|
676
|
+
agent_name,
|
|
677
|
+
time_since_last_seen,
|
|
678
|
+
self.health_check_ttl_seconds,
|
|
679
|
+
)
|
|
680
|
+
self.agent_registry.remove_agent(agent_name)
|
|
681
|
+
agents_removed += 1
|
|
682
|
+
|
|
683
|
+
if agents_removed > 0:
|
|
684
|
+
log.info(
|
|
685
|
+
"%s Agent health check complete: %d/%d agents removed",
|
|
686
|
+
self.log_identifier,
|
|
687
|
+
agents_removed,
|
|
688
|
+
total_agents,
|
|
689
|
+
)
|
|
690
|
+
else:
|
|
691
|
+
log.debug(
|
|
692
|
+
"%s Agent health check complete: %d agents, all healthy",
|
|
693
|
+
self.log_identifier,
|
|
694
|
+
total_agents,
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
def publish_a2a(
|
|
698
|
+
self, topic: str, payload: dict, user_properties: dict | None = None
|
|
699
|
+
):
|
|
700
|
+
"""
|
|
701
|
+
Publish direct message to deployer (not A2A protocol).
|
|
702
|
+
|
|
703
|
+
Platform Service sends deployment commands directly to deployer service.
|
|
704
|
+
This is service-to-service communication, not agent-to-agent protocol.
|
|
705
|
+
|
|
706
|
+
Commands sent to:
|
|
707
|
+
- {namespace}/deployer/agent/{agent_id}/deploy
|
|
708
|
+
- {namespace}/deployer/agent/{agent_id}/update
|
|
709
|
+
- {namespace}/deployer/agent/{agent_id}/undeploy
|
|
710
|
+
|
|
711
|
+
Args:
|
|
712
|
+
topic: Message topic
|
|
713
|
+
payload: Message payload dictionary (will be JSON-serialized)
|
|
714
|
+
user_properties: Optional user properties (not used by deployer)
|
|
715
|
+
|
|
716
|
+
Raises:
|
|
717
|
+
Exception: If publishing fails
|
|
718
|
+
"""
|
|
719
|
+
import json
|
|
720
|
+
from solace.messaging.resources.topic import Topic
|
|
721
|
+
|
|
722
|
+
log.debug("%s Publishing deployer command to topic: %s", self.log_identifier, topic)
|
|
723
|
+
|
|
724
|
+
try:
|
|
725
|
+
if not self.direct_publisher:
|
|
726
|
+
self._init_direct_publisher()
|
|
727
|
+
if not self.direct_publisher:
|
|
728
|
+
raise RuntimeError("Direct publisher not initialized")
|
|
729
|
+
|
|
730
|
+
# Serialize payload to JSON and convert to bytearray
|
|
731
|
+
message_body = json.dumps(payload)
|
|
732
|
+
message_bytes = bytearray(message_body.encode("utf-8"))
|
|
733
|
+
|
|
734
|
+
# Publish directly to topic
|
|
735
|
+
self.direct_publisher.publish(
|
|
736
|
+
message=message_bytes,
|
|
737
|
+
destination=Topic.of(topic)
|
|
738
|
+
)
|
|
739
|
+
|
|
740
|
+
log.debug(
|
|
741
|
+
"%s Successfully published deployer command to topic: %s (payload size: %d bytes)",
|
|
742
|
+
self.log_identifier,
|
|
743
|
+
topic,
|
|
744
|
+
len(message_body)
|
|
745
|
+
)
|
|
746
|
+
|
|
747
|
+
except Exception as e:
|
|
748
|
+
log.error(
|
|
749
|
+
"%s Failed to publish deployer command: %s",
|
|
750
|
+
self.log_identifier,
|
|
751
|
+
e,
|
|
752
|
+
exc_info=True
|
|
753
|
+
)
|
|
754
|
+
raise
|