solace-agent-mesh 1.5.0__py3-none-any.whl → 1.6.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.
Potentially problematic release.
This version of solace-agent-mesh might be problematic. Click here for more details.
- solace_agent_mesh/agent/adk/callbacks.py +14 -17
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +3 -1
- solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +2 -1
- solace_agent_mesh/agent/adk/mcp_content_processor.py +2 -1
- solace_agent_mesh/agent/adk/models/lite_llm.py +123 -8
- solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +245 -0
- solace_agent_mesh/agent/adk/runner.py +3 -1
- solace_agent_mesh/agent/adk/services.py +4 -1
- solace_agent_mesh/agent/adk/setup.py +3 -1
- solace_agent_mesh/agent/adk/tool_wrapper.py +2 -2
- solace_agent_mesh/agent/protocol/event_handlers.py +42 -2
- solace_agent_mesh/agent/proxies/__init__.py +0 -0
- solace_agent_mesh/agent/proxies/a2a/__init__.py +3 -0
- solace_agent_mesh/agent/proxies/a2a/app.py +55 -0
- solace_agent_mesh/agent/proxies/a2a/component.py +1115 -0
- solace_agent_mesh/agent/proxies/a2a/config.py +140 -0
- solace_agent_mesh/agent/proxies/a2a/oauth_token_cache.py +104 -0
- solace_agent_mesh/agent/proxies/base/__init__.py +3 -0
- solace_agent_mesh/agent/proxies/base/app.py +99 -0
- solace_agent_mesh/agent/proxies/base/component.py +619 -0
- solace_agent_mesh/agent/proxies/base/config.py +85 -0
- solace_agent_mesh/agent/proxies/base/proxy_task_context.py +17 -0
- solace_agent_mesh/agent/sac/app.py +12 -4
- solace_agent_mesh/agent/sac/component.py +164 -9
- solace_agent_mesh/agent/tools/audio_tools.py +127 -9
- solace_agent_mesh/agent/tools/builtin_artifact_tools.py +3 -1
- solace_agent_mesh/agent/tools/builtin_data_analysis_tools.py +3 -1
- solace_agent_mesh/agent/tools/dynamic_tool.py +2 -1
- solace_agent_mesh/agent/tools/general_agent_tools.py +2 -1
- solace_agent_mesh/agent/tools/image_tools.py +2 -1
- solace_agent_mesh/agent/tools/peer_agent_tool.py +2 -1
- solace_agent_mesh/agent/tools/registry.py +3 -1
- solace_agent_mesh/agent/tools/test_tools.py +2 -1
- solace_agent_mesh/agent/tools/web_tools.py +12 -6
- solace_agent_mesh/agent/utils/artifact_helpers.py +144 -4
- solace_agent_mesh/agent/utils/config_parser.py +3 -1
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/{b7006a3a.73a79653.js → 032c2d61.f3d37824.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/0bcf40b7.c019ad46.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2131ec11.5c7a1f6e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{2334.622a6395.js → 2334.1cf50a20.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/240a0364.7eac6021.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/341393d4.0fac2613.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{3624.b524e433.js → 3624.0eaa1fd0.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.76654dd9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/509e993c.4c7a1a6d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6063ff4c.ef84f702.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/631738c7.a8b1ef8b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6fdfefc7.99de744e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/71da7b71.38583438.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/722f809d.965da774.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/742f027b.46c07808.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/77cf947d.48cb18a2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8024126c.56e59919.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/81a99df0.07034dd9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/82fbfb93.139a1a1f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{8591.d7c16be6.js → 8591.5d015485.js} +2 -2
- solace_agent_mesh/assets/docs/assets/js/{8731.49e930c2.js → 8731.6c1dbf0c.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/945fb41e.6f4cdffd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/94e8668d.b5ddb7a1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9bb13469.dd1c9b54.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9e9d0a82.570c057b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e6dd091.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ad71b5ed.af3ecfd1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c198a0dc.8f31f867.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ceb2a7a6.5d92d7d0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/da0b5bad.d08a9466.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/db924877.e98d12a1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/de5f4c65.e8241890.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.2b916f9e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e6f9706b.e74a984d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e92d0134.cf6d6522.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.42f59cdd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.20feee82.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.0d198646.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +154 -0
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/artifact-management/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/audio-tools/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/data-analysis-tools/index.html +8 -8
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/embeds/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → components}/builtin-tools/index.html +11 -11
- solace_agent_mesh/assets/docs/docs/documentation/{concepts → components}/cli/index.html +25 -25
- solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +91 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/index.html +29 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +55 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +110 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +262 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +104 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +85 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +25 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +59 -0
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/create-agents/index.html +113 -152
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/create-gateways/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/{user-guide → developing}/creating-python-tools/index.html +12 -12
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +54 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +135 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +34 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +55 -0
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/bedrock-agents/index.html +25 -25
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/custom-agent/index.html +13 -13
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/event-mesh-gateway/index.html +12 -12
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/mcp-integration/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/mongodb-integration/index.html +13 -13
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/rag-integration/index.html +13 -13
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/rest-gateway/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +72 -0
- solace_agent_mesh/assets/docs/docs/documentation/{tutorials → developing/tutorials}/sql-database/index.html +14 -14
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +33 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +83 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +222 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +161 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +75 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +53 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +35 -100
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +41 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +81 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +25 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +76 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +160 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +142 -0
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +100 -0
- solace_agent_mesh/assets/docs/docs/documentation/{Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html → migrations/a2a-upgrade/a2a-technical-migration-map/index.html} +10 -11
- solace_agent_mesh/assets/docs/img/solace-logo.png +0 -0
- solace_agent_mesh/assets/docs/lunr-index-1761165361160.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1761165361160.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/agent_cmd.py +2 -69
- solace_agent_mesh/cli/commands/eval_cmd.py +11 -49
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +0 -5
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +10 -12
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +9 -61
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +9 -49
- solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +1 -2
- solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-DwrxZE0E.js → authCallback-BTf6dqwp.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-DarGQzyw.js → client-CaY59VuC.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-BGTaW0uv.js +342 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-DHJKSW1S.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{vendor-BKIeiHj_.js → vendor-BEmvJSYz.js} +1 -1
- 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/common/a2a/__init__.py +24 -0
- solace_agent_mesh/common/a2a/artifact.py +41 -1
- solace_agent_mesh/common/a2a/events.py +29 -0
- solace_agent_mesh/common/a2a/message.py +68 -0
- solace_agent_mesh/common/a2a/protocol.py +76 -3
- solace_agent_mesh/common/a2a/translation.py +3 -1
- solace_agent_mesh/common/agent_registry.py +83 -3
- solace_agent_mesh/common/constants.py +3 -1
- solace_agent_mesh/common/middleware/config_resolver.py +3 -1
- solace_agent_mesh/common/middleware/registry.py +3 -1
- solace_agent_mesh/common/sac/sam_component_base.py +2 -1
- solace_agent_mesh/common/sam_events/event_service.py +3 -2
- solace_agent_mesh/common/services/employee_service.py +3 -1
- solace_agent_mesh/common/services/identity_service.py +2 -1
- solace_agent_mesh/common/services/providers/local_file_identity_service.py +2 -1
- solace_agent_mesh/common/utils/artifact_utils.py +3 -1
- solace_agent_mesh/common/utils/asyncio_macos_fix.py +3 -1
- solace_agent_mesh/common/utils/embeds/converter.py +3 -1
- solace_agent_mesh/common/utils/embeds/evaluators.py +2 -1
- solace_agent_mesh/common/utils/embeds/modifiers.py +3 -2
- solace_agent_mesh/common/utils/embeds/resolver.py +2 -1
- solace_agent_mesh/common/utils/initializer.py +3 -1
- solace_agent_mesh/common/utils/message_utils.py +2 -1
- solace_agent_mesh/common/utils/push_notification_auth.py +3 -2
- solace_agent_mesh/common/utils/pydantic_utils.py +12 -0
- solace_agent_mesh/config_portal/backend/common.py +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +98 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-44d62be6.js → manifest-61038fc6.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
- solace_agent_mesh/core_a2a/service.py +2 -2
- solace_agent_mesh/evaluation/evaluator.py +128 -104
- solace_agent_mesh/evaluation/message_organizer.py +116 -110
- solace_agent_mesh/evaluation/report_data_processor.py +84 -86
- solace_agent_mesh/evaluation/report_generator.py +73 -79
- solace_agent_mesh/evaluation/run.py +421 -235
- solace_agent_mesh/evaluation/shared/__init__.py +92 -0
- solace_agent_mesh/evaluation/shared/constants.py +47 -0
- solace_agent_mesh/evaluation/shared/exceptions.py +50 -0
- solace_agent_mesh/evaluation/shared/helpers.py +35 -0
- solace_agent_mesh/evaluation/shared/test_case_loader.py +167 -0
- solace_agent_mesh/evaluation/shared/test_suite_loader.py +280 -0
- solace_agent_mesh/evaluation/subscriber.py +111 -232
- solace_agent_mesh/evaluation/summary_builder.py +227 -117
- solace_agent_mesh/gateway/base/app.py +3 -2
- solace_agent_mesh/gateway/base/component.py +11 -2
- solace_agent_mesh/gateway/base/task_context.py +2 -1
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251015_add_session_performance_indexes.py +70 -0
- solace_agent_mesh/gateway/http_sse/app.py +2 -1
- solace_agent_mesh/gateway/http_sse/component.py +102 -3
- solace_agent_mesh/gateway/http_sse/components/task_logger_forwarder.py +3 -2
- solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +3 -1
- solace_agent_mesh/gateway/http_sse/dependencies.py +7 -5
- solace_agent_mesh/gateway/http_sse/main.py +5 -2
- solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +12 -13
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +15 -18
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +25 -18
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +30 -26
- solace_agent_mesh/gateway/http_sse/repository/task_repository.py +35 -44
- solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +7 -5
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +97 -205
- solace_agent_mesh/gateway/http_sse/routers/auth.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/config.py +3 -2
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +4 -3
- solace_agent_mesh/gateway/http_sse/routers/people.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +5 -3
- solace_agent_mesh/gateway/http_sse/routers/sse.py +3 -2
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +35 -42
- solace_agent_mesh/gateway/http_sse/routers/users.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +19 -12
- solace_agent_mesh/gateway/http_sse/services/agent_card_service.py +3 -1
- solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +6 -5
- solace_agent_mesh/gateway/http_sse/services/feedback_service.py +53 -44
- solace_agent_mesh/gateway/http_sse/services/people_service.py +2 -2
- solace_agent_mesh/gateway/http_sse/services/session_service.py +23 -21
- solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +10 -9
- solace_agent_mesh/gateway/http_sse/services/task_service.py +3 -2
- solace_agent_mesh/gateway/http_sse/session_manager.py +2 -1
- solace_agent_mesh/gateway/http_sse/shared/base_repository.py +45 -71
- solace_agent_mesh/gateway/http_sse/shared/types.py +0 -18
- solace_agent_mesh/gateway/http_sse/sse_event_buffer.py +2 -1
- solace_agent_mesh/gateway/http_sse/sse_manager.py +2 -2
- solace_agent_mesh/templates/gateway_app_template.py +4 -2
- solace_agent_mesh/templates/gateway_component_template.py +3 -1
- solace_agent_mesh/templates/gateway_config_template.yaml +0 -5
- solace_agent_mesh/templates/logging_config_template.ini +27 -46
- solace_agent_mesh/templates/plugin_gateway_config_template.yaml +0 -3
- solace_agent_mesh/templates/plugin_tools_template.py +2 -2
- solace_agent_mesh/templates/shared_config.yaml +40 -0
- {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/METADATA +47 -21
- {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/RECORD +254 -225
- solace_agent_mesh/assets/docs/assets/images/sac-flows-80d5b603c6aafd33e87945680ce0abf3.png +0 -0
- solace_agent_mesh/assets/docs/assets/images/sac_parts_of_a_component-cb3d0424b1d0c17734c5435cca6b4082.png +0 -0
- solace_agent_mesh/assets/docs/assets/js/04989206.a248f00c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/0e682baa.d54b8668.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1023fc19.8a8a9309.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1523c6b4.2645ef68.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/166ab619.e27886d9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1c6e87d2.e056b7e0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/21ceee5f.3bf39250.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/2a9cab12.2afaee76.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/332e10b5.f7629851.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3d406171.5560fdf9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.508ae8db.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/442a8107.b5c2532a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/453a82a6.3c6bb61d.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/483cef9a.bf9398af.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/4c2787c2.c1290a40.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/55f47984.bcd00a86.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/5b4258a4.fdfd2325.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/664b740a.ba305a89.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/75384d09.c19e8b51.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/768e31b0.9abcdc48.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/85387663.be2bc838.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/945fb41e.16e00776.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9a09e75d.92de8cf5.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9eff14a2.d62aad71.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/a12a4955.25fbed32.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/a3a92b25.af35e313.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/aba87c2f.4ddf32f2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.5fe5203f.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ae4415af.16cc58d3.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/bac0be12.17de4316.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c2c06897.87cb1f47.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c835a94d.ce21f0bf.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cc969b05.feef7dcc.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cd3d4052.a19e7d78.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ced92a13.fb92e7ca.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cee5d587.47904f5e.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/d6a81ee7.829198f1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.ed8dd236.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f897a61a.126663fe.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/fbfa3e75.e144b16c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.0c149855.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.c66557e4.js +0 -1
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +0 -46
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/rbac-setup-guilde/index.html +0 -201
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +0 -29
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +0 -105
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +0 -144
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +0 -91
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +0 -91
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +0 -55
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +0 -111
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +0 -77
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +0 -48
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +0 -54
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +0 -45
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +0 -74
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/litellm_models/index.html +0 -49
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +0 -76
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +0 -73
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +0 -72
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +0 -54
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +0 -69
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +0 -59
- solace_agent_mesh/assets/docs/lunr-index-1760032255022.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1760032255022.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-CZbpmwfA.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-C__uuUkB.js +0 -339
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-BNuqpWDc.js +0 -98
- solace_agent_mesh/evaluation/config_loader.py +0 -657
- solace_agent_mesh/evaluation/test_case_loader.py +0 -714
- /solace_agent_mesh/assets/docs/assets/js/{8591.d7c16be6.js.LICENSE.txt → 8591.5d015485.js.LICENSE.txt} +0 -0
- /solace_agent_mesh/assets/docs/assets/js/{main.0c149855.js.LICENSE.txt → main.20feee82.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.5.0.dist-info → solace_agent_mesh-1.6.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[1537],{9377:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"documentation/developing/tutorials/rag-integration","title":"RAG Integration","description":"This tutorial guides you through setting up and configuring Agent Mesh Retrieval Augmented Generation (RAG) plugin. The RAG plugin enables your agents to answer questions by retrieving information from a knowledge base of your documents.","source":"@site/docs/documentation/developing/tutorials/rag-integration.md","sourceDirName":"documentation/developing/tutorials","slug":"/documentation/developing/tutorials/rag-integration","permalink":"/solace-agent-mesh/docs/documentation/developing/tutorials/rag-integration","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/developing/tutorials/rag-integration.md","tags":[],"version":"current","sidebarPosition":70,"frontMatter":{"title":"RAG Integration","sidebar_position":70,"toc_max_heading_level":4},"sidebar":"docSidebar","previous":{"title":"Slack Integration","permalink":"/solace-agent-mesh/docs/documentation/developing/tutorials/slack-integration"},"next":{"title":"Deploying Agent Mesh","permalink":"/solace-agent-mesh/docs/documentation/deploying/"}}');var r=t(4848),a=t(8453);const o={title:"RAG Integration",sidebar_position:70,toc_max_heading_level:4},s="RAG Integration",l={},c=[{value:"What is Agent Mesh RAG?",id:"what-is-agent-mesh-rag",level:2},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Adding the RAG Plugin",id:"adding-the-rag-plugin",level:2},{value:"Configuring the RAG Agent",id:"configuring-the-rag-agent",level:2},{value:"Shared Configuration",id:"shared-configuration",level:3},{value:"RAG Pipeline Configuration",id:"rag-pipeline-configuration",level:3},{value:"1. Scanner Configuration",id:"1-scanner-configuration",level:4},{value:"2. Preprocessor Configuration",id:"2-preprocessor-configuration",level:4},{value:"3. Splitter Configuration",id:"3-splitter-configuration",level:4},{value:"4. Embedding Configuration",id:"4-embedding-configuration",level:4},{value:"5. Vector Database Configuration",id:"5-vector-database-configuration",level:4},{value:"6. LLM Configuration",id:"6-llm-configuration",level:4},{value:"7. Retrieval Configuration",id:"7-retrieval-configuration",level:4},{value:"Environment Variables",id:"environment-variables",level:3},{value:"Running the RAG Agent",id:"running-the-rag-agent",level:2},{value:"Testing the RAG Agent",id:"testing-the-rag-agent",level:2},{value:"Ingesting Documents",id:"ingesting-documents",level:3},{value:"Option 1: Automatic Scanning (Batch Ingestion)",id:"option-1-automatic-scanning-batch-ingestion",level:4},{value:"Option 2: Manual Upload via Gateway",id:"option-2-manual-upload-via-gateway",level:4},{value:"Querying the Knowledge Base",id:"querying-the-knowledge-base",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2}];function d(e){const n={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"rag-integration",children:"RAG Integration"})}),"\n",(0,r.jsx)(n.p,{children:"This tutorial guides you through setting up and configuring Agent Mesh Retrieval Augmented Generation (RAG) plugin. The RAG plugin enables your agents to answer questions by retrieving information from a knowledge base of your documents."}),"\n",(0,r.jsx)(n.h2,{id:"what-is-agent-mesh-rag",children:"What is Agent Mesh RAG?"}),"\n",(0,r.jsx)(n.p,{children:"The Agent Mesh RAG plugin enhances your agents with the ability to perform retrieval-augmented generation. This means the agent can:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Scan"})," documents from various sources (local filesystem, Google Drive, etc.)."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Preprocess"})," and ",(0,r.jsx)(n.strong,{children:"split"})," the text into manageable chunks."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Embed"})," these chunks into vectors and store them in a vector database."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Retrieve"})," relevant chunks of text based on a user's query."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Generate"})," an answer using a large language model (LLM) augmented with the retrieved information."]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"This allows you to build agents that can answer questions about your own private data."}),"\n",(0,r.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,r.jsx)(n.p,{children:"Before you begin, ensure you have:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/installing-and-configuring/installation",children:"Installed Agent Mesh and the Agent Mesh CLI"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/installing-and-configuring/run-project",children:"Created a new Agent Mesh project"}),"."]}),"\n",(0,r.jsx)(n.li,{children:"Access to a vector database (for example, Qdrant, Chroma, and Pinecone)."}),"\n",(0,r.jsx)(n.li,{children:"Access to an LLM for generation and an embedding model."}),"\n",(0,r.jsx)(n.li,{children:"A directory with some documents for the agent to ingest."}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"adding-the-rag-plugin",children:"Adding the RAG Plugin"}),"\n",(0,r.jsx)(n.p,{children:"To add the RAG plugin to your Agent Mesh project, run the following command:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"sam plugin add my-rag-agent --plugin sam-rag\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Replace ",(0,r.jsx)(n.code,{children:"my-rag-agent"})," with your preferred agent name. This command:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Installs the ",(0,r.jsx)(n.code,{children:"sam-rag"})," plugin."]}),"\n",(0,r.jsxs)(n.li,{children:["Creates a new agent configuration file at ",(0,r.jsx)(n.code,{children:"configs/agents/my-rag-agent.yaml"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"configuring-the-rag-agent",children:"Configuring the RAG Agent"}),"\n",(0,r.jsxs)(n.p,{children:["The RAG agent requires a detailed configuration. Open ",(0,r.jsx)(n.code,{children:"configs/agents/my-rag-agent.yaml"})," to configure the following sections:"]}),"\n",(0,r.jsx)(n.h3,{id:"shared-configuration",children:"Shared Configuration"}),"\n",(0,r.jsxs)(n.p,{children:["Like other agents, the RAG agent needs a connection to the Solace broker and a configured LLM. This is typically done in a ",(0,r.jsx)(n.code,{children:"shared_config.yaml"})," file."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"# configs/shared_config.yaml\nshared_config:\n - broker_connection: &broker_connection\n dev_mode: ${SOLACE_DEV_MODE, false}\n broker_url: ${SOLACE_BROKER_URL, ws://localhost:8008}\n broker_username: ${SOLACE_BROKER_USERNAME, default}\n broker_password: ${SOLACE_BROKER_PASSWORD, default}\n broker_vpn: ${SOLACE_BROKER_VPN, default}\n temporary_queue: ${USE_TEMPORARY_QUEUES, true}\n\n - models:\n general: &general_model\n model: ${LLM_SERVICE_GENERAL_MODEL_NAME}\n api_base: ${LLM_SERVICE_ENDPOINT}\n api_key: ${LLM_SERVICE_API_KEY}\n"})}),"\n",(0,r.jsx)(n.h3,{id:"rag-pipeline-configuration",children:"RAG Pipeline Configuration"}),"\n",(0,r.jsxs)(n.p,{children:["The RAG pipeline has several stages, each with its own configuration block within the ",(0,r.jsx)(n.code,{children:"app_config"})," section of your ",(0,r.jsx)(n.code,{children:"my-rag-agent.yaml"})," file."]}),"\n",(0,r.jsx)(n.h4,{id:"1-scanner-configuration",children:"1. Scanner Configuration"}),"\n",(0,r.jsx)(n.p,{children:"The scanner discovers documents to be ingested. You can configure it to scan a local filesystem or cloud sources."}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Local Filesystem Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'scanner:\n batch: true\n use_memory_storage: true\n source:\n type: filesystem\n directories:\n - "/path/to/your/documents" # Important: Replace with your actual document directory path\n filters:\n file_formats:\n - ".txt"\n - ".pdf"\n - ".md"\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Multi-Cloud Source Example:"}),"\nYou can also configure multiple sources, including Google Drive, OneDrive, and S3."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'scanner:\n batch: true\n use_memory_storage: true\n sources:\n - type: filesystem\n directories: ["${LOCAL_DOCUMENTS_PATH}"]\n - type: google_drive\n credentials_path: "${GOOGLE_DRIVE_CREDENTIALS_PATH}"\n folders:\n - folder_id: "${GOOGLE_DRIVE_FOLDER_ID_1}"\n name: "Documents"\n recursive: true\n'})}),"\n",(0,r.jsx)(n.h4,{id:"2-preprocessor-configuration",children:"2. Preprocessor Configuration"}),"\n",(0,r.jsx)(n.p,{children:"The preprocessor cleans the text extracted from documents."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"preprocessor:\n default_preprocessor:\n type: enhanced\n params:\n lowercase: true\n normalize_whitespace: true\n remove_urls: true\n preprocessors:\n pdf: \n type: document\n params:\n lowercase: true\n normalize_whitespace: true\n remove_non_ascii: true\n remove_urls: true\n"})}),"\n",(0,r.jsx)(n.h4,{id:"3-splitter-configuration",children:"3. Splitter Configuration"}),"\n",(0,r.jsx)(n.p,{children:"The splitter breaks down large documents into smaller chunks. Different splitters are available for different file types."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"splitter:\n default_splitter:\n type: recursive_character\n params:\n chunk_size: 2048\n chunk_overlap: 400\n splitters:\n markdown:\n type: markdown\n params:\n chunk_size: 2048\n chunk_overlap: 400\n pdf:\n type: token\n params:\n chunk_size: 500\n chunk_overlap: 100\n"})}),"\n",(0,r.jsx)(n.h4,{id:"4-embedding-configuration",children:"4. Embedding Configuration"}),"\n",(0,r.jsx)(n.p,{children:"This section defines the model used to create vector embeddings from the text chunks."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'embedding:\n embedder_type: "openai"\n embedder_params:\n model: "${OPENAI_EMBEDDING_MODEL}"\n api_key: "${OPENAI_API_KEY}"\n api_base: "${OPENAI_API_ENDPOINT}"\n normalize_embeddings: true\n'})}),"\n",(0,r.jsx)(n.h4,{id:"5-vector-database-configuration",children:"5. Vector Database Configuration"}),"\n",(0,r.jsx)(n.p,{children:"Configure the connection to your vector database where the embeddings are stored."}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Qdrant Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'vector_db:\n db_type: "qdrant"\n db_params:\n url: "${QDRANT_URL}"\n api_key: "${QDRANT_API_KEY}"\n collection_name: "${QDRANT_COLLECTION}"\n embedding_dimension: ${QDRANT_EMBEDDING_DIMENSION}\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Chroma Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'vector_db:\n db_type: "chroma"\n db_params:\n host: "${CHROMA_HOST}"\n port: "${CHROMA_PORT}"\n collection_name: "${CHROMA_COLLECTION}"\n'})}),"\n",(0,r.jsx)(n.h4,{id:"6-llm-configuration",children:"6. LLM Configuration"}),"\n",(0,r.jsx)(n.p,{children:"Configure the LLM that is used to generate answers based on the retrieved context."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'llm:\n load_balancer:\n - model_name: "gpt-4o"\n litellm_params:\n model: "openai/${OPENAI_MODEL_NAME}"\n api_key: "${OPENAI_API_KEY}"\n api_base: "${OPENAI_API_ENDPOINT}"\n'})}),"\n",(0,r.jsx)(n.h4,{id:"7-retrieval-configuration",children:"7. Retrieval Configuration"}),"\n",(0,r.jsx)(n.p,{children:"This defines how many document chunks are retrieved to answer a query."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"retrieval:\n top_k: 7\n"})}),"\n",(0,r.jsx)(n.h3,{id:"environment-variables",children:"Environment Variables"}),"\n",(0,r.jsxs)(n.p,{children:["The RAG agent relies heavily on environment variables. Here are some of the most important ones you'll need to set in your ",(0,r.jsx)(n.code,{children:".env"})," file:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'# Solace Connection\nSOLACE_BROKER_URL=ws://localhost:8008\nSOLACE_BROKER_VPN=default\nSOLACE_BROKER_USERNAME=default\nSOLACE_BROKER_PASSWORD=default\nNAMESPACE=my-org/dev\n\n# LLM and Embedding Models\nOPENAI_API_KEY="your-openai-api-key"\nOPENAI_API_ENDPOINT="your-openai-api-endpoint"\nOPENAI_MODEL_NAME="model name. E.g., gpt-4o"\nOPENAI_EMBEDDING_MODEL="embedding model name. E.g., text-embedding-3-small"\n\n# Vector Database (Qdrant example)\nQDRANT_URL="Qdrant url"\nQDRANT_API_KEY="API key"\nQDRANT_COLLECTION="my-rag-collection"\nQDRANT_EMBEDDING_DIMENSION=1536 # Depends on your embedding model\n\n# Scanner\nLOCAL_DOCUMENTS_PATH="./my_documents" # Relative path to your documents folder\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Create a directory named ",(0,r.jsx)(n.code,{children:"my_documents"})," in your project root and place some text or markdown files inside it."]}),"\n",(0,r.jsx)(n.h2,{id:"running-the-rag-agent",children:"Running the RAG Agent"}),"\n",(0,r.jsx)(n.p,{children:"Once you have configured your agent and set the environment variables, you can run it:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"sam run configs/agents/my-rag-agent.yaml\n"})}),"\n",(0,r.jsx)(n.p,{children:"When the agent starts, it begins scanning the documents in the configured source, processing and ingesting them into your vector database. This process may take some time, depending on the number and size of your documents."}),"\n",(0,r.jsx)(n.h2,{id:"testing-the-rag-agent",children:"Testing the RAG Agent"}),"\n",(0,r.jsx)(n.p,{children:"Once your agent is running, you can test its retrieval capabilities and ingest new documents."}),"\n",(0,r.jsx)(n.h3,{id:"ingesting-documents",children:"Ingesting Documents"}),"\n",(0,r.jsx)(n.p,{children:"There are two primary ways to ingest documents into your RAG agent's knowledge base:"}),"\n",(0,r.jsx)(n.h4,{id:"option-1-automatic-scanning-batch-ingestion",children:"Option 1: Automatic Scanning (Batch Ingestion)"}),"\n",(0,r.jsxs)(n.p,{children:["This method uses the configured ",(0,r.jsx)(n.code,{children:"scanner"})," component. The agent automatically ingests documents from the directories specified in your configuration upon startup."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Step 1: Create a Document"})}),"\n",(0,r.jsxs)(n.p,{children:["First, create a simple text file named ",(0,r.jsx)(n.code,{children:"sam_features.txt"})," and add some content to it. For example:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-text",children:"Agent Mesh is a powerful framework for building AI agents.\nKey features of Agent Mesh include:\n- A flexible plugin architecture.\n- Integration with various LLMs and vector databases.\n- Scalable gateways for different communication protocols.\n- An event-driven design based on Solace event broker.\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Step 2: Place the Document in the Scanned Directory"})}),"\n",(0,r.jsxs)(n.p,{children:['In the "Environment Variables" section, we configured ',(0,r.jsx)(n.code,{children:"LOCAL_DOCUMENTS_PATH"})," to point to a directory (e.g., ",(0,r.jsx)(n.code,{children:"./my_documents"}),")."]}),"\n",(0,r.jsxs)(n.p,{children:["Create this directory in your project's root folder if you haven't already, and move your ",(0,r.jsx)(n.code,{children:"sam_features.txt"})," file into it."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"mkdir -p my_documents\nmv sam_features.txt my_documents/\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Step 3: Run the Agent to Trigger Ingestion"})}),"\n",(0,r.jsx)(n.p,{children:"If your agent is already running, you'll need to restart it to trigger the batch scan. If it's not running, start it now:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sh",children:"sam run configs/agents/my-rag-agent.yaml\n"})}),"\n",(0,r.jsx)(n.p,{children:"You will see logs indicating that the file is being processed. Once the agent is running and the initial scan is complete, the document is successfully ingested and ready for retrieval."}),"\n",(0,r.jsx)(n.h4,{id:"option-2-manual-upload-via-gateway",children:"Option 2: Manual Upload via Gateway"}),"\n",(0,r.jsx)(n.p,{children:"You can also ingest documents dynamically by uploading them directly through a gateway, like the Web UI. This is useful for adding single documents without restarting the agent. The RAG agent exposes a tool for this purpose."}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Step 1: Start the RAG Agent and Web UI"})}),"\n",(0,r.jsx)(n.p,{children:"Ensure both your RAG agent and the Web UI gateway are running."}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Step 2: Upload a Document in the Web UI"})}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["Open the Web UI (usually at ",(0,r.jsx)(n.a,{href:"http://localhost:8000",children:"http://localhost:8000"}),", or check your gateway configuration for the correct URL) and start a chat with your RAG agent."]}),"\n",(0,r.jsx)(n.li,{children:"Use the file attachment button to select a document from your local machine."}),"\n",(0,r.jsxs)(n.li,{children:["Send a prompt along with the file, instructing the agent to ingest it. For example:","\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsx)(n.p,{children:'"Please ingest the attached document into your knowledge base."'}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["The RAG agent uses its ",(0,r.jsx)(n.code,{children:"built-in"})," ingest_document tool to process the file you uploaded. The file goes through the same preprocessing, splitting, and embedding pipeline as the documents from the automatic scan."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Step 3: Confirm Ingestion"})}),"\n",(0,r.jsx)(n.p,{children:"After the agent confirms that the document has been ingested, you can immediately ask questions about its content."}),"\n",(0,r.jsx)(n.h3,{id:"querying-the-knowledge-base",children:"Querying the Knowledge Base"}),"\n",(0,r.jsx)(n.p,{children:"You can interact with your RAG agent through any gateway, such as the Web UI gateway."}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"Make sure you have a Web UI gateway running (or add one to your project)."}),"\n",(0,r.jsxs)(n.li,{children:["Open the Web UI (usually at ",(0,r.jsx)(n.code,{children:"http://localhost:8000"}),")."]}),"\n",(0,r.jsxs)(n.li,{children:["Start a conversation with ",(0,r.jsx)(n.code,{children:"my-rag-agent"}),"."]}),"\n",(0,r.jsx)(n.li,{children:"Ask a question related to the content of the documents you provided during the initial scan."}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"For example, if you have a document about product features, you could ask:"}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsx)(n.p,{children:'"What are the key features of Product X?"'}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"The agent searches its knowledge base, finds the relevant information, and generates an answer based on the content of your documents."}),"\n",(0,r.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Connection Errors"}),": Double-check all your URLs, API keys, and credentials for your LLM and vector database."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Ingestion Issues"}),": Check the agent logs for errors during the scanning, preprocessing, or embedding stages. Ensure the file formats are supported and the paths are correct."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"No Answers"}),": If the agent can't answer, it might be because the information is not in the documents, or the ",(0,r.jsx)(n.code,{children:"top_k"})," retrieval setting is too low."]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>s});var i=t(6540);const r={},a=i.createContext(r);function o(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[3478],{2467:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>r,contentTitle:()=>l,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"documentation/developing/evaluations","title":"Evaluating Agents","description":"The framework includes an evaluation system that helps you test your agents\' behavior in a structured way. You can define test suites, run them against your agents, and generate detailed reports to analyze the results. When running evaluations locally, you can also benchmark different language models to see how they affect your agents\' responses.","source":"@site/docs/documentation/developing/evaluations.md","sourceDirName":"documentation/developing","slug":"/documentation/developing/evaluations","permalink":"/solace-agent-mesh/docs/documentation/developing/evaluations","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/developing/evaluations.md","tags":[],"version":"current","sidebarPosition":450,"frontMatter":{"title":"Evaluating Agents","sidebar_position":450},"sidebar":"docSidebar","previous":{"title":"Creating Service Providers","permalink":"/solace-agent-mesh/docs/documentation/developing/creating-service-providers"},"next":{"title":"Build Your Own Agent","permalink":"/solace-agent-mesh/docs/documentation/developing/tutorials/custom-agent"}}');var a=t(4848),o=t(8453);const i={title:"Evaluating Agents",sidebar_position:450},l="Evaluating Agents",r={},c=[{value:"Creating a Test Case",id:"creating-a-test-case",level:2},{value:"Test Case Configuration",id:"test-case-configuration",level:3},{value:"Test Case Examples",id:"test-case-examples",level:3},{value:"Creating a Test Suite",id:"creating-a-test-suite",level:2},{value:"Local Evaluation",id:"local-evaluation",level:3},{value:"Local Test Suite Configuration",id:"local-test-suite-configuration",level:4},{value:"Example Local Test Suite",id:"example-local-test-suite",level:4},{value:"Remote Evaluation",id:"remote-evaluation",level:3},{value:"Remote Test Suite Configuration",id:"remote-test-suite-configuration",level:4},{value:"Example Remote Test Suite",id:"example-remote-test-suite",level:4},{value:"Evaluation Settings",id:"evaluation-settings",level:2},{value:"<code>tool_match</code>",id:"tool_match",level:3},{value:"<code>response_match</code>",id:"response_match",level:3},{value:"<code>llm_evaluator</code>",id:"llm_evaluator",level:3},{value:"Running Evaluations",id:"running-evaluations",level:2},{value:"Command",id:"command",level:3},{value:"Options",id:"options",level:3},{value:"Example",id:"example",level:3},{value:"Interpreting the Results",id:"interpreting-the-results",level:2},{value:"Results Directory",id:"results-directory",level:3},{value:"HTML Report",id:"html-report",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.header,{children:(0,a.jsx)(n.h1,{id:"evaluating-agents",children:"Evaluating Agents"})}),"\n",(0,a.jsx)(n.p,{children:"The framework includes an evaluation system that helps you test your agents' behavior in a structured way. You can define test suites, run them against your agents, and generate detailed reports to analyze the results. When running evaluations locally, you can also benchmark different language models to see how they affect your agents' responses."}),"\n",(0,a.jsx)(n.p,{children:"At a high level, the evaluation process involves three main components:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:"Test Case"}),": A ",(0,a.jsx)(n.code,{children:"JSON"})," file that defines a single, specific task for an agent to perform. It includes the initial prompt, any required files (artifacts), and the criteria for a successful outcome."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:"Test Suite"}),": A ",(0,a.jsx)(n.code,{children:"JSON"})," file that groups one or more test cases into a single evaluation run. It also defines the environment for the evaluation, such as whether to run the agents locally or connect to a remote Agent Mesh."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:"Evaluation Settings"}),": A configuration block within the test suite that specifies how to score the agent's performance. You can choose from several methods, from simple metric-based comparisons to more advanced evaluations using a language model."]}),"\n"]}),"\n",(0,a.jsx)(n.p,{children:"This document guides you through creating test cases, assembling them into test suites, and running evaluations to test your agents."}),"\n",(0,a.jsx)(n.h2,{id:"creating-a-test-case",children:"Creating a Test Case"}),"\n",(0,a.jsxs)(n.p,{children:["A test case is a ",(0,a.jsx)(n.code,{children:"JSON"})," file that defines a specific task for an agent to perform. It serves as the fundamental building block of an evaluation. You create a test case to represent a single interaction you want to test, such as asking a question, providing a file for processing, or requesting a specific action from an agent."]}),"\n",(0,a.jsx)(n.h3,{id:"test-case-configuration",children:"Test Case Configuration"}),"\n",(0,a.jsxs)(n.p,{children:["The following fields are available in the test case ",(0,a.jsx)(n.code,{children:"JSON"})," file."]}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"test_case_id"})," (Required): A unique identifier for the test case."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"query"})," (Required): The initial prompt to be sent to the agent."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"target_agent"})," (Required): The name of the agent to which the query should be sent."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"category"})," (Optional): The category of the test case. Defaults to ",(0,a.jsx)(n.code,{children:"Other"}),"."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"description"})," (Optional): A description of the test case."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"artifacts"})," (Optional): A list of artifacts to be sent with the initial query. Each artifact has a ",(0,a.jsx)(n.code,{children:"type"})," and a ",(0,a.jsx)(n.code,{children:"path"}),"."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"wait_time"})," (Optional): The maximum time in seconds to wait for a response from the agent. Defaults to ",(0,a.jsx)(n.code,{children:"60"}),"."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"evaluation"})," (Optional): The evaluation criteria for the test case.","\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"expected_tools"})," (Optional): A list of tools that the agent is expected to use. Defaults to an empty list."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"expected_response"})," (Optional): The expected final response from the agent. Defaults to an empty string."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"criterion"})," (Optional): The criterion to be used by the ",(0,a.jsx)(n.code,{children:"llm_evaluator"}),". Defaults to an empty string."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"test-case-examples",children:"Test Case Examples"}),"\n",(0,a.jsx)(n.p,{children:"Here is an example of a simple test case. It sends a greeting to an agent and checks for a standard response."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'{\n "test_case_id": "hello_world",\n "category": "Content Generation",\n "description": "A simple test case to check the basic functionality of the system.",\n "query": "Hello, world!",\n "target_agent": "OrchestratorAgent",\n "wait_time": 30,\n "evaluation": {\n "expected_tools": [],\n "expected_response": "Hello! How can I help you today?",\n "criterion": "Evaluate if the agent provides a standard greeting."\n }\n}\n'})}),"\n",(0,a.jsxs)(n.p,{children:["This next example shows a more complex test case. It includes a ",(0,a.jsx)(n.code,{children:"CSV"})," file as an artifact and asks the agent to filter the data in the file."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'{\n "test_case_id": "filter_csv_employees_by_age_and_country",\n "category": "Tool Usage",\n "description": "A test case to filter employees from a CSV file based on age and country.",\n "target_agent": "OrchestratorAgent",\n "query": "From the attached CSV, please list the names of all people who are older or equal to 30 and live in the USA.",\n "artifacts": [\n {\n "type": "file",\n "path": "artifacts/sample.csv"\n }\n ],\n "wait_time": 120,\n "evaluation": {\n "expected_tools": ["extract_content_from_artifact"],\n "expected_response": "The person who is 30 or older and lives in the USA is John Doe.",\n "criterion": "Evaluate if the agent correctly filters the CSV data."\n }\n}\n'})}),"\n",(0,a.jsx)(n.h2,{id:"creating-a-test-suite",children:"Creating a Test Suite"}),"\n",(0,a.jsxs)(n.p,{children:["The test suite is a ",(0,a.jsx)(n.code,{children:"JSON"})," file that defines the parameters of an evaluation run. You use it to group test cases and configure the environment in which they run."]}),"\n",(0,a.jsxs)(n.p,{children:["A common convention in the test suite configuration is to use keys ending with ",(0,a.jsx)(n.code,{children:"_VAR"}),". These keys indicate that the corresponding value is the name of an environment variable from which the framework should read the actual value. This practice helps you keep sensitive information\u2014like API keys and credentials\u2014out of your configuration files. This convention applies to the ",(0,a.jsx)(n.code,{children:"broker"})," object, the ",(0,a.jsx)(n.code,{children:"env"})," object within ",(0,a.jsx)(n.code,{children:"llm_models"}),", and the ",(0,a.jsx)(n.code,{children:"env"})," object within the ",(0,a.jsx)(n.code,{children:"llm_evaluator"})," in ",(0,a.jsx)(n.code,{children:"evaluation_settings"}),"."]}),"\n",(0,a.jsx)(n.p,{children:"You can run evaluations in two modes: local and remote. Both modes require a connection to a Solace event broker to function."}),"\n",(0,a.jsx)(n.h3,{id:"local-evaluation",children:"Local Evaluation"}),"\n",(0,a.jsx)(n.p,{children:"In a local evaluation, the evaluation framework brings up a local instance of Solace Agent Mesh (SAM) and runs the agents on your local machine. This mode is useful for development and testing because it allows you to iterate quickly on your agents and test cases. You can also use this mode to benchmark different language models against your agents to see how they perform."}),"\n",(0,a.jsxs)(n.p,{children:["To run a local evaluation, you need to install the ",(0,a.jsx)(n.code,{children:"sam-rest-gateway"})," plugin. This plugin allows the evaluation framework to communicate with the local SAM instance. You can install it with the following command:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:'pip install "sam-rest-gateway @ git+https://github.com/SolaceLabs/solace-agent-mesh-core-plugins#subdirectory=sam-rest-gateway"\n'})}),"\n",(0,a.jsx)(n.h4,{id:"local-test-suite-configuration",children:"Local Test Suite Configuration"}),"\n",(0,a.jsxs)(n.p,{children:["For a local evaluation, you must define the ",(0,a.jsx)(n.code,{children:"agents"}),", ",(0,a.jsx)(n.code,{children:"broker"}),", ",(0,a.jsx)(n.code,{children:"llm_models"}),", and ",(0,a.jsx)(n.code,{children:"test_cases"})," fields."]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"agents"})," field is a required list of paths to the agent configuration files. You must specify at least one agent."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"agents": [ "examples/agents/a2a_agents_example.yaml" ]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"broker"})," field is a required object containing the connection details for the Solace event broker."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"broker": {\n "SOLACE_BROKER_URL_VAR": "SOLACE_BROKER_URL",\n "SOLACE_BROKER_USERNAME_VAR": "SOLACE_BROKER_USERNAME",\n "SOLACE_BROKER_PASSWORD_VAR": "SOLACE_BROKER_PASSWORD",\n "SOLACE_BROKER_VPN_VAR": "SOLACE_BROKER_VPN"\n}\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"llm_models"})," field is a required list of language models to use. You must specify at least one model. The ",(0,a.jsx)(n.code,{children:"env"})," object contains environment variables required by the model, such as the model name, endpoint, and API key."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"llm_models": [\n {\n "name": "gpt-4-1",\n "env": {\n "LLM_SERVICE_PLANNING_MODEL_NAME": "openai/azure-gpt-4-1",\n "LLM_SERVICE_ENDPOINT_VAR": "LLM_SERVICE_ENDPOINT",\n "LLM_SERVICE_API_KEY_VAR": "LLM_SERVICE_API_KEY"\n }\n },\n {\n "name": "gemini-1.5-pro",\n "env": {\n "LLM_SERVICE_PLANNING_MODEL_NAME": "google/gemini-1.5-pro-latest",\n "LLM_SERVICE_ENDPOINT_VAR": "LLM_SERVICE_ENDPOINT_GOOGLE",\n "LLM_SERVICE_API_KEY_VAR": "LLM_SERVICE_API_KEY_GOOGLE"\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"test_cases"})," field is a required list of paths to the test case ",(0,a.jsx)(n.code,{children:"JSON"})," files. You must specify at least one test case."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"test_cases": [ "tests/evaluation/test_cases/hello_world.test.json" ]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["You can also provide optional settings for ",(0,a.jsx)(n.code,{children:"results_dir_name"}),", ",(0,a.jsx)(n.code,{children:"runs"}),", ",(0,a.jsx)(n.code,{children:"workers"}),", and ",(0,a.jsx)(n.code,{children:"evaluation_settings"}),"."]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"results_dir_name"})," field is an optional string that specifies the name of the directory for evaluation results. It defaults to ",(0,a.jsx)(n.code,{children:"tests"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"results_dir_name": "my-local-test-results"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"runs"})," field is an optional integer that specifies the number of times to run each test case. It defaults to ",(0,a.jsx)(n.code,{children:"1"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"runs": 3\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"workers"})," field is an optional integer that specifies the number of parallel workers for running tests. It defaults to ",(0,a.jsx)(n.code,{children:"4"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"workers": 8\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"evaluation_settings"})," field is an optional object that allows you to configure the evaluation. This object can contain ",(0,a.jsx)(n.code,{children:"tool_match"}),", ",(0,a.jsx)(n.code,{children:"response_match"}),", and ",(0,a.jsx)(n.code,{children:"llm_evaluator"})," settings."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"evaluation_settings": {\n "tool_match": {\n "enabled": true\n },\n "response_match": {\n "enabled": true\n },\n "llm_evaluator": {\n "enabled": true,\n "env": {\n "LLM_SERVICE_PLANNING_MODEL_NAME": "openai/gemini-2.5-pro",\n "LLM_SERVICE_ENDPOINT_VAR": "LLM_SERVICE_ENDPOINT",\n "LLM_SERVICE_API_KEY_VAR": "LLM_SERVICE_API_KEY"\n }\n }\n}\n'})}),"\n",(0,a.jsx)(n.h4,{id:"example-local-test-suite",children:"Example Local Test Suite"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'{\n "agents": [\n "examples/agents/a2a_agents_example.yaml",\n "examples/agents/multimodal_example.yaml",\n "examples/agents/orchestrator_example.yaml"\n ],\n "broker": {\n "SOLACE_BROKER_URL_VAR": "SOLACE_BROKER_URL",\n "SOLACE_BROKER_USERNAME_VAR": "SOLACE_BROKER_USERNAME",\n "SOLACE_BROKER_PASSWORD_VAR": "SOLACE_BROKER_PASSWORD",\n "SOLACE_BROKER_VPN_VAR": "SOLACE_BROKER_VPN"\n },\n "llm_models": [\n {\n "name": "gpt-4-1",\n "env": {\n "LLM_SERVICE_PLANNING_MODEL_NAME": "openai/azure-gpt-4-1",\n "LLM_SERVICE_ENDPOINT_VAR": "LLM_SERVICE_ENDPOINT",\n "LLM_SERVICE_API_KEY_VAR": "LLM_SERVICE_API_KEY"\n }\n }\n ],\n "results_dir_name": "sam-local-eval-test",\n "runs": 3,\n "workers": 4,\n "test_cases": [\n "tests/evaluation/test_cases/filter_csv_employees_by_age_and_country.test.json",\n "tests/evaluation/test_cases/hello_world.test.json"\n ],\n "evaluation_settings": {\n "tool_match": {\n "enabled": true\n },\n "response_match": {\n "enabled": true\n },\n "llm_evaluator": {\n "enabled": true,\n "env": {\n "LLM_SERVICE_PLANNING_MODEL_NAME": "openai/gemini-2.5-pro",\n "LLM_SERVICE_ENDPOINT_VAR": "LLM_SERVICE_ENDPOINT",\n "LLM_SERVICE_API_KEY_VAR": "LLM_SERVICE_API_KEY"\n }\n }\n }\n}\n'})}),"\n",(0,a.jsx)(n.h3,{id:"remote-evaluation",children:"Remote Evaluation"}),"\n",(0,a.jsx)(n.p,{children:"In a remote evaluation, the evaluation framework sends requests to a remote Agent Mesh instance. This mode is useful for testing agents in a production-like environment where the agents are running on a separate server. The remote environment must have a REST gateway running to accept requests from the evaluation framework. You can also use an authentication token to communicate securely with the remote SAM instance."}),"\n",(0,a.jsx)(n.h4,{id:"remote-test-suite-configuration",children:"Remote Test Suite Configuration"}),"\n",(0,a.jsxs)(n.p,{children:["For a remote evaluation, you must define the ",(0,a.jsx)(n.code,{children:"broker"}),", ",(0,a.jsx)(n.code,{children:"remote"}),", and ",(0,a.jsx)(n.code,{children:"test_cases"})," fields."]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"broker"})," field is a required object with connection details for the Solace event broker."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"broker": {\n "SOLACE_BROKER_URL_VAR": "SOLACE_BROKER_URL",\n "SOLACE_BROKER_USERNAME_VAR": "SOLACE_BROKER_USERNAME",\n "SOLACE_BROKER_PASSWORD_VAR": "SOLACE_BROKER_PASSWORD",\n "SOLACE_BROKER_VPN_VAR": "SOLACE_BROKER_VPN"\n}\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"remote"})," field is a required object containing the connection details for the remote Agent Mesh instance."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"remote": {\n "EVAL_REMOTE_URL_VAR": "EVAL_REMOTE_URL",\n "EVAL_AUTH_TOKEN_VAR": "EVAL_AUTH_TOKEN",\n "EVAL_NAMESPACE_VAR": "EVAL_NAMESPACE"\n}\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"test_cases"})," field is a required list of paths to the test case ",(0,a.jsx)(n.code,{children:"JSON"})," files. You must specify at least one test case."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"test_cases": [ "tests/evaluation/test_cases/hello_world.test.json" ]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["You can also provide optional settings for ",(0,a.jsx)(n.code,{children:"results_dir_name"}),", ",(0,a.jsx)(n.code,{children:"runs"}),", and ",(0,a.jsx)(n.code,{children:"evaluation_settings"}),"."]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"results_dir_name"})," field is an optional string that specifies the name of the directory for evaluation results. It defaults to ",(0,a.jsx)(n.code,{children:"tests"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"results_dir_name": "my-remote-test-results"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"runs"})," field is an optional integer that specifies the number of times to run each test case. It defaults to ",(0,a.jsx)(n.code,{children:"1"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"runs": 5\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"evaluation_settings"})," field is an optional object that allows you to configure the evaluation."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'"evaluation_settings": {\n "tool_match": {\n "enabled": true\n },\n "response_match": {\n "enabled": true\n }\n}\n'})}),"\n",(0,a.jsx)(n.h4,{id:"example-remote-test-suite",children:"Example Remote Test Suite"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'{\n "broker": {\n "SOLACE_BROKER_URL_VAR": "SOLACE_BROKER_URL",\n "SOLACE_BROKER_USERNAME_VAR": "SOLACE_BROKER_USERNAME",\n "SOLACE_BROKER_PASSWORD_VAR": "SOLACE_BROKER_PASSWORD",\n "SOLACE_BROKER_VPN_VAR": "SOLACE_BROKER_VPN"\n },\n "remote": {\n "EVAL_REMOTE_URL_VAR": "EVAL_REMOTE_URL",\n "EVAL_AUTH_TOKEN_VAR": "EVAL_AUTH_TOKEN",\n "EVAL_NAMESPACE_VAR": "EVAL_NAMESPACE"\n },\n "results_dir_name": "sam-remote-eval-test",\n "runs": 1,\n "test_cases": [\n "tests/evaluation/test_cases/filter_csv_employees_by_age_and_country.test.json",\n "tests/evaluation/test_cases/hello_world.test.json"\n ],\n "evaluation_settings": {\n "tool_match": {\n "enabled": true\n },\n "response_match": {\n "enabled": true\n },\n "llm_evaluator": {\n "enabled": true,\n "env": {\n "LLM_SERVICE_PLANNING_MODEL_NAME": "openai/gemini-2.5-pro",\n "LLM_SERVICE_ENDPOINT_VAR": "LLM_SERVICE_ENDPOINT",\n "LLM_SERVICE_API_KEY_VAR": "LLM_SERVICE_API_KEY"\n }\n }\n }\n}\n'})}),"\n",(0,a.jsx)(n.h2,{id:"evaluation-settings",children:"Evaluation Settings"}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"evaluation_settings"})," block in the test suite ",(0,a.jsx)(n.code,{children:"JSON"})," file allows you to configure how the evaluation is performed. Each enabled setting provides a score from 0 to 1, which contributes to the overall score for the test case."]}),"\n",(0,a.jsx)(n.h3,{id:"tool_match",children:(0,a.jsx)(n.code,{children:"tool_match"})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"tool_match"})," setting compares the tools the agent used with the ",(0,a.jsx)(n.code,{children:"expected_tools"})," defined in the test case. This is a simple, direct comparison and does not use a language model for the evaluation. It is most effective when the agent's expected behavior is straightforward and there is a clear, correct sequence of tools to be used. In more complex scenarios where multiple paths could lead to a successful outcome, this method may not be the best way to evaluate the agent's performance."]}),"\n",(0,a.jsx)(n.h3,{id:"response_match",children:(0,a.jsx)(n.code,{children:"response_match"})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"response_match"})," setting compares the agent's final response with the ",(0,a.jsx)(n.code,{children:"expected_response"})," from the test case. This comparison is based on the ROUGE metric, which evaluates the similarity between two responses by comparing their sequence of words. This method does not use a language model for the evaluation and does not work well with synonyms, so it is most effective when the expected answer is consistent. For more information about the ROUGE metric, see the ",(0,a.jsx)(n.a,{href:"https://pypi.org/project/rouge-metric/",children:"official documentation"}),"."]}),"\n",(0,a.jsx)(n.h3,{id:"llm_evaluator",children:(0,a.jsx)(n.code,{children:"llm_evaluator"})}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"llm_evaluator"})," setting uses a language model to evaluate the entire lifecycle of a request within the agent mesh. This includes the initial prompt, all tool calls, delegation between agents, artifact inputs and outputs, and the final message output. The evaluation is based on a ",(0,a.jsx)(n.code,{children:"criterion"})," you provide in the test case, which defines what a successful outcome looks like. This is the most comprehensive evaluation method because it considers the full context of the request's execution."]}),"\n",(0,a.jsx)(n.h2,{id:"running-evaluations",children:"Running Evaluations"}),"\n",(0,a.jsxs)(n.p,{children:["After you create your test cases and test suite, you can run the evaluation from the command line using the ",(0,a.jsx)(n.code,{children:"sam eval"})," command."]}),"\n",(0,a.jsx)(n.h3,{id:"command",children:"Command"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:"sam eval <PATH> [OPTIONS]\n"})}),"\n",(0,a.jsxs)(n.p,{children:["The command takes the path to the evaluation test suite ",(0,a.jsx)(n.code,{children:"JSON"})," file as a required argument."]}),"\n",(0,a.jsx)(n.h3,{id:"options",children:"Options"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"-v"}),", ",(0,a.jsx)(n.code,{children:"--verbose"}),": Enable verbose output to see detailed logs during the evaluation run."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"-h"}),", ",(0,a.jsx)(n.code,{children:"--help"}),": Show a help message with information about the command and its options."]}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"example",children:"Example"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:"sam eval tests/evaluation/local_example.json --verbose\n"})}),"\n",(0,a.jsx)(n.h2,{id:"interpreting-the-results",children:"Interpreting the Results"}),"\n",(0,a.jsxs)(n.p,{children:["After an evaluation run is complete, the framework stores the results in a directory. The path to this directory is ",(0,a.jsx)(n.code,{children:"results/"})," followed by the ",(0,a.jsx)(n.code,{children:"results_dir_name"})," you specified in the test suite."]}),"\n",(0,a.jsx)(n.h3,{id:"results-directory",children:"Results Directory"}),"\n",(0,a.jsx)(n.p,{children:"The results directory has the following structure:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{children:"<results_dir_name>/\n\u251c\u2500\u2500 report.html\n\u251c\u2500\u2500 stats.json\n\u2514\u2500\u2500 <model_name>/\n \u251c\u2500\u2500 full_messages.json\n \u251c\u2500\u2500 results.json\n \u2514\u2500\u2500 <test_case_id>/\n \u2514\u2500\u2500 run_1/\n \u251c\u2500\u2500 messages.json\n \u251c\u2500\u2500 summary.json\n \u2514\u2500\u2500 test_case_info.json\n \u2514\u2500\u2500 run_2/\n \u251c\u2500\u2500 ...\n"})}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:(0,a.jsx)(n.code,{children:"report.html"})}),": An ",(0,a.jsx)(n.code,{children:"HTML"})," report that provides a comprehensive overview of the evaluation results. It includes a summary of the test runs, a breakdown of the results for each test case, and detailed logs for each test run. This report is the primary tool for analyzing the results of an evaluation."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:(0,a.jsx)(n.code,{children:"stats.json"})}),": A ",(0,a.jsx)(n.code,{children:"JSON"})," file containing detailed statistics about the evaluation run, including scores for each evaluation metric."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:(0,a.jsx)(n.code,{children:"<model_name>/"})}),": A directory for each language model tested (or a single ",(0,a.jsx)(n.code,{children:"remote"})," directory for remote evaluations).","\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:(0,a.jsx)(n.code,{children:"full_messages.json"})}),": A log of all messages exchanged during the evaluation for that model."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:(0,a.jsx)(n.code,{children:"results.json"})}),": The raw evaluation results for each test case."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.strong,{children:(0,a.jsx)(n.code,{children:"<test_case_id>/"})}),": A directory for each test case, containing a ",(0,a.jsx)(n.code,{children:"run_n"})," subdirectory for each run of the test case. These directories contain detailed logs and artifacts for each run."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"html-report",children:"HTML Report"}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"report.html"})," file provides a comprehensive overview of the evaluation results. It includes a summary of the test runs, a breakdown of the results for each test case, and detailed logs for each test run. This report is the primary tool for analyzing the results of an evaluation. You can open this file in a web browser to view the report."]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>i,x:()=>l});var s=t(6540);const a={},o=s.createContext(a);function i(e){const n=s.useContext(o);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[582],{4415:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>_,frontMatter:()=>r,metadata:()=>a,toc:()=>c});const a=JSON.parse('{"id":"documentation/developing/create-gateways","title":"Create Gateways","description":"Gateways in Agent Mesh serve as bridges between external systems and the A2A (Agent-to-Agent) ecosystem. They enable your agents to receive information from and send responses to diverse external platforms like chat systems, web applications, IoT devices, APIs, and file systems.","source":"@site/docs/documentation/developing/create-gateways.md","sourceDirName":"documentation/developing","slug":"/documentation/developing/create-gateways","permalink":"/solace-agent-mesh/docs/documentation/developing/create-gateways","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/developing/create-gateways.md","tags":[],"version":"current","sidebarPosition":430,"frontMatter":{"title":"Create Gateways","sidebar_position":430},"sidebar":"docSidebar","previous":{"title":"Creating Agents","permalink":"/solace-agent-mesh/docs/documentation/developing/create-agents"},"next":{"title":"Creating Python Tools","permalink":"/solace-agent-mesh/docs/documentation/developing/creating-python-tools"}}');var i=t(4848),s=t(8453);const r={title:"Create Gateways",sidebar_position:430},o="Create Gateways",l={},c=[{value:"What Are Gateways?",id:"what-are-gateways",level:2},{value:"Quick Start: Creating Your First Gateway",id:"quick-start-creating-your-first-gateway",level:2},{value:"CLI Options",id:"cli-options",level:3},{value:"Gateway Architecture",id:"gateway-architecture",level:2},{value:"Gateway App",id:"gateway-app",level:3},{value:"Gateway Component",id:"gateway-component",level:3},{value:"Step-by-Step Tutorial",id:"step-by-step-tutorial",level:2},{value:"Step 1: Generate the Gateway Structure",id:"step-1-generate-the-gateway-structure",level:3},{value:"Step 2: Define Configuration Schema",id:"step-2-define-configuration-schema",level:3},{value:"Step 3: Implement Core Logic",id:"step-3-implement-core-logic",level:3},{value:"Step 4: Configure the Gateway",id:"step-4-configure-the-gateway",level:3},{value:"Step 5: Install Dependencies",id:"step-5-install-dependencies",level:3},{value:"Step 6: Run Your Gateway",id:"step-6-run-your-gateway",level:3},{value:"Advanced Gateway Patterns",id:"advanced-gateway-patterns",level:2},{value:"Authentication and Authorization",id:"authentication-and-authorization",level:3},{value:"File Handling with Artifacts",id:"file-handling-with-artifacts",level:3},{value:"Streaming Responses",id:"streaming-responses",level:3},{value:"Error Handling and Retry Logic",id:"error-handling-and-retry-logic",level:3},{value:"Best Practices",id:"best-practices",level:2},{value:"1. Configuration Management",id:"1-configuration-management",level:3},{value:"2. Error Handling",id:"2-error-handling",level:3},{value:"3. Security",id:"3-security",level:3},{value:"4. Performance",id:"4-performance",level:3},{value:"5. Monitoring and Logging",id:"5-monitoring-and-logging",level:3},{value:"Common Gateway Patterns",id:"common-gateway-patterns",level:2},{value:"HTTP/REST API Gateway",id:"httprest-api-gateway",level:3},{value:"WebSocket Gateway",id:"websocket-gateway",level:3},{value:"Message Queue Gateway",id:"message-queue-gateway",level:3},{value:"Packaging as a Plugin",id:"packaging-as-a-plugin",level:2},{value:"1. Create Plugin Structure",id:"1-create-plugin-structure",level:3},{value:"2. Configure <code>pyproject.toml</code>",id:"2-configure-pyprojecttoml",level:3},{value:"3. Build and Install",id:"3-build-and-install",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2},{value:"Common Issues",id:"common-issues",level:3},{value:"Gateway Fails to Start",id:"gateway-fails-to-start",level:4},{value:"Tasks Not Reaching Agents",id:"tasks-not-reaching-agents",level:4},{value:"Authentication Failures",id:"authentication-failures",level:4},{value:"File/Artifact Issues",id:"fileartifact-issues",level:4},{value:"Debugging Tips",id:"debugging-tips",level:3}];function d(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"create-gateways",children:"Create Gateways"})}),"\n",(0,i.jsx)(n.p,{children:"Gateways in Agent Mesh serve as bridges between external systems and the A2A (Agent-to-Agent) ecosystem. They enable your agents to receive information from and send responses to diverse external platforms like chat systems, web applications, IoT devices, APIs, and file systems."}),"\n",(0,i.jsx)(n.p,{children:"This guide walks you through the steps of creating custom gateways, from basic concepts to advanced implementations."}),"\n",(0,i.jsx)(n.h2,{id:"what-are-gateways",children:"What Are Gateways?"}),"\n",(0,i.jsx)(n.p,{children:"A gateway acts as a translator and coordinator that:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Receives"})," events, messages, or data from external systems"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Authenticates"})," and authorizes external interactions"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Translates"})," external data into standardized A2A ",(0,i.jsx)(n.code,{children:"Task"})," format"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Submits"})," tasks to target A2A agents for processing"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Receives"})," responses and status updates from agents"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Translates"})," A2A responses back to external system format"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Sends"})," results back to the originating external system"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"quick-start-creating-your-first-gateway",children:"Quick Start: Creating Your First Gateway"}),"\n",(0,i.jsxs)(n.p,{children:["You can create a gateway directly using the Agent Mesh CLI ",(0,i.jsx)(n.code,{children:"sam add gateway"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam add gateway my-custom-gateway\n"})}),"\n",(0,i.jsx)(n.p,{children:"This command:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Launches an interactive setup (or use ",(0,i.jsx)(n.code,{children:"--gui"})," for browser-based configuration)"]}),"\n",(0,i.jsx)(n.li,{children:"Generates the necessary files and configuration"}),"\n",(0,i.jsx)(n.li,{children:"Sets up the basic gateway structure"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"cli-options",children:"CLI Options"}),"\n",(0,i.jsx)(n.p,{children:"You can customize the gateway creation with these options:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'sam add gateway my-gateway \\\n --namespace "myorg/dev" \\\n --gateway-id "my-custom-gw-id" \\\n --artifact-service-type "filesystem" \\\n --artifact-service-base-path "var/data/my-gateway-artifacts" \\\n --system-purpose "This gateway processes external data feeds" \\\n --response-format "Agents should respond with structured JSON"\n'})}),"\n",(0,i.jsx)(n.p,{children:"For a complete list of options, run:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam add gateway --help\n"})}),"\n",(0,i.jsx)(n.h2,{id:"gateway-architecture",children:"Gateway Architecture"}),"\n",(0,i.jsx)(n.p,{children:"Every Agent Mesh gateway consists of two main components:"}),"\n",(0,i.jsx)(n.h3,{id:"gateway-app",children:"Gateway App"}),"\n",(0,i.jsxs)(n.p,{children:["Gateway App (",(0,i.jsx)(n.code,{children:"app.py"}),"):"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Defines configuration schema"}),"\n",(0,i.jsx)(n.li,{children:"Manages gateway-level settings"}),"\n",(0,i.jsx)(n.li,{children:"Links to the gateway component"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"gateway-component",children:"Gateway Component"}),"\n",(0,i.jsxs)(n.p,{children:["Gateway Component (",(0,i.jsx)(n.code,{children:"component.py"}),"):"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Contains the core business logic"}),"\n",(0,i.jsx)(n.li,{children:"Handles external system integration"}),"\n",(0,i.jsx)(n.li,{children:"Implements required abstract methods"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"step-by-step-tutorial",children:"Step-by-Step Tutorial"}),"\n",(0,i.jsxs)(n.p,{children:["Let's create a practical example, ",(0,i.jsx)(n.strong,{children:"Directory Monitor Gateway"}),", a gateway that monitors a directory for new files and sends them to agents for processing."]}),"\n",(0,i.jsxs)(n.p,{children:["You can create a gateway using either ",(0,i.jsx)(n.code,{children:"sam add gateway <your_gateway_name>"})," command directly or ",(0,i.jsx)(n.code,{children:"sam plugin create <your_gateway_plugin_name> --type gateway"})," command as gateway plugin."]}),"\n",(0,i.jsxs)(n.admonition,{title:"Gateway as plugin",type:"tip",children:[(0,i.jsx)(n.p,{children:"Gateways can also be implemented as plugins. This allows you to easily package your gateway logic and reuse it across different projects."}),(0,i.jsxs)(n.p,{children:["To create a plugin of type gateway, use the ",(0,i.jsx)(n.code,{children:"sam plugin create <your_gateway_plugin_name> --type gateway"})," command."]}),(0,i.jsx)(n.p,{children:"For a complete list of options, run:"}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam plugin create --help\n"})}),(0,i.jsxs)(n.p,{children:["To create a gateway instance based on a plugin, use the ",(0,i.jsx)(n.code,{children:"sam plugin add <your_gateway_name> --plugin <your_gateway_plugin>"})," command."]}),(0,i.jsx)(n.p,{children:"For a complete list of options, run:"}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam plugin add --help\n"})}),(0,i.jsx)(n.p,{children:"Although the specific directory structure may differ from standalone gateways, the core concepts remain the same. The core files remain the same: app.py, component.py, and the YAML configuration file."})]}),"\n",(0,i.jsx)(n.h3,{id:"step-1-generate-the-gateway-structure",children:"Step 1: Generate the Gateway Structure"}),"\n",(0,i.jsxs)(n.p,{children:["This tutorial shows you how to create a new gateway with the ",(0,i.jsx)(n.code,{children:"sam add gateway"})," command."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam add gateway dir-monitor\n"})}),"\n",(0,i.jsx)(n.p,{children:"This creates:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"configs/gateways/dir_monitor_config.yaml"})," - Configuration file"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"src/dir_monitor/app.py"})," - Gateway app class"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"src/dir_monitor/component.py"})," - Gateway component class"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"step-2-define-configuration-schema",children:"Step 2: Define Configuration Schema"}),"\n",(0,i.jsxs)(n.p,{children:["Define Configuration Schema (",(0,i.jsx)(n.code,{children:"app.py"}),")"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'# src/dir_monitor/app.py\nfrom typing import Any, Dict, List, Type\nfrom solace_ai_connector.common.log import log\nfrom solace_agent_mesh.gateway.base.app import BaseGatewayApp\nfrom solace_agent_mesh.gateway.base.component import BaseGatewayComponent\nfrom .component import DirMonitorGatewayComponent\n\n# Module info required by SAC\ninfo = {\n "class_name": "DirMonitorGatewayApp",\n "description": "Custom App class for the A2A DirMonitor Gateway.",\n}\n\nclass DirMonitorGatewayApp(BaseGatewayApp):\n """\n Directory Monitor Gateway App\n Extends BaseGatewayApp with directory monitoring specific configuration.\n """\n\n # Define gateway-specific configuration parameters\n SPECIFIC_APP_SCHEMA_PARAMS: List[Dict[str, Any]] = [\n {\n "name": "directory_path",\n "required": True,\n "type": "string",\n "description": "The directory path to monitor for changes.",\n },\n {\n "name": "target_agent_name",\n "required": False,\n "type": "string",\n "default": "OrchestratorAgent",\n "description": "The A2A agent to send tasks to.",\n },\n {\n "name": "default_user_identity",\n "required": False,\n "type": "string",\n "default": "dir_monitor_user",\n "description": "Default user identity for A2A tasks.",\n },\n {\n "name": "error_directory_path",\n "required": True,\n "type": "string",\n "description": "Directory to move files if processing fails.",\n },\n ]\n\n def __init__(self, app_info: Dict[str, Any], **kwargs):\n log_prefix = app_info.get("name", "DirMonitorGatewayApp")\n log.info("[%s] Initializing Directory Monitor Gateway App...", log_prefix)\n super().__init__(app_info=app_info, **kwargs)\n log.info("[%s] Directory Monitor Gateway App initialized.", self.name)\n\n def _get_gateway_component_class(self) -> Type[BaseGatewayComponent]:\n """Returns the gateway component class for this app."""\n return DirMonitorGatewayComponent\n'})}),"\n",(0,i.jsx)(n.h3,{id:"step-3-implement-core-logic",children:"Step 3: Implement Core Logic"}),"\n",(0,i.jsxs)(n.p,{children:["Implement Core Logic (",(0,i.jsx)(n.code,{children:"component.py"}),")"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'# src/dir_monitor/component.py\nimport asyncio\nimport os\nimport shutil\nimport mimetypes\nimport threading\nfrom typing import Any, Dict, List, Optional, Tuple, Union\nfrom datetime import datetime, timezone\n\nfrom solace_ai_connector.common.log import log\n\n# Import watchdog for file system monitoring\ntry:\n from watchdog.observers import Observer\n from watchdog.events import FileSystemEventHandler\n WATCHDOG_AVAILABLE = True\nexcept ImportError:\n WATCHDOG_AVAILABLE = False\n Observer = None\n FileSystemEventHandler = None\n\nfrom solace_agent_mesh.gateway.base.component import BaseGatewayComponent\nfrom solace_agent_mesh.common.types import (\n Part as A2APart,\n TextPart,\n FilePart,\n Task,\n TaskStatusUpdateEvent,\n TaskArtifactUpdateEvent,\n JSONRPCError,\n FileContent,\n)\nfrom solace_agent_mesh.agent.utils.artifact_helpers import save_artifact_with_metadata\n\n# Component info\ninfo = {\n "class_name": "DirMonitorGatewayComponent",\n "description": "Monitors directories for new files and processes them via A2A agents.",\n}\n\nclass DirMonitorGatewayComponent(BaseGatewayComponent):\n """\n Directory Monitor Gateway Component\n Watches a directory and creates A2A tasks for new files.\n """\n\n def __init__(self, **kwargs: Any):\n super().__init__(**kwargs)\n log.info("%s Initializing Directory Monitor Gateway Component...", self.log_identifier)\n\n # Check if watchdog is available\n if not WATCHDOG_AVAILABLE:\n log.error("%s Watchdog library not found. Install with: pip install watchdog", \n self.log_identifier)\n raise ImportError("Watchdog library required for directory monitoring")\n\n # Load configuration\n try:\n self.directory_path = self.get_config("directory_path")\n self.target_agent_name = self.get_config("target_agent_name", "OrchestratorAgent")\n self.default_user_identity_id = self.get_config("default_user_identity", "dir_monitor_user")\n self.error_directory_path = self.get_config("error_directory_path")\n\n # Validate directories\n if not os.path.isdir(self.directory_path):\n raise ValueError(f"Monitor directory not found: {self.directory_path}")\n \n os.makedirs(self.error_directory_path, exist_ok=True)\n log.info("%s Monitoring: %s, Error dir: %s", \n self.log_identifier, self.directory_path, self.error_directory_path)\n\n except Exception as e:\n log.error("%s Configuration error: %s", self.log_identifier, e)\n raise\n\n # Initialize monitoring components\n self.observer: Optional[Observer] = None\n self.watchdog_thread: Optional[threading.Thread] = None\n\n log.info("%s Directory Monitor Gateway Component initialized.", self.log_identifier)\n\n class DirWatchEventHandler(FileSystemEventHandler):\n """Handles file system events from Watchdog."""\n \n def __init__(self, component_ref: \'DirMonitorGatewayComponent\'):\n super().__init__()\n self.component_ref = component_ref\n self.log_identifier = f"{component_ref.log_identifier}[FileHandler]"\n\n def on_created(self, event):\n if event.is_directory:\n return\n\n file_path = event.src_path\n log.info("%s New file detected: %s", self.log_identifier, file_path)\n\n # Bridge to async loop\n if self.component_ref.async_loop and self.component_ref.async_loop.is_running():\n asyncio.run_coroutine_threadsafe(\n self.component_ref._process_new_file(file_path),\n self.component_ref.async_loop\n )\n else:\n log.error("%s Async loop not available for file: %s", \n self.log_identifier, file_path)\n\n def generate_uuid(self) -> str:\n """Generate a unique identifier."""\n import uuid\n return str(uuid.uuid4())\n\n def _start_listener(self) -> None:\n """Start the directory monitoring listener."""\n log_id_prefix = f"{self.log_identifier}[StartListener]"\n log.info("%s Starting directory monitor for: %s", log_id_prefix, self.directory_path)\n\n if not WATCHDOG_AVAILABLE:\n log.error("%s Watchdog not available", log_id_prefix)\n self.stop_signal.set()\n return\n\n # Set up file system observer\n self.observer = Observer()\n event_handler = self.DirWatchEventHandler(self)\n self.observer.schedule(event_handler, self.directory_path, recursive=False)\n\n # Start observer in separate thread\n self.watchdog_thread = threading.Thread(\n target=self._run_observer,\n name=f"{self.name}_WatchdogThread",\n daemon=True\n )\n self.watchdog_thread.start()\n log.info("%s Directory monitor started", log_id_prefix)\n\n def _run_observer(self):\n """Run the watchdog observer."""\n if not self.observer:\n return\n \n log_id_prefix = f"{self.log_identifier}[Observer]"\n try:\n log.info("%s Starting file system observer...", log_id_prefix)\n self.observer.start()\n \n # Wait for stop signal\n while not self.stop_signal.is_set() and self.observer.is_alive():\n self.stop_signal.wait(timeout=1)\n \n log.info("%s Observer loop exiting", log_id_prefix)\n except Exception as e:\n log.exception("%s Observer error: %s", log_id_prefix, e)\n self.stop_signal.set()\n finally:\n if self.observer.is_alive():\n self.observer.stop()\n self.observer.join()\n log.info("%s Observer stopped", log_id_prefix)\n\n def _stop_listener(self) -> None:\n """Stop the directory monitoring listener."""\n log_id_prefix = f"{self.log_identifier}[StopListener]"\n log.info("%s Stopping directory monitor...", log_id_prefix)\n \n if self.observer and self.observer.is_alive():\n log.info("%s Stopping observer...", log_id_prefix)\n self.observer.stop()\n \n if self.watchdog_thread and self.watchdog_thread.is_alive():\n log.info("%s Joining observer thread...", log_id_prefix)\n self.watchdog_thread.join(timeout=5)\n if self.watchdog_thread.is_alive():\n log.warning("%s Observer thread did not join cleanly", log_id_prefix)\n \n log.info("%s Directory monitor stopped", log_id_prefix)\n\n async def _process_new_file(self, file_path: str):\n """Process a newly detected file."""\n log_id_prefix = f"{self.log_identifier}[ProcessFile:{os.path.basename(file_path)}]"\n log.info("%s Processing new file: %s", log_id_prefix, file_path)\n \n error_context = {\n "file_path": file_path,\n "a2a_session_id": f"dir_monitor-error-{self.generate_uuid()}"\n }\n\n try:\n # Step 1: Authenticate and enrich user\n user_identity_profile = await self.authenticate_and_enrich_user(file_path)\n if not user_identity_profile:\n log.error("%s Authentication failed for file: %s", log_id_prefix, file_path)\n error_obj = JSONRPCError(code=-32001, message="Authentication failed")\n await self._send_error_to_external(error_context, error_obj)\n return\n\n # Step 2: Translate external input to A2A format\n target_agent_name, a2a_parts, external_request_context = await self._translate_external_input(\n file_path, user_identity_profile\n )\n\n if not target_agent_name or not a2a_parts:\n log.error("%s Failed to translate file to A2A task: %s", log_id_prefix, file_path)\n error_obj = JSONRPCError(code=-32002, message="Failed to translate file to A2A task")\n final_error_context = {**error_context, **external_request_context}\n await self._send_error_to_external(final_error_context, error_obj)\n return\n\n # Step 3: Submit A2A task\n log.info("%s Submitting A2A task for file: %s to agent: %s", \n log_id_prefix, file_path, target_agent_name)\n await self.submit_a2a_task(\n target_agent_name=target_agent_name,\n a2a_parts=a2a_parts,\n external_request_context=external_request_context,\n user_identity=user_identity_profile\n )\n log.info("%s A2A task submitted for file: %s", log_id_prefix, file_path)\n\n except FileNotFoundError:\n log.error("%s File not found during processing: %s", log_id_prefix, file_path)\n except Exception as e:\n log.exception("%s Unexpected error processing file %s: %s", log_id_prefix, file_path, e)\n error_obj = JSONRPCError(code=-32000, message=f"Unexpected error: {e}")\n await self._send_error_to_external(error_context, error_obj)\n\n async def _extract_initial_claims(self, external_event_data: Any) -> Optional[Dict[str, Any]]:\n """Extract user identity claims from file event."""\n file_path = str(external_event_data)\n log_id_prefix = f"{self.log_identifier}[ExtractClaims:{os.path.basename(file_path)}]"\n \n claims = {\n "id": self.default_user_identity_id,\n "source": "dir_monitor",\n "file_path": file_path\n }\n log.debug("%s Extracted claims for file %s: %s", log_id_prefix, file_path, claims)\n return claims\n\n async def _translate_external_input(\n self, external_event_data: Any, authenticated_user_identity: Dict[str, Any]\n ) -> Tuple[Optional[str], List[A2APart], Dict[str, Any]]:\n """Translate file event to A2A task format."""\n file_path = str(external_event_data)\n log_id_prefix = f"{self.log_identifier}[TranslateInput:{os.path.basename(file_path)}]"\n\n user_id_for_a2a = authenticated_user_identity.get("id", self.default_user_identity_id)\n a2a_session_id = f"dir_monitor-session-{self.generate_uuid()}"\n \n # Prepare external request context\n external_request_context: Dict[str, Any] = {\n "file_path": file_path,\n "user_id_for_a2a": user_id_for_a2a,\n "app_name_for_artifacts": self.gateway_id,\n "user_id_for_artifacts": user_id_for_a2a,\n "a2a_session_id": a2a_session_id,\n }\n a2a_parts: List[A2APart] = []\n\n try:\n # Check if file exists\n if not os.path.exists(file_path):\n log.error("%s File does not exist: %s", log_id_prefix, file_path)\n raise FileNotFoundError(f"File not found: {file_path}")\n\n # Read file content\n with open(file_path, "rb") as f:\n content_bytes = f.read()\n \n # Determine MIME type\n mime_type, _ = mimetypes.guess_type(file_path)\n if mime_type is None:\n mime_type = "application/octet-stream"\n\n # Save file as artifact\n if not self.shared_artifact_service:\n log.error("%s Artifact service not available for file: %s", \n log_id_prefix, os.path.basename(file_path))\n return None, [], external_request_context\n\n artifact_metadata = {\n "source": "dir_monitor_gateway",\n "original_filename": os.path.basename(file_path),\n "detected_mime_type": mime_type,\n "processing_timestamp_utc": datetime.now(timezone.utc).isoformat(),\n }\n\n log.debug("%s Saving artifact for file: %s", log_id_prefix, file_path)\n save_result = await save_artifact_with_metadata(\n artifact_service=self.shared_artifact_service,\n app_name=self.gateway_id,\n user_id=str(user_id_for_a2a),\n session_id=a2a_session_id,\n filename=os.path.basename(file_path),\n content_bytes=content_bytes,\n mime_type=mime_type,\n metadata_dict=artifact_metadata,\n timestamp=datetime.now(timezone.utc),\n )\n\n if save_result["status"] not in ["success", "partial_success"]:\n log.error("%s Failed to save file as artifact: %s", \n log_id_prefix, save_result.get("message"))\n return None, [], external_request_context\n\n # Create artifact URI\n data_version = save_result.get("data_version", 0)\n artifact_uri = f"artifact://{self.gateway_id}/{str(user_id_for_a2a)}/{a2a_session_id}/{os.path.basename(file_path)}?version={data_version}"\n \n log.info("%s Saved file as artifact: %s", log_id_prefix, artifact_uri)\n\n # Create A2A parts\n file_content_obj = FileContent(\n name=os.path.basename(file_path),\n uri=artifact_uri,\n mimeType=mime_type\n )\n a2a_parts.append(FilePart(file=file_content_obj))\n a2a_parts.append(TextPart(\n text=f"Please analyze and summarize the content of: {os.path.basename(file_path)}"\n ))\n\n log.info("%s Successfully translated file %s into A2A parts", log_id_prefix, file_path)\n return self.target_agent_name, a2a_parts, external_request_context\n\n except Exception as e:\n log.exception("%s Error translating file %s: %s", log_id_prefix, file_path, e)\n return None, [], external_request_context\n\n async def _send_final_response_to_external(\n self, external_request_context: Dict[str, Any], task_data: Task\n ) -> None:\n """Handle final response from A2A agent."""\n log_id_prefix = f"{self.log_identifier}[SendFinalResponse]"\n file_path = external_request_context.get("file_path", "Unknown file")\n task_id = task_data.id\n\n # Extract summary from response\n summary_text = "Summary not available."\n if task_data.status and task_data.status.message and task_data.status.message.parts:\n for part in task_data.status.message.parts:\n if isinstance(part, TextPart):\n summary_text = part.text\n break\n \n log.info("%s Task %s completed for file \'%s\'. Status: %s", \n log_id_prefix, task_id, os.path.basename(file_path), \n task_data.status.state if task_data.status else "Unknown")\n log.info("%s Summary: %s", log_id_prefix, summary_text[:200] + "..." if len(summary_text) > 200 else summary_text)\n\n async def _send_error_to_external(\n self, external_request_context: Dict[str, Any], error_data: JSONRPCError\n ) -> None:\n """Handle errors by moving files to error directory."""\n log_id_prefix = f"{self.log_identifier}[SendError]"\n file_path = external_request_context.get("file_path")\n \n log.error("%s A2A Error for file \'%s\'. Code: %s, Message: %s",\n log_id_prefix, \n os.path.basename(file_path) if file_path else "Unknown file",\n error_data.code, error_data.message)\n\n # Move problematic file to error directory\n if file_path and os.path.exists(file_path):\n try:\n os.makedirs(self.error_directory_path, exist_ok=True)\n base_name = os.path.basename(file_path)\n error_file_path = os.path.join(self.error_directory_path, base_name)\n \n # Handle filename conflicts\n counter = 0\n while os.path.exists(error_file_path):\n counter += 1\n name, ext = os.path.splitext(base_name)\n error_file_path = os.path.join(self.error_directory_path, f"{name}_error_{counter}{ext}")\n\n shutil.move(file_path, error_file_path)\n log.info("%s Moved problematic file %s to %s", log_id_prefix, file_path, error_file_path)\n except Exception as e:\n log.exception("%s Failed to move file %s to error directory: %s",\n log_id_prefix, file_path, e)\n\n async def _send_update_to_external(\n self,\n external_request_context: Dict[str, Any],\n event_data: Union[TaskStatusUpdateEvent, TaskArtifactUpdateEvent],\n is_final_chunk_of_update: bool,\n ) -> None:\n """Handle intermediate updates (optional for this gateway)."""\n log_id_prefix = f"{self.log_identifier}[SendUpdate]"\n task_id = event_data.id\n file_path = external_request_context.get("file_path", "Unknown file")\n \n log.debug("%s Received update for task %s (file %s). Updates not processed by this gateway.",\n log_id_prefix, task_id, os.path.basename(file_path))\n\n def cleanup(self):\n """Clean up resources."""\n log.info("%s Cleaning up Directory Monitor Gateway Component...", self.log_identifier)\n super().cleanup()\n log.info("%s Directory Monitor Gateway Component cleanup finished.", self.log_identifier)\n'})}),"\n",(0,i.jsx)(n.h3,{id:"step-4-configure-the-gateway",children:"Step 4: Configure the Gateway"}),"\n",(0,i.jsxs)(n.p,{children:["Configure the Gateway (",(0,i.jsx)(n.code,{children:"dir_monitor_config.yaml"}),")"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'# configs/gateways/dir_monitor_config.yaml\nlog:\n stdout_log_level: INFO\n log_file_level: DEBUG\n log_file: "dir_monitor_gateway.log"\n\n!include ../shared_config.yaml\n\napps:\n - name: dir_monitor_gateway_app\n app_base_path: .\n app_module: src.dir_monitor.app\n\n broker:\n <<: *broker_connection\n\n app_config:\n namespace: ${NAMESPACE}\n gateway_id: dir-monitor-gateway\n \n # Artifact service configuration\n artifact_service: *default_artifact_service\n\n # System purpose for A2A context\n system_purpose: >\n This system monitors directories for new files and processes them automatically.\n Analyze and summarize file contents. Always provide useful insights about the files.\n Your external name is Directory Monitor Agent.\n\n response_format: >\n Responses should be clear, concise, and professionally formatted.\n Provide structured analysis of file contents in Markdown format.\n\n # Gateway-specific configuration\n directory_path: /path/to/monitor/directory\n error_directory_path: /path/to/error/directory\n target_agent_name: "OrchestratorAgent"\n default_user_identity: "dir_monitor_system"\n'})}),"\n",(0,i.jsx)(n.h3,{id:"step-5-install-dependencies",children:"Step 5: Install Dependencies"}),"\n",(0,i.jsx)(n.p,{children:"Add required dependencies to your project:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"pip install watchdog\n"})}),"\n",(0,i.jsx)(n.h3,{id:"step-6-run-your-gateway",children:"Step 6: Run Your Gateway"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam run configs/gateways/dir_monitor_config.yaml\n"})}),"\n",(0,i.jsx)(n.h2,{id:"advanced-gateway-patterns",children:"Advanced Gateway Patterns"}),"\n",(0,i.jsx)(n.h3,{id:"authentication-and-authorization",children:"Authentication and Authorization"}),"\n",(0,i.jsx)(n.p,{children:"Gateways can implement sophisticated authentication:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'async def _extract_initial_claims(self, external_event_data: Any) -> Optional[Dict[str, Any]]:\n """Extract user claims with API key validation."""\n request = external_event_data.get("request")\n \n # Validate API key\n api_key = request.headers.get("X-API-Key")\n if not api_key or not self._validate_api_key(api_key):\n return None\n \n # Extract user information\n user_id = request.headers.get("X-User-ID", "anonymous")\n \n return {\n "id": user_id,\n "source": "api_gateway",\n "api_key_hash": hashlib.sha256(api_key.encode()).hexdigest()[:8],\n "roles": self._get_user_roles(user_id)\n }\n'})}),"\n",(0,i.jsx)(n.h3,{id:"file-handling-with-artifacts",children:"File Handling with Artifacts"}),"\n",(0,i.jsx)(n.p,{children:"For gateways that handle files:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'async def _save_file_as_artifact(self, file_content: bytes, filename: str, \n mime_type: str, session_id: str) -> Optional[str]:\n """Save file content as artifact and return URI."""\n if not self.shared_artifact_service:\n return None\n \n try:\n save_result = await save_artifact_with_metadata(\n artifact_service=self.shared_artifact_service,\n app_name=self.gateway_id,\n user_id="system",\n session_id=session_id,\n filename=filename,\n content_bytes=file_content,\n mime_type=mime_type,\n metadata_dict={\n "source": "my_gateway",\n "upload_timestamp": datetime.now(timezone.utc).isoformat()\n },\n timestamp=datetime.now(timezone.utc)\n )\n \n if save_result["status"] in ["success", "partial_success"]:\n version = save_result.get("data_version", 0)\n return f"artifact://{self.gateway_id}/system/{session_id}/{filename}?version={version}"\n \n except Exception as e:\n log.error("Failed to save artifact: %s", e)\n \n return None\n'})}),"\n",(0,i.jsx)(n.h3,{id:"streaming-responses",children:"Streaming Responses"}),"\n",(0,i.jsx)(n.p,{children:"Handle streaming responses from agents:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'async def _send_update_to_external(\n self, external_request_context: Dict[str, Any],\n event_data: Union[TaskStatusUpdateEvent, TaskArtifactUpdateEvent],\n is_final_chunk_of_update: bool\n) -> None:\n """Send streaming updates to external system."""\n if isinstance(event_data, TaskStatusUpdateEvent):\n if event_data.status and event_data.status.message:\n for part in event_data.status.message.parts:\n if isinstance(part, TextPart):\n # Send partial text to external system\n await self._send_partial_response(\n external_request_context,\n part.text,\n is_final=is_final_chunk_of_update\n )\n'})}),"\n",(0,i.jsx)(n.h3,{id:"error-handling-and-retry-logic",children:"Error Handling and Retry Logic"}),"\n",(0,i.jsx)(n.p,{children:"Implement robust error handling:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'async def _process_with_retry(self, data: Any, max_retries: int = 3):\n """Process data with retry logic."""\n for attempt in range(max_retries):\n try:\n return await self._process_data(data)\n except TemporaryError as e:\n if attempt < max_retries - 1:\n wait_time = 2 ** attempt # Exponential backoff\n log.warning("Attempt %d failed, retrying in %ds: %s", \n attempt + 1, wait_time, e)\n await asyncio.sleep(wait_time)\n else:\n raise\n except PermanentError:\n # Don\'t retry permanent errors\n raise\n'})}),"\n",(0,i.jsx)(n.h2,{id:"best-practices",children:"Best Practices"}),"\n",(0,i.jsx)(n.h3,{id:"1-configuration-management",children:"1. Configuration Management"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Use environment variables for sensitive data"}),"\n",(0,i.jsx)(n.li,{children:"Provide sensible defaults"}),"\n",(0,i.jsx)(n.li,{children:"Validate configuration at startup"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"2-error-handling",children:"2. Error Handling"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Implement comprehensive error handling"}),"\n",(0,i.jsx)(n.li,{children:"Use appropriate HTTP status codes"}),"\n",(0,i.jsx)(n.li,{children:"Log errors with sufficient context"}),"\n",(0,i.jsx)(n.li,{children:"Provide meaningful error messages"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"3-security",children:"3. Security"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Validate all external inputs"}),"\n",(0,i.jsx)(n.li,{children:"Use secure authentication methods"}),"\n",(0,i.jsx)(n.li,{children:"Implement rate limiting where appropriate"}),"\n",(0,i.jsx)(n.li,{children:"Store secrets securely (use environment variables)"}),"\n",(0,i.jsx)(n.li,{children:"Follow principle of least privilege"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"4-performance",children:"4. Performance"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Use async/await for I/O operations"}),"\n",(0,i.jsx)(n.li,{children:"Implement connection pooling for external APIs"}),"\n",(0,i.jsx)(n.li,{children:"Monitor resource usage"}),"\n",(0,i.jsx)(n.li,{children:"Handle backpressure appropriately"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"5-monitoring-and-logging",children:"5. Monitoring and Logging"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Use structured logging"}),"\n",(0,i.jsx)(n.li,{children:"Include correlation IDs"}),"\n",(0,i.jsx)(n.li,{children:"Monitor key metrics (latency, error rates, throughput)"}),"\n",(0,i.jsx)(n.li,{children:"Set up health checks"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"common-gateway-patterns",children:"Common Gateway Patterns"}),"\n",(0,i.jsx)(n.h3,{id:"httprest-api-gateway",children:"HTTP/REST API Gateway"}),"\n",(0,i.jsx)(n.p,{children:"For HTTP-based integrations:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'from fastapi import FastAPI, HTTPException, Depends\nfrom fastapi.security import HTTPBearer\n\nclass HTTPAPIGatewayComponent(BaseGatewayComponent):\n def __init__(self, **kwargs):\n super().__init__(**kwargs)\n self.app = FastAPI()\n self.security = HTTPBearer()\n self._setup_routes()\n \n def _setup_routes(self):\n @self.app.post("/webhook/{endpoint_id}")\n async def webhook_handler(endpoint_id: str, request: Request,\n token: str = Depends(self.security)):\n # Authenticate request\n user_identity = await self.authenticate_and_enrich_user({\n "token": token,\n "endpoint_id": endpoint_id,\n "request": request\n })\n \n if not user_identity:\n raise HTTPException(status_code=401, detail="Unauthorized")\n \n # Process webhook\n body = await request.json()\n target_agent, parts, context = await self._translate_external_input(\n body, user_identity\n )\n \n task_id = await self.submit_a2a_task(\n target_agent_name=target_agent,\n a2a_parts=parts,\n external_request_context=context,\n user_identity=user_identity\n )\n \n return {"task_id": task_id, "status": "accepted"}\n'})}),"\n",(0,i.jsx)(n.h3,{id:"websocket-gateway",children:"WebSocket Gateway"}),"\n",(0,i.jsx)(n.p,{children:"For real-time bidirectional communication:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'import websockets\nimport json\n\nclass WebSocketGatewayComponent(BaseGatewayComponent):\n def __init__(self, **kwargs):\n super().__init__(**kwargs)\n self.connections = {}\n \n async def _start_listener(self):\n """Start WebSocket server."""\n self.server = await websockets.serve(\n self.handle_websocket,\n self.get_config("websocket_host", "localhost"),\n self.get_config("websocket_port", 8765)\n )\n log.info("%s WebSocket server started", self.log_identifier)\n \n async def handle_websocket(self, websocket, path):\n """Handle WebSocket connections."""\n connection_id = self.generate_uuid()\n self.connections[connection_id] = websocket\n \n try:\n async for message in websocket:\n data = json.loads(message)\n await self.process_websocket_message(connection_id, data)\n except websockets.exceptions.ConnectionClosed:\n log.info("%s WebSocket connection closed: %s", self.log_identifier, connection_id)\n finally:\n self.connections.pop(connection_id, None)\n \n async def process_websocket_message(self, connection_id: str, data: dict):\n """Process incoming WebSocket message."""\n user_identity = await self.authenticate_and_enrich_user({\n "connection_id": connection_id,\n "data": data\n })\n \n if user_identity:\n target_agent, parts, context = await self._translate_external_input(\n data, user_identity\n )\n context["connection_id"] = connection_id\n \n await self.submit_a2a_task(\n target_agent_name=target_agent,\n a2a_parts=parts,\n external_request_context=context,\n user_identity=user_identity\n )\n \n async def _send_final_response_to_external(self, context: Dict[str, Any], task_data: Task):\n """Send response back via WebSocket."""\n connection_id = context.get("connection_id")\n websocket = self.connections.get(connection_id)\n \n if websocket:\n response = {\n "task_id": task_data.id,\n "status": task_data.status.state.value if task_data.status else "unknown",\n "result": self._extract_text_from_task(task_data)\n }\n await websocket.send(json.dumps(response))\n'})}),"\n",(0,i.jsx)(n.h3,{id:"message-queue-gateway",children:"Message Queue Gateway"}),"\n",(0,i.jsx)(n.p,{children:"For integration with message queues:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'import asyncio\nimport aio_pika\n\nclass MessageQueueGatewayComponent(BaseGatewayComponent):\n def __init__(self, **kwargs):\n super().__init__(**kwargs)\n self.connection = None\n self.channel = None\n \n async def _start_listener(self):\n """Connect to message queue and start consuming."""\n connection_url = self.get_config("rabbitmq_url")\n queue_name = self.get_config("input_queue_name")\n \n self.connection = await aio_pika.connect_robust(connection_url)\n self.channel = await self.connection.channel()\n \n queue = await self.channel.declare_queue(queue_name, durable=True)\n await queue.consume(self.process_message)\n \n log.info("%s Started consuming from queue: %s", self.log_identifier, queue_name)\n \n async def process_message(self, message: aio_pika.IncomingMessage):\n """Process incoming queue message."""\n async with message.process():\n try:\n data = json.loads(message.body.decode())\n \n user_identity = await self.authenticate_and_enrich_user(data)\n if not user_identity:\n log.warning("%s Authentication failed for message", self.log_identifier)\n return\n \n target_agent, parts, context = await self._translate_external_input(\n data, user_identity\n )\n context["message_id"] = message.message_id\n context["reply_to"] = message.reply_to\n \n await self.submit_a2a_task(\n target_agent_name=target_agent,\n a2a_parts=parts,\n external_request_context=context,\n user_identity=user_identity\n )\n \n except Exception as e:\n log.exception("%s Error processing message: %s", self.log_identifier, e)\n \n async def _send_final_response_to_external(self, context: Dict[str, Any], task_data: Task):\n """Send response back to reply queue."""\n reply_to = context.get("reply_to")\n if reply_to and self.channel:\n response = {\n "task_id": task_data.id,\n "status": task_data.status.state.value if task_data.status else "unknown",\n "result": self._extract_text_from_task(task_data)\n }\n \n await self.channel.default_exchange.publish(\n aio_pika.Message(json.dumps(response).encode()),\n routing_key=reply_to\n )\n'})}),"\n",(0,i.jsx)(n.h2,{id:"packaging-as-a-plugin",children:"Packaging as a Plugin"}),"\n",(0,i.jsx)(n.p,{children:"For distribution and reusability, package your gateway as a plugin:"}),"\n",(0,i.jsx)(n.h3,{id:"1-create-plugin-structure",children:"1. Create Plugin Structure"}),"\n",(0,i.jsxs)(n.p,{children:["The following structure is created when running the ",(0,i.jsx)(n.code,{children:"sam plugin create my-gateway-plugin --type gateway"})," command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"my-gateway-plugin/\n\u251c\u2500\u2500 pyproject.toml\n\u251c\u2500\u2500 README.md\n\u251c\u2500\u2500 src/\n\u2502 \u2514\u2500\u2500 sam_my_gateway/\n\u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 app.py\n\u2502 \u251c\u2500\u2500 component.py\n\u251c\u2500\u2500 config.yaml\n\u2514\u2500\u2500 examples/\n \u2514\u2500\u2500 my_gateway_example.yaml\n"})}),"\n",(0,i.jsxs)(n.h3,{id:"2-configure-pyprojecttoml",children:["2. Configure ",(0,i.jsx)(n.code,{children:"pyproject.toml"})]}),"\n",(0,i.jsxs)(n.p,{children:["Update the ",(0,i.jsx)(n.code,{children:"pyproject.toml"})," file to include your gateway dependencies:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-toml",children:'...\ndependencies = [\n "watchdog>=3.0.0", # Add your specific dependencies\n]\n...\n'})}),"\n",(0,i.jsx)(n.h3,{id:"3-build-and-install",children:"3. Build and Install"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"# Build the plugin\nsam plugin build\n\n# Install plugin from local wheel file\nsam plugin add my-gateway --plugin dist/sam_my_gateway-0.1.0-py3-none-any.whl\n"})}),"\n",(0,i.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,i.jsx)(n.h3,{id:"common-issues",children:"Common Issues"}),"\n",(0,i.jsx)(n.h4,{id:"gateway-fails-to-start",children:"Gateway Fails to Start"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Check configuration schema validation"}),"\n",(0,i.jsx)(n.li,{children:"Verify all required parameters are provided"}),"\n",(0,i.jsx)(n.li,{children:"Ensure external dependencies are installed"}),"\n"]}),"\n",(0,i.jsx)(n.h4,{id:"tasks-not-reaching-agents",children:"Tasks Not Reaching Agents"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Verify namespace configuration matches agents"}),"\n",(0,i.jsx)(n.li,{children:"Check Solace broker connectivity"}),"\n",(0,i.jsx)(n.li,{children:"Confirm agent names are correct"}),"\n"]}),"\n",(0,i.jsx)(n.h4,{id:"authentication-failures",children:"Authentication Failures"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Validate user identity extraction logic"}),"\n",(0,i.jsx)(n.li,{children:"Check authorization service configuration"}),"\n",(0,i.jsx)(n.li,{children:"Verify claims format matches expectations"}),"\n"]}),"\n",(0,i.jsx)(n.h4,{id:"fileartifact-issues",children:"File/Artifact Issues"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Ensure artifact service is properly configured"}),"\n",(0,i.jsx)(n.li,{children:"Check file permissions and paths"}),"\n",(0,i.jsx)(n.li,{children:"Verify artifact URI construction"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"debugging-tips",children:"Debugging Tips"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Enable Debug Logging"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"log:\n stdout_log_level: DEBUG\n log_file_level: DEBUG\n"})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Use Test Agents"}),":\nCreate simple echo agents for testing gateway integration"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Monitor Solace Topics"}),":\nUse Solace monitoring tools to trace message flow"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Add Correlation IDs"}),":\nInclude unique identifiers in logs for request tracing"]}),"\n"]}),"\n"]})]})}function _(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>o});var a=t(6540);const i={},s=a.createContext(i);function r(e){const n=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),a.createElement(s.Provider,{value:n},e.children)}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[9066],{7517:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"documentation/developing/creating-service-providers","title":"Creating Service Providers","description":"This guide details the process for developers to create service provider plugins for integrating backend systems (for example, HR platforms, CRMs) with Agent Mesh.","source":"@site/docs/documentation/developing/creating-service-providers.md","sourceDirName":"documentation/developing","slug":"/documentation/developing/creating-service-providers","permalink":"/solace-agent-mesh/docs/documentation/developing/creating-service-providers","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/developing/creating-service-providers.md","tags":[],"version":"current","sidebarPosition":450,"frontMatter":{"title":"Creating Service Providers","sidebar_position":450},"sidebar":"docSidebar","previous":{"title":"Creating Python Tools","permalink":"/solace-agent-mesh/docs/documentation/developing/creating-python-tools"},"next":{"title":"Evaluating Agents","permalink":"/solace-agent-mesh/docs/documentation/developing/evaluations"}}');var t=r(4848),s=r(8453);const o={title:"Creating Service Providers",sidebar_position:450},d="Creating Service Providers",c={},l=[{value:"Understanding Service Providers",id:"understanding-service-providers",level:2},{value:"The "Dual-Role Provider" Pattern",id:"the-dual-role-provider-pattern",level:2},{value:"Step-by-Step Implementation Guide",id:"step-by-step-implementation-guide",level:2},{value:"Step 1: Establish the Plugin Structure",id:"step-1-establish-the-plugin-structure",level:3},{value:"Step 2: Define the Provider Class",id:"step-2-define-the-provider-class",level:3},{value:"Step 3: Map to the Canonical Employee Schema",id:"step-3-map-to-the-canonical-employee-schema",level:3},{value:"Step 4: Register the Plugin",id:"step-4-register-the-plugin",level:3},{value:"Configuring the Provider",id:"configuring-the-provider",level:2}];function a(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"creating-service-providers",children:"Creating Service Providers"})}),"\n",(0,t.jsx)(n.p,{children:"This guide details the process for developers to create service provider plugins for integrating backend systems (for example, HR platforms, CRMs) with Agent Mesh."}),"\n",(0,t.jsx)(n.h2,{id:"understanding-service-providers",children:"Understanding Service Providers"}),"\n",(0,t.jsx)(n.p,{children:"Service Providers function as the abstraction layer between Agent Mesh and enterprise data sources. They are implemented as Python classes that adhere to a specific abstract base class, enabling standardized interaction between Agent Mesh components (Gateways and Agents) and the underlying data."}),"\n",(0,t.jsx)(n.p,{children:"There are two primary service provider interfaces:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"BaseIdentityService"})}),": Responsible for ",(0,t.jsx)(n.strong,{children:"identity enrichment"}),". This service is utilized by Gateways to augment the profile of an authenticated user with additional details (for example, full name, job title) based on their initial authentication claims."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:(0,t.jsx)(n.code,{children:"BaseEmployeeService"})}),": Responsible for ",(0,t.jsx)(n.strong,{children:"general directory querying"}),". This service is utilized by agents (for example, the ",(0,t.jsx)(n.code,{children:"EmployeeAgent"}),") to execute lookups across the entire employee directory."]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"the-dual-role-provider-pattern",children:'The "Dual-Role Provider" Pattern'}),"\n",(0,t.jsx)(n.p,{children:'In many enterprise systems, particularly HR platforms, the data source for identity enrichment and general employee queries is identical. To optimize development, Agent Mesh promotes a "Dual-Role Provider" pattern.'}),"\n",(0,t.jsxs)(n.p,{children:["This pattern involves creating a single class that inherits from both ",(0,t.jsx)(n.code,{children:"BaseIdentityService"})," and ",(0,t.jsx)(n.code,{children:"BaseEmployeeService"}),". This consolidated class can then be configured to fulfill either or both roles, thereby reducing code duplication."]}),"\n",(0,t.jsx)(n.h2,{id:"step-by-step-implementation-guide",children:"Step-by-Step Implementation Guide"}),"\n",(0,t.jsx)(n.p,{children:'This section provides a walkthrough for creating a new provider for a fictional "CorpHR" system.'}),"\n",(0,t.jsx)(n.h3,{id:"step-1-establish-the-plugin-structure",children:"Step 1: Establish the Plugin Structure"}),"\n",(0,t.jsxs)(n.p,{children:["The recommended structure for a custom service provider plugin should include a ",(0,t.jsx)(n.code,{children:"pyproject.toml"})," for packaging and a ",(0,t.jsx)(n.code,{children:"src"})," directory for the source code."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"sam plugin create my_corp_hr_provider --type custom\n"})}),"\n",(0,t.jsx)(n.h3,{id:"step-2-define-the-provider-class",children:"Step 2: Define the Provider Class"}),"\n",(0,t.jsxs)(n.p,{children:["Create a ",(0,t.jsx)(n.code,{children:"provider.py"})," module and define the provider class, ensuring it inherits from both base service classes."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-python",children:'# my_corp_hr_provider/provider.py\n\n# Import base classes from the Agent Mesh framework\ntry:\n from solace_agent_mesh.common.services.identity_service import BaseIdentityService\n from solace_agent_mesh.common.services.employee_service import BaseEmployeeService\nexcept ImportError:\n # Fallback for local development environments\n from src.solace_agent_mesh.common.services.identity_service import BaseIdentityService\n from src.solace_agent_mesh.common.services.employee_service import BaseEmployeeService\n\n# Import any other necessary libraries, such as \'requests\' or a proprietary SDK\n# from .corp_hr_sdk import CorpHR_SDK\n\nclass CorpHRProvider(BaseIdentityService, BaseEmployeeService):\n """\n A dual-role provider for the CorpHR system, implementing methods\n for both identity enrichment and employee directory services.\n """\n def __init__(self, config):\n super().__init__(config)\n # Initialize the backend service/SDK client here.\n # It is best practice to implement this as a singleton to share\n # connection pools and cache.\n # self.corp_hr_sdk = CorpHR_SDK(api_key=config.get("api_key"))\n\n # --- BaseIdentityService Method Implementations ---\n\n async def get_user_profile(self, auth_claims):\n """Enrich the current user\'s profile based on their auth claims."""\n # TODO: Implement logic to fetch user data from CorpHR\n pass\n\n async def search_users(self, query, limit=10):\n """Search for users, for features like @-mentions."""\n # TODO: Implement user search logic against CorpHR\n pass\n\n # --- BaseEmployeeService Method Implementations ---\n\n async def get_employee_dataframe(self):\n """Return all employees as a pandas DataFrame for directory-wide queries."""\n # TODO: Fetch all employee data and return as a DataFrame\n pass\n\n async def get_employee_profile(self, employee_id):\n """Get a single employee\'s full profile by their ID."""\n # Note: This is a general directory lookup, distinct from get_user_profile.\n # TODO: Implement single employee lookup\n pass\n\n async def get_time_off_data(self, employee_id):\n """Get an employee\'s raw time off data."""\n # Example return format:\n # return [{\'start\': \'2025-07-04\', \'end\': \'2025-07-04\', \'type\': \'Holiday\'}]\n # TODO: Implement time off data retrieval\n pass\n\n async def get_employee_profile_picture(self, employee_id):\n """Fetch a profile picture as a data URI string."""\n # Example return format: "data:image/jpeg;base64,..."\n # TODO: Implement profile picture fetching\n pass\n'})}),"\n",(0,t.jsx)(n.h3,{id:"step-3-map-to-the-canonical-employee-schema",children:"Step 3: Map to the Canonical Employee Schema"}),"\n",(0,t.jsxs)(n.p,{children:["When implementing the service methods, it is ",(0,t.jsx)(n.strong,{children:"mandatory"})," to map the data from the source system to the ",(0,t.jsx)(n.strong,{children:"canonical employee schema"})," of Agent Mesh. This ensures data consistency and interoperability with all tools and components across the mesh."]}),"\n",(0,t.jsxs)(n.table,{children:[(0,t.jsx)(n.thead,{children:(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.th,{children:"Field Name"}),(0,t.jsx)(n.th,{children:"Data Type"}),(0,t.jsx)(n.th,{children:"Description"})]})}),(0,t.jsxs)(n.tbody,{children:[(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"id"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsxs)(n.td,{children:["A unique, stable, and ",(0,t.jsx)(n.strong,{children:"lowercase"})," identifier (e.g., email, GUID)."]})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"displayName"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The employee's full name for display purposes."})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"workEmail"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The employee's primary work email address."})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"jobTitle"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The employee's official job title."})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"department"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The department to which the employee belongs."})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"location"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The physical or regional location of the employee."})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"supervisorId"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsxs)(n.td,{children:["The unique ",(0,t.jsx)(n.code,{children:"id"})," of the employee's direct manager."]})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"hireDate"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsxs)(n.td,{children:["The date the employee was hired (ISO 8601: ",(0,t.jsx)(n.code,{children:"YYYY-MM-DD"}),")."]})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"mobilePhone"})}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"string"})}),(0,t.jsx)(n.td,{children:"The employee's mobile phone number (optional)."})]})]})]}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["If a field is not available in the source system, return ",(0,t.jsx)(n.code,{children:"None"})," or omit the key from the returned dictionary."]})}),"\n",(0,t.jsx)(n.h3,{id:"step-4-register-the-plugin",children:"Step 4: Register the Plugin"}),"\n",(0,t.jsx)(n.p,{children:"To make the provider discoverable by Agent Mesh, it must be registered as a plugin via entry points."}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsxs)(n.strong,{children:["1. Add an entry point in ",(0,t.jsx)(n.code,{children:"pyproject.toml"}),":"]}),"\nThe key assigned here (",(0,t.jsx)(n.code,{children:"corphr"}),") is used as the ",(0,t.jsx)(n.code,{children:"type"})," identifier in YAML configurations."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-toml",children:'[project.entry-points."solace_agent_mesh.plugins"]\ncorphr = "my_corp_hr_provider:info"\n'})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsxs)(n.strong,{children:["2. Define the ",(0,t.jsx)(n.code,{children:"info"})," object in the plugin's ",(0,t.jsx)(n.code,{children:"__init__.py"}),":"]}),"\nThis object points to the provider's class path and provides a brief description."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-python",children:'# my_corp_hr_provider/__init__.py\ninfo = {\n "class_path": "my_corp_hr_provider.provider.CorpHRProvider",\n "description": "Identity and People Service provider for CorpHR.",\n}\n'})}),"\n",(0,t.jsx)(n.h2,{id:"configuring-the-provider",children:"Configuring the Provider"}),"\n",(0,t.jsxs)(n.p,{children:["Once the plugin is created and installed (for example, via ",(0,t.jsx)(n.code,{children:"pip install ."}),"), it can be configured in any Gateway or Agent ",(0,t.jsx)(n.code,{children:"app_config.yml"}),"."]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"For a Gateway (Identity Service Role):"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-yaml",children:'app_config:\n identity_service:\n type: "corphr" # Matches the key in pyproject.toml\n api_key: "${CORPHR_API_KEY}"\n lookup_key: "email" # The field from auth_claims to use for lookup\n'})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"For an Agent (Employee Service Role):"}),"\nThis example demonstrates configuring the provider for the ",(0,t.jsx)(n.code,{children:"employee_tools"})," group."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-yaml",children:'app_config:\n tools:\n - tool_type: builtin-group\n group_name: "employee_tools"\n config:\n type: "corphr" # Same provider, different role\n api_key: "${CORPHR_API_KEY}"\n'})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(a,{...e})}):a(e)}},8453:(e,n,r)=>{r.d(n,{R:()=>o,x:()=>d});var i=r(6540);const t={},s=i.createContext(t);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[1188],{7026:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"documentation/enterprise/enterprise","title":"Agent Mesh Enterprise","description":"Agent Mesh Enterprise extends the open-source framework with production-ready features that enterprise environments require. This version provides enhanced security through single sign-on integration, granular access control through role-based permissions, intelligent data management for cost optimization, and comprehensive observability tools for monitoring agent workflows and system performance.","source":"@site/docs/documentation/enterprise/enterprise.md","sourceDirName":"documentation/enterprise","slug":"/documentation/enterprise/","permalink":"/solace-agent-mesh/docs/documentation/enterprise/","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/enterprise/enterprise.md","tags":[],"version":"current","sidebarPosition":700,"frontMatter":{"title":"Agent Mesh Enterprise","sidebar_position":700},"sidebar":"docSidebar","previous":{"title":"A2A Technical Migration Map","permalink":"/solace-agent-mesh/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map"},"next":{"title":"Installing Agent Mesh Enterprise","permalink":"/solace-agent-mesh/docs/documentation/enterprise/installation"}}');var s=t(4848),r=t(8453);const o={title:"Agent Mesh Enterprise",sidebar_position:700},a="Agent Mesh Enterprise",c={},l=[{value:"Enterprise Features",id:"enterprise-features",level:2},{value:"Getting Started with Enterprise",id:"getting-started-with-enterprise",level:2},{value:"Installation",id:"installation",level:3},{value:"Access Control",id:"access-control",level:3},{value:"Single Sign-On",id:"single-sign-on",level:3},{value:"What's Next",id:"whats-next",level:2}];function h(e){const n={a:"a",h1:"h1",h2:"h2",h3:"h3",header:"header",p:"p",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"agent-mesh-enterprise",children:"Agent Mesh Enterprise"})}),"\n",(0,s.jsx)(n.p,{children:"Agent Mesh Enterprise extends the open-source framework with production-ready features that enterprise environments require. This version provides enhanced security through single sign-on integration, granular access control through role-based permissions, intelligent data management for cost optimization, and comprehensive observability tools for monitoring agent workflows and system performance."}),"\n",(0,s.jsxs)(n.p,{children:["Enterprise is available as a self-managed container image that you can deploy in your own infrastructure. You can obtain access by joining the pilot program at ",(0,s.jsx)(n.a,{href:"https://solace.com/solace-agent-mesh-pilot-registration/",children:"solace.com/solace-agent-mesh-pilot-registration"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"enterprise-features",children:"Enterprise Features"}),"\n",(0,s.jsx)(n.p,{children:"The Enterprise version delivers several key capabilities that distinguish it from the Community edition."}),"\n",(0,s.jsx)(n.p,{children:"Authentication and authorization integrate with your existing identity systems through SSO, eliminating the need for separate credentials while maintaining security standards. You can configure role-based access control to implement granular authorization policies that determine which agents and resources each user can access through the Agent Mesh Gateways."}),"\n",(0,s.jsx)(n.p,{children:"Data management features help you optimize costs and improve accuracy. Smart filtering capabilities reduce unnecessary compute expenses while precise data governance helps prevent hallucinations by controlling what information reaches your language models."}),"\n",(0,s.jsx)(n.p,{children:"Observability tools provide complete visibility into your agent ecosystem. The built-in workflow viewer tracks LLM interactions and agent communications in real time, giving you the insights needed to monitor performance, diagnose issues, and understand system behavior."}),"\n",(0,s.jsx)(n.h2,{id:"getting-started-with-enterprise",children:"Getting Started with Enterprise"}),"\n",(0,s.jsx)(n.p,{children:"Setting up Agent Mesh Enterprise involves three main areas: installation, security configuration, and authentication setup."}),"\n",(0,s.jsx)(n.h3,{id:"installation",children:"Installation"}),"\n",(0,s.jsxs)(n.p,{children:["The Docker-based installation process downloads the enterprise image from the Solace Product Portal, loads it into your container environment, and launches it with the appropriate configuration for your deployment scenario. You can run Enterprise in development mode with an embedded broker for testing, or connect it to an external Solace broker for production deployments. For complete installation instructions, see ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/enterprise/installation",children:"Installing Agent Mesh Enterprise"}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"access-control",children:"Access Control"}),"\n",(0,s.jsxs)(n.p,{children:["Role-based access control lets you define who can access which agents and features in your deployment. You create roles that represent job functions, assign permissions to those roles through scopes, and then assign roles to users. This three-tier model implements the principle of least privilege while simplifying administration. For guidance on planning and implementing RBAC, see ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/enterprise/rbac-setup-guide",children:"Setting Up RBAC"}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"single-sign-on",children:"Single Sign-On"}),"\n",(0,s.jsxs)(n.p,{children:["SSO integration connects Agent Mesh Enterprise with your organization's identity provider, whether you use Azure, Google, Auth0, Okta, Keycloak, or another OAuth2-compliant system. The configuration process involves creating YAML files that define the authentication service and provider settings, then launching the container with the appropriate environment variables. For step-by-step configuration instructions, see ",(0,s.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/enterprise/single-sign-on",children:"Enabling SSO"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"whats-next",children:"What's Next"}),"\n",(0,s.jsx)(n.p,{children:"After you complete the initial setup, you can begin developing agents and gateways using the same patterns and tools available in the Community edition. The Enterprise features operate transparently\u2014your agents and tools work the same way, but with the added security, governance, and observability that production environments demand."})]})}function d(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>a});var i=t(6540);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[7669],{2260:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>c});const o=JSON.parse('{"id":"documentation/developing/create-agents","title":"Creating Agents","description":"For a more comprehensive tutorial example, see the Build Your Own Agent guide.","source":"@site/docs/documentation/developing/create-agents.md","sourceDirName":"documentation/developing","slug":"/documentation/developing/create-agents","permalink":"/solace-agent-mesh/docs/documentation/developing/create-agents","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/developing/create-agents.md","tags":[],"version":"current","sidebarPosition":420,"frontMatter":{"title":"Creating Agents","sidebar_position":420},"sidebar":"docSidebar","previous":{"title":"Project Structure","permalink":"/solace-agent-mesh/docs/documentation/developing/structure"},"next":{"title":"Create Gateways","permalink":"/solace-agent-mesh/docs/documentation/developing/create-gateways"}}');var i=t(4848),s=t(8453);const a={title:"Creating Agents",sidebar_position:420},r=void 0,l={},c=[{value:"Understanding the Architecture",id:"understanding-the-architecture",level:2},{value:"Core Concepts",id:"core-concepts",level:2},{value:"Tools: The Building Blocks",id:"tools-the-building-blocks",level:3},{value:"Configuration File: The Blueprint",id:"configuration-file-the-blueprint",level:3},{value:"Tool Configuration: Customizing Behavior",id:"tool-configuration-customizing-behavior",level:3},{value:"ToolContext: Accessing Framework Services",id:"toolcontext-accessing-framework-services",level:3},{value:"Lifecycle Functions: Managing Resources",id:"lifecycle-functions-managing-resources",level:3},{value:"Creating Your First Agent: Step-by-Step",id:"creating-your-first-agent-step-by-step",level:2},{value:"Step 1: Initialize Your Agent Plugin",id:"step-1-initialize-your-agent-plugin",level:3},{value:"Step 2: Create Your Tool Functions",id:"step-2-create-your-tool-functions",level:3},{value:"Step 3: Configure Your Agent",id:"step-3-configure-your-agent",level:3},{value:"Step 4: Create Lifecycle Functions",id:"step-4-create-lifecycle-functions",level:3},{value:"Running Your Agent",id:"running-your-agent",level:2},{value:"Building and Installing the Plugin",id:"building-and-installing-the-plugin",level:3},{value:"Quick Debug Mode",id:"quick-debug-mode",level:3},{value:"Advanced Concepts",id:"advanced-concepts",level:2},{value:"Working with Artifacts",id:"working-with-artifacts",level:3},{value:"Using Multiple Tool Configurations",id:"using-multiple-tool-configurations",level:3},{value:"Quick Start: Using the CLI",id:"quick-start-using-the-cli",level:2},{value:"CLI Options",id:"cli-options",level:3},{value:"Best Practices",id:"best-practices",level:2},{value:"Tool Design",id:"tool-design",level:3},{value:"Configuration",id:"configuration",level:3},{value:"Testing",id:"testing",level:3}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",mermaid:"mermaid",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["For a more comprehensive tutorial example, see the ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/developing/tutorials/custom-agent",children:"Build Your Own Agent"})," guide.\nThis page walks through the fundamental concepts for creating agents in Agent Mesh."]})}),"\n",(0,i.jsx)(n.p,{children:"Agent Mesh is a powerful platform that enables you to create intelligent agents that can communicate with each other and perform complex tasks. At its core, Agent Mesh uses a tool-based architecture where LLM-powered agents are equipped with specific capabilities (tools) that they can use to accomplish user requests."}),"\n",(0,i.jsxs)(n.p,{children:["Before continuing with this tutorial, make sure you are familiar with the basic ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/components/agents",children:"agent concept"}),"."]}),"\n",(0,i.jsx)(n.p,{children:'This tutorial guides you through creating your first Agent Mesh agent from scratch. You will learn how to define tools as Python functions, configure an agent using YAML, and set up agent lifecycle functions. By the end of this tutorial, you should have a working "Hello World" agent that demonstrates the fundamental concepts of Agent Mesh agent development.'}),"\n",(0,i.jsx)(n.h2,{id:"understanding-the-architecture",children:"Understanding the Architecture"}),"\n",(0,i.jsx)(n.p,{children:"Before diving into implementation, you need to understand how the different components of an Agent Mesh agent work together. This architectural overview will help you see the big picture before you start building."}),"\n",(0,i.jsx)(n.mermaid,{value:"graph TD\n subgraph Agent Configuration\n direction LR\n A[config.yaml] --\x3e|Defines| B(Agent Properties);\n A --\x3e|Lists & Configures| C(Tools);\n end\n\n subgraph Agent Host\n direction TB\n D[Agent Mesh Host] --\x3e|Loads| A;\n D --\x3e|Instantiates| E[Agent];\n E --\x3e|Initializes with| F[Lifecycle Functions];\n end\n\n subgraph Tool Implementation\n direction LR\n G[Python Module tools.py] --\x3e|Contains| H[Tool Functions];\n end\n\n subgraph Execution Flow\n direction TB\n I[User Request] --\x3e J[LLM Orchestrator];\n J --\x3e|Selects Tool| K{ADKToolWrapper};\n K --\x3e|Calls| H;\n H --\x3e|Accesses| L[ToolContext];\n H --\x3e|Uses| M[tool_config];\n H --\x3e|Returns Result| J;\n end\n\n C --\x3e|Wrapped by| K;\n\n style A fill:#b60000,stroke:#faa,stroke-width:2px\n style H fill:#b60000,stroke:#faa,stroke-width:2px\n style F fill:#007000,stroke:#faa,stroke-width:2px"}),"\n",(0,i.jsx)(n.p,{children:"When a user sends a request to your agent, the LLM orchestrator analyzes the request and decides which tool to use. The framework wraps your tool functions and provides them with context and configuration. Your tool executes its logic and returns results to the LLM, which then formulates a response to the user."}),"\n",(0,i.jsx)(n.h2,{id:"core-concepts",children:"Core Concepts"}),"\n",(0,i.jsx)(n.p,{children:"Understanding these fundamental concepts will help you build effective agents."}),"\n",(0,i.jsx)(n.h3,{id:"tools-the-building-blocks",children:"Tools: The Building Blocks"}),"\n",(0,i.jsx)(n.p,{children:"Tools are the fundamental building blocks of Agent Mesh agents. Each tool is implemented as a Python function that performs a specific task. The LLM orchestrating your agent decides which tools to use based on the user's request and the tool descriptions you provide."}),"\n",(0,i.jsx)(n.p,{children:"Tools can process text and data, interact with external APIs, create and manipulate files, communicate with other agents, and access databases and services. You write tools as standard Python functions, and the framework handles the integration with the LLM."}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Agent Mesh provides a set of ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/components/builtin-tools/",children:"built-in tools"})," plus support for ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/developing/tutorials/mcp-integration",children:"model context protocol (MCP)"})," servers, which can be configured in the tools list of your agent configuration."]})}),"\n",(0,i.jsx)(n.h3,{id:"configuration-file-the-blueprint",children:"Configuration File: The Blueprint"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"config.yaml"})," (for plugin template) or ",(0,i.jsx)(n.code,{children:"agent-name.yaml"})," (for agent instances) file is the blueprint of your agent. This YAML file defines your agent's identity (name, description, and capabilities), model configuration (which LLM to use), tools list (which tools the agent can access and how they're configured), lifecycle functions (setup and cleanup procedures), framework services (session management, artifact storage, and so on), and ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/components/agents#agent-card",children:"agent card"})," (metadata describing the agent capabilities, skills and its visibility in the system)."]}),"\n",(0,i.jsx)(n.p,{children:"The configuration file connects all the pieces together. It tells the framework where to find your tool functions, how to configure them, and what instructions to give the LLM about your agent's purpose."}),"\n",(0,i.jsx)(n.h3,{id:"tool-configuration-customizing-behavior",children:"Tool Configuration: Customizing Behavior"}),"\n",(0,i.jsxs)(n.p,{children:["Within the ",(0,i.jsx)(n.code,{children:"tools"})," list in your YAML config, each tool can have its own ",(0,i.jsx)(n.code,{children:"tool_config"})," section. This allows you to configure the same tool function for different purposes, pass specific parameters to tool instances, and customize tool behavior per agent."]}),"\n",(0,i.jsx)(n.p,{children:"This design pattern enables code reuse. You can write a single generic tool function and configure it multiple times with different parameters to serve different purposes within the same agent."}),"\n",(0,i.jsxs)(n.admonition,{type:"info",children:[(0,i.jsxs)(n.p,{children:['For tools of type "python", you can also use the ',(0,i.jsx)(n.code,{children:"tool_name"})," and ",(0,i.jsx)(n.code,{children:"tool_description"})," to overwrite the function name and description in the tool docstring."]}),(0,i.jsx)(n.p,{children:"This is useful when using a generic tool function for multiple purposes, allowing you to provide a more descriptive name and description for each instance."})]}),"\n",(0,i.jsx)(n.h3,{id:"toolcontext-accessing-framework-services",children:"ToolContext: Accessing Framework Services"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"ToolContext"})," object (passed as one of the arguments to your tool function) provides your tools with access to Agent Mesh core services. Through this context object, your tools can access structured logging for debugging and monitoring, the artifact service for file storage and retrieval, session information about the current user and session context, and agent state for sharing data between tool calls."]}),"\n",(0,i.jsx)(n.p,{children:"The framework automatically provides this context to your tool functions. You don't need to create or manage it yourself."}),"\n",(0,i.jsx)(n.h3,{id:"lifecycle-functions-managing-resources",children:"Lifecycle Functions: Managing Resources"}),"\n",(0,i.jsxs)(n.p,{children:["Lifecycle functions allow you to manage resources that should persist for the agent's lifetime. The ",(0,i.jsx)(n.code,{children:"agent_init_function"})," runs when the agent starts (for example, to establish database connections), and the ",(0,i.jsx)(n.code,{children:"agent_cleanup_function"})," runs when the agent shuts down (for example, to close connections gracefully)."]}),"\n",(0,i.jsx)(n.p,{children:"These functions are optional but recommended for managing resources effectively. They ensure that your agent properly initializes any required resources and cleans them up when shutting down."}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsx)(n.p,{children:"Lifecycle functions are optional but recommended for managing resources effectively."})}),"\n",(0,i.jsx)(n.h2,{id:"creating-your-first-agent-step-by-step",children:"Creating Your First Agent: Step-by-Step"}),"\n",(0,i.jsx)(n.p,{children:'Now that you understand the core concepts, you can create a simple agent that demonstrates how these pieces work together. You will build a "Hello World" agent that can greet users and say goodbye.'}),"\n",(0,i.jsx)(n.h3,{id:"step-1-initialize-your-agent-plugin",children:"Step 1: Initialize Your Agent Plugin"}),"\n",(0,i.jsxs)(n.p,{children:["You can create an agent either by using the ",(0,i.jsx)(n.code,{children:"sam add agent"})," command or by creating a new plugin of type agent with ",(0,i.jsx)(n.code,{children:"sam plugin create my-hello-agent --type agent"}),"."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["For information and recommendations about these options, see ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/components/plugins#agent-or-plugin-which-to-use",children:(0,i.jsx)(n.code,{children:"Agent or Plugin: Which To use?"})}),"."]})}),"\n",(0,i.jsxs)(n.p,{children:["In this tutorial, you create a new agent by creating a new plugin of type agent. For an example of custom agents, see ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/developing/tutorials/custom-agent",children:"Build Your Own Agent"})," guide."]}),"\n",(0,i.jsx)(n.p,{children:"Although the directory structure for plugins is slightly different than the one for agents, both require a YAML configuration file, and a python module with the tools and lifecycle functions you want."}),"\n",(0,i.jsx)(n.p,{children:"To create a new agent plugin, run the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam plugin create my-hello-agent --type agent\n"})}),"\n",(0,i.jsx)(n.p,{children:"Follow the prompts to set up your agent. The prompts create a new directory structure for your agent:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"my-hello-agent/\n\u251c\u2500\u2500 src/\n\u2502 \u2514\u2500\u2500 my_hello_agent/\n\u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 tools.py\n\u2502 \u2514\u2500\u2500 lifecycle.py # This file won't be automatically created\n\u251c\u2500\u2500 config.yaml\n\u251c\u2500\u2500 pyproject.toml\n\u2514\u2500\u2500 README.md\n"})}),"\n",(0,i.jsx)(n.mermaid,{value:"graph TD\n A[my-hello-agent/] --\x3e B[src/]\n A --\x3e C[config.yaml]\n A --\x3e D[pyproject.toml]\n A --\x3e E[README.md]\n \n B --\x3e F[my_hello_agent/]\n F --\x3e G[__init__.py]\n F --\x3e H[tools.py]\n F --\x3e I[lifecycle.py]\n \n style C fill:#b60000,stroke:#333,stroke-width:2px\n style H fill:#b60000,stroke:#333,stroke-width:2px\n style I fill:#007000,stroke:#333,stroke-width:2px"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"config.yaml"})," file will contain your agent configuration, ",(0,i.jsx)(n.code,{children:"tools.py"})," will contain your tool functions, and ",(0,i.jsx)(n.code,{children:"lifecycle.py"})," (which you'll create manually) will contain your lifecycle functions. The ",(0,i.jsx)(n.code,{children:"pyproject.toml"})," file manages your plugin's dependencies and metadata."]}),"\n",(0,i.jsx)(n.h3,{id:"step-2-create-your-tool-functions",children:"Step 2: Create Your Tool Functions"}),"\n",(0,i.jsx)(n.p,{children:"Tools are where your agent's actual capabilities live. You will create two simple tools: one to greet users and one to say goodbye."}),"\n",(0,i.jsxs)(n.p,{children:["Create your tool functions in the ",(0,i.jsx)(n.code,{children:"src/my_hello_agent/tools.py"})," file. For a complete guide on creating python tools, see our ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/developing/creating-python-tools",children:"Creating Python Tools"})," documentation."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'# src/my_hello_agent/tools.py\n"""\nTools for the Hello World agent.\n"""\n\nfrom typing import Any, Dict, Optional\nfrom google.adk.tools import ToolContext\nfrom solace_ai_connector.common.log import log\n\n\nasync def hello_tool(\n name: str,\n tool_context: Optional[ToolContext] = None,\n tool_config: Optional[Dict[str, Any]] = None\n) -> Dict[str, Any]:\n """\n Greets a user with a personalized message.\n \n Args:\n name: The name of the person to greet\n \n Returns:\n A dictionary with the greeting message\n """\n log_identifier = "[HelloTool]"\n log.info(f"{log_identifier} Greeting user: {name}")\n \n # Get configuration from tool_config\n greeting_prefix = "Hello"\n if tool_config:\n greeting_prefix = tool_config.get("greeting_prefix", "Hello")\n \n # Create the greeting message\n greeting_message = f"{greeting_prefix}, {name}! Welcome to Agent Mesh!"\n \n log.info(f"{log_identifier} Generated greeting: {greeting_message}")\n \n return {\n "status": "success",\n "message": greeting_message,\n "greeted_name": name\n }\n\n\nasync def farewell_tool(\n name: str,\n tool_context: Optional[ToolContext] = None,\n tool_config: Optional[Dict[str, Any]] = None\n) -> Dict[str, Any]:\n """\n Says goodbye to a user.\n \n Args:\n name: The name of the person to say goodbye to\n \n Returns:\n A dictionary with the farewell message\n """\n log_identifier = "[FarewellTool]"\n log.info(f"{log_identifier} Saying goodbye to user: {name}")\n \n # Get configuration from tool_config\n farewell_prefix = "Goodbye"\n if tool_config:\n farewell_prefix = tool_config.get("farewell_prefix", "Goodbye")\n \n # Create the farewell message\n farewell_message = f"{farewell_prefix}, {name}! Thanks for using Agent Mesh!"\n \n log.info(f"{log_identifier} Generated farewell: {farewell_message}")\n \n return {\n "status": "success",\n "message": farewell_message,\n "farewell_name": name\n }\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Let's examine what makes these tool functions work. All tool functions must be asynchronous (defined with ",(0,i.jsx)(n.code,{children:"async def"}),") because the framework uses asynchronous execution. The framework automatically provides two special parameters: ",(0,i.jsx)(n.code,{children:"tool_context"})," gives you access to framework services like logging and artifact storage, and ",(0,i.jsx)(n.code,{children:"tool_config"})," contains any custom configuration you define in your YAML file."]}),"\n",(0,i.jsxs)(n.p,{children:["The function signature includes regular parameters (like ",(0,i.jsx)(n.code,{children:"name"}),") that the LLM will provide when calling the tool. The docstring is important because the LLM uses it to understand what the tool does and when to use it. You should always write clear, descriptive docstrings."]}),"\n",(0,i.jsxs)(n.p,{children:["The tool retrieves its configuration from the ",(0,i.jsx)(n.code,{children:"tool_config"})," dictionary. This allows you to customize the tool's behavior without changing the code. In this example, you can configure different greeting prefixes for different use cases."]}),"\n",(0,i.jsxs)(n.p,{children:["The tool returns a dictionary with at least a ",(0,i.jsx)(n.code,{children:"status"})," field. This structured format makes it easy for the LLM to understand the result. You can include any additional data that might be useful for the LLM or for debugging."]}),"\n",(0,i.jsx)(n.p,{children:"The logging statements help you track what your tool is doing. The framework provides a logger that you should use for consistent logging across your agent."}),"\n",(0,i.jsx)(n.h3,{id:"step-3-configure-your-agent",children:"Step 3: Configure Your Agent"}),"\n",(0,i.jsxs)(n.p,{children:["Now you need to tell the framework about your agent and its tools. Create the main configuration file for your agent in ",(0,i.jsx)(n.code,{children:"config.yaml"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'# File: config.yaml (at root of project directory)\n# ... (additional services and configurations)\n\napps:\n - name: my-hello-agent\n app_module: solace_agent_mesh.agent.sac.app \n broker:\n # Can be found in configs/shared_config.yaml after running sam init\n <<: *broker_connection\n \n # Agent-specific configuration\n app_config:\n # Basic agent identity\n namespace: ${NAMESPACE} \n supports_streaming: true \n agent_name: "HelloAgent"\n display_name: "Hello World Agent"\n \n # LLM model configuration\n model: *general_model \n \n # Agent instructions (system prompt)\n instruction: |\n You are a friendly Hello World agent. Your purpose is to greet users and \n demonstrate the capabilities of Agent Mesh. You can:\n \n 1. Greet users with personalized messages using the hello_tool\n 2. Say goodbye to users using the farewell_tool\n \n Always be polite and helpful. When greeting someone, ask for their name \n if they haven\'t provided it.\n \n # Lifecycle functions\n agent_init_function:\n module: "my_hello_agent.lifecycle" # This should point to your lifecycle python module\n name: "initialize_hello_agent"\n base_path: .\n config:\n startup_message: "Hello Agent is starting up!"\n log_level: "INFO"\n \n agent_cleanup_function:\n module: "my_hello_agent.lifecycle"\n base_path: .\n name: "cleanup_hello_agent"\n \n # Tools configuration\n tools:\n # Hello tool with custom greeting\n - tool_type: python\n component_module: "my_hello_agent.tools"\n component_base_path: .\n function_name: "hello_tool"\n tool_name: "greet_user" # Renaming the tool, must use this name in the agent card\n tool_config:\n greeting_prefix: "Hello there"\n \n # Farewell tool with custom farewell\n - tool_type: python\n component_module: "my_hello_agent.tools"\n component_base_path: .\n function_name: "farewell_tool"\n tool_name: "say_goodbye"\n tool_config:\n farewell_prefix: "See you later"\n \n # Built-in artifact tools for file operations\n - tool_type: builtin-group\n group_name: "artifact_management"\n \n # Agent card (describes the agent\'s capabilities)\n agent_card:\n description: "A friendly Hello World agent that demonstrates Agent Mesh capabilities"\n defaultInputModes: ["text"]\n defaultOutputModes: ["text"]\n skills:\n - id: "greet_user"\n name: "Greet User"\n description: "Greets users with personalized messages"\n - id: "say_goodbye"\n name: "Say Goodbye"\n description: "Says goodbye to users"\n - id: "file_operations"\n name: "File Operations"\n description: "Create, read, and manage files and artifacts"\n \n # Session and artifact services\n session_service: *default_session_service\n artifact_service: *default_artifact_service\n# ... (additional services and configurations)\n'})}),"\n",(0,i.jsx)(n.p,{children:"This configuration file connects all the pieces of your agent. Let's examine each section to understand its purpose."}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"namespace"})," uniquely identifies your agent in the mesh. This allows multiple agents to coexist and communicate. The ",(0,i.jsx)(n.code,{children:"agent_name"})," and ",(0,i.jsx)(n.code,{children:"display_name"})," provide human-readable identifiers for your agent."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"model"})," section specifies which LLM to use. The ",(0,i.jsx)(n.code,{children:"*general_model"})," reference points to a model configuration defined elsewhere in your configuration files (typically in ",(0,i.jsx)(n.code,{children:"shared_config.yaml"}),"). This allows you to centrally manage model configurations across multiple agents."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"instruction"})," field contains the system prompt that defines your agent's personality and behavior. This text tells the LLM what role it should play and what capabilities it has. You\nshould write clear, specific instructions that help the LLM understand its role."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"tools"})," section lists all the tools your agent can use. Each tool entry specifies the ",(0,i.jsx)(n.code,{children:"tool_type"})," (python for custom functions, builtin-group for built-in tools), the ",(0,i.jsx)(n.code,{children:"component_module"})," that contains the function, the ",(0,i.jsx)(n.code,{children:"function_name"})," to call, and optionally a ",(0,i.jsx)(n.code,{children:"tool_name"})," to rename the tool for the LLM. The ",(0,i.jsx)(n.code,{children:"tool_config"})," section passes custom configuration to each tool instance. This is where you provide the ",(0,i.jsx)(n.code,{children:"greeting_prefix"})," and ",(0,i.jsx)(n.code,{children:"farewell_prefix"})," values that your tool functions read."]}),"\n",(0,i.jsxs)(n.p,{children:["Notice that you can configure the same function multiple times with different names and configurations. The ",(0,i.jsx)(n.code,{children:"hello_tool"})," function is configured as ",(0,i.jsx)(n.code,{children:"greet_user"})," with one greeting prefix, but you could add another configuration with a different prefix for formal greetings."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"agent_card"})," section describes your agent's capabilities to other parts of the system. The ",(0,i.jsx)(n.code,{children:"skills"})," list should match the tools you've configured. Each skill has an ",(0,i.jsx)(n.code,{children:"id"})," that corresponds to a tool name, making it discoverable by other agents and the user interface."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"session_service"})," and ",(0,i.jsx)(n.code,{children:"artifact_service"})," references connect your agent to framework services for managing user sessions and storing files. These services are typically defined in your shared configuration."]}),"\n",(0,i.jsx)(n.h3,{id:"step-4-create-lifecycle-functions",children:"Step 4: Create Lifecycle Functions"}),"\n",(0,i.jsx)(n.p,{children:"Lifecycle functions manage resources that should persist for your agent's lifetime. Although these functions are optional, they demonstrate how to properly initialize and clean up resources."}),"\n",(0,i.jsx)(n.p,{children:"The lifecycle file is not automatically created, so you need to create it manually:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"touch src/my_hello_agent/lifecycle.py\n"})}),"\n",(0,i.jsx)(n.p,{children:"Now add your lifecycle functions:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'# src/my_hello_agent/lifecycle.py\n"""\nLifecycle functions for the Hello World agent.\n"""\n\nfrom typing import Any, Dict\nfrom pydantic import BaseModel, Field\nfrom solace_ai_connector.common.log import log\n\n\nclass HelloAgentInitConfig(BaseModel):\n """\n Configuration model for the Hello Agent initialization.\n """\n startup_message: str = Field(description="Message to log on startup")\n log_level: str = Field(default="INFO", description="Logging level for the agent")\n\n\ndef initialize_hello_agent(host_component: Any, init_config: HelloAgentInitConfig):\n """\n Initializes the Hello World agent.\n \n Args:\n host_component: The agent host component\n init_config: Validated initialization configuration\n """\n log_identifier = f"[{host_component.agent_name}:init]"\n log.info(f"{log_identifier} Starting Hello Agent initialization...")\n \n # Log the startup message from config\n log.info(f"{log_identifier} {init_config.startup_message}")\n \n # You could initialize shared resources here, such as:\n # - Database connections\n # - API clients\n # - Caches or shared data structures\n \n # Store any shared state in the agent\n host_component.set_agent_specific_state("initialized_at", "2024-01-01T00:00:00Z")\n host_component.set_agent_specific_state("greeting_count", 0)\n \n log.info(f"{log_identifier} Hello Agent initialization completed successfully")\n\n\ndef cleanup_hello_agent(host_component: Any):\n """\n Cleans up resources when the Hello World agent shuts down.\n \n Args:\n host_component: The agent host component\n """\n log_identifier = f"[{host_component.agent_name}:cleanup]"\n log.info(f"{log_identifier} Starting Hello Agent cleanup...")\n \n # Retrieve any shared state\n greeting_count = host_component.get_agent_specific_state("greeting_count", 0)\n log.info(f"{log_identifier} Agent processed {greeting_count} greetings during its lifetime")\n \n # Clean up resources here, such as:\n # - Closing database connections\n # - Shutting down background tasks\n # - Saving final state\n \n log.info(f"{log_identifier} Hello Agent cleanup completed")\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The lifecycle functions follow a specific pattern. The ",(0,i.jsx)(n.code,{children:"initialize_hello_agent"})," function receives two parameters: ",(0,i.jsx)(n.code,{children:"host_component"})," provides access to the agent instance and its methods, and ",(0,i.jsx)(n.code,{children:"init_config"})," contains the validated configuration from your YAML file's ",(0,i.jsx)(n.code,{children:"agent_init_function.config"})," section."]}),"\n",(0,i.jsxs)(n.p,{children:["Using a Pydantic model for ",(0,i.jsx)(n.code,{children:"init_config"})," provides automatic validation. The framework validates your configuration against this model when the agent starts, catching configuration errors early. This is better than manually checking configuration values in your code."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"host_component"})," object provides methods for managing agent state. The ",(0,i.jsx)(n.code,{children:"set_agent_specific_state"})," method stores data that persists across tool calls within the same agent instance. This is useful for tracking statistics, caching data, or maintaining connections. The state is specific to this agent instance and is not shared with other agents."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"cleanup_hello_agent"})," function runs when the agent shuts down. This is your opportunity to gracefully close connections, save final state, or perform any other cleanup tasks. The function receives only the ",(0,i.jsx)(n.code,{children:"host_component"})," parameter because cleanup typically doesn't need additional configuration."]}),"\n",(0,i.jsx)(n.p,{children:"In this example, you retrieve the greeting count from the agent state and log it. In a real application, you might close database connections, flush caches to disk, or notify other services that the agent is shutting down."}),"\n",(0,i.jsx)(n.h2,{id:"running-your-agent",children:"Running Your Agent"}),"\n",(0,i.jsx)(n.p,{children:"Now that you have created all the necessary components, you can run your agent. The process involves building your plugin and adding it to your Agent Mesh project."}),"\n",(0,i.jsx)(n.h3,{id:"building-and-installing-the-plugin",children:"Building and Installing the Plugin"}),"\n",(0,i.jsxs)(n.p,{children:["To properly instantiate your plugin agent, first build the plugin. The following command will produce a python wheel file under ",(0,i.jsx)(n.code,{children:"dist"})," directory:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam plugin build\n"})}),"\n",(0,i.jsx)(n.p,{children:"This command packages your agent code, configuration, and dependencies into a distributable wheel file. The wheel file is a standard Python package format that can be installed into any Python environment."}),"\n",(0,i.jsxs)(n.p,{children:["Check into ",(0,i.jsx)(n.a,{href:"/solace-agent-mesh/docs/documentation/getting-started/try-agent-mesh",children:"your Agent Mesh project directory"}),", and add the plugin wheel with a given name:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam plugin add my-first-weather-agent --plugin PATH/TO/weather-agent/dist/weather-agent.whl\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Using the ",(0,i.jsx)(n.code,{children:"sam plugin add"})," command installs your plugin as a python dependency into your python environment.\nThis also means changing the source code without reinstalling the plugin will not reflect the changes."]})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"sam plugin add"})," command does several things. It installs your plugin package into your Python environment, making your tool functions and lifecycle functions importable. It also creates a configuration file in your project's ",(0,i.jsx)(n.code,{children:"configs/agents/"})," directory that references your plugin. This configuration file is what the framework loads when you run your agent."]}),"\n",(0,i.jsx)(n.p,{children:"Now, you can run the complete Agent Mesh application along with your newly added agent:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam run\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Alternatively, only run the newly added agent using ",(0,i.jsx)(n.code,{children:"sam run configs/agents/my-first-weather-agent.yaml"})]}),"\n",(0,i.jsx)(n.h3,{id:"quick-debug-mode",children:"Quick Debug Mode"}),"\n",(0,i.jsxs)(n.admonition,{title:"Quick Debug",type:"tip",children:[(0,i.jsxs)(n.p,{children:["For debugging or isolated development testing, you can run your agent from the ",(0,i.jsx)(n.code,{children:"src"})," directory directly using the Agent Mesh CLI."]}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"cd src\nsam run ../config.yaml\n"})}),(0,i.jsx)(n.p,{children:"Changing to the src directory allows the module path to be set correctly so that Agent Mesh can find your functions without your having to install them in your python environment as a plugin package."})]}),"\n",(0,i.jsx)(n.p,{children:"This quick debug mode is useful during development because you can make changes to your code and immediately test them without rebuilding and reinstalling the plugin. However, you should always test with the full plugin installation process before deploying to production."}),"\n",(0,i.jsx)(n.h2,{id:"advanced-concepts",children:"Advanced Concepts"}),"\n",(0,i.jsx)(n.p,{children:"Once you understand the basics, you can explore more advanced patterns for building sophisticated agents."}),"\n",(0,i.jsx)(n.h3,{id:"working-with-artifacts",children:"Working with Artifacts"}),"\n",(0,i.jsx)(n.p,{children:"The artifact service allows your tools to create, store, and retrieve files. You can enhance your hello tool to save greetings to a file using the artifact service:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'\nfrom datetime import datetime\nfrom solace_agent_mesh.agent.utils.artifact_helpers import save_artifact_with_metadata\n\nasync def hello_tool_with_artifact(\n name: str,\n save_to_file: bool = False,\n tool_context: Optional[ToolContext] = None,\n tool_config: Optional[Dict[str, Any]] = None\n) -> Dict[str, Any]:\n """\n Greets a user and optionally saves the greeting to a file.\n """\n log_identifier = "[HelloToolWithArtifact]"\n \n # Generate greeting (same as before)\n greeting_prefix = tool_config.get("greeting_prefix", "Hello") if tool_config else "Hello"\n greeting_message = f"{greeting_prefix}, {name}! Welcome to Agent Mesh!"\n \n result = {\n "status": "success",\n "message": greeting_message,\n "greeted_name": name\n }\n \n # Save to artifact if requested\n if save_to_file and tool_context:\n try:\n # Prepare content\n timestamp = datetime.now(timezone.utc)\n filename = f"greeting_{name}_{timestamp}.txt"\n content = f"Greeting: {greeting_message}\\nTimestamp: {timestamp}\\n"\n \n # Save artifact\n artifact_service = tool_context._invocation_context.artifact_service\n await save_artifact_with_metadata(\n artifact_service=artifact_service,\n app_name=tool_context._invocation_context.app_name,\n user_id=tool_context._invocation_context.user_id,\n session_id=tool_context._invocation_context.session.id,\n filename=filename,\n content_bytes=content.encode(\'utf-8\'),\n mime_type="application/json",\n metadata_dict={\n "description": "Greeting message",\n "source": "Greeting Agent",\n },\n timestamp=timestamp\n )\n \n result["artifact_saved"] = filename\n log.info(f"{log_identifier} Saved greeting to artifact: {filename}")\n \n except Exception as e:\n log.error(f"{log_identifier} Failed to save artifact: {e}")\n result["artifact_error"] = str(e)\n \n return result\n'})}),"\n",(0,i.jsxs)(n.p,{children:["This enhanced tool demonstrates several important concepts. The ",(0,i.jsx)(n.code,{children:"save_to_file"})," parameter allows the LLM to decide whether to save the greeting based on the user's request. This gives your agent flexibility in how it uses the tool."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"tool_context"})," object provides access to the artifact service through its ",(0,i.jsx)(n.code,{children:"_invocation_context"})," property. The invocation context contains information about the current execution environment, including the user ID, session ID, and app name. These identifiers are necessary for properly organizing and retrieving artifacts."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"save_artifact_with_metadata"})," helper function handles the details of saving files to the artifact service. You provide the content as bytes, specify a MIME type, and include metadata that describes the artifact. The metadata makes it easier to search for and manage artifacts later."]}),"\n",(0,i.jsx)(n.p,{children:"Error handling is important when working with external services. The try-except block ensures that if artifact saving fails, your tool can still return a successful greeting. The error is logged and included in the result, allowing the LLM to inform the user about the issue."}),"\n",(0,i.jsx)(n.h3,{id:"using-multiple-tool-configurations",children:"Using Multiple Tool Configurations"}),"\n",(0,i.jsx)(n.p,{children:"You can configure the same tool function multiple times with different settings. This pattern is useful when you want to provide the LLM with multiple variations of the same capability:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'tools:\n # Formal greeting\n - tool_type: python\n component_module: "my_hello_agent.tools"\n function_name: "hello_tool"\n tool_name: "formal_greeting"\n tool_config:\n greeting_prefix: "Good day"\n \n # Casual greeting\n - tool_type: python\n component_module: "my_hello_agent.tools"\n function_name: "hello_tool"\n tool_name: "casual_greeting"\n tool_config:\n greeting_prefix: "Hey there"\n \n # Enthusiastic greeting\n - tool_type: python\n component_module: "my_hello_agent.tools"\n function_name: "hello_tool"\n tool_name: "enthusiastic_greeting"\n tool_config:\n greeting_prefix: "Hello and welcome"\n'})}),"\n",(0,i.jsx)(n.p,{children:"This configuration creates three different tools from the same function. The LLM sees these as distinct capabilities and can choose the appropriate greeting style based on the context of the conversation. For example, it might use the formal greeting for business contexts and the casual greeting for friendly conversations."}),"\n",(0,i.jsxs)(n.p,{children:["Each tool configuration should have a unique ",(0,i.jsx)(n.code,{children:"tool_name"})," and should be listed in your agent card's skills section. This makes each variation discoverable and allows you to provide specific descriptions for each greeting style."]}),"\n",(0,i.jsx)(n.h2,{id:"quick-start-using-the-cli",children:"Quick Start: Using the CLI"}),"\n",(0,i.jsx)(n.p,{children:"If you want to get started quickly without manually creating all the files, you can use the Agent Mesh CLI to generate the basic structure:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam add agent my-first-agent\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This command launches an interactive setup (or use ",(0,i.jsx)(n.code,{children:"--gui"})," for browser-based configuration) that generates the necessary files and configuration, and sets up the basic agent structure."]}),"\n",(0,i.jsx)(n.p,{children:"Note that creating an agent as a plugin is preferred over creating an agent directly because plugins are more portable and easier to share."}),"\n",(0,i.jsx)(n.h3,{id:"cli-options",children:"CLI Options"}),"\n",(0,i.jsx)(n.p,{children:"You can customize the agent creation with provided CLI options. For a complete list of options, run:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sam add agent --help\n"})}),"\n",(0,i.jsx)(n.p,{children:"The CLI tool is useful for quickly scaffolding new agents, but understanding the manual process helps you customize and troubleshoot your agents more effectively."}),"\n",(0,i.jsx)(n.h2,{id:"best-practices",children:"Best Practices"}),"\n",(0,i.jsx)(n.p,{children:"Following these best practices will help you create robust, maintainable agents."}),"\n",(0,i.jsx)(n.h3,{id:"tool-design",children:"Tool Design"}),"\n",(0,i.jsx)(n.p,{children:"Each tool should do one thing well. This single responsibility principle makes your tools easier to test, debug, and reuse. Instead of creating one large tool that handles multiple tasks, create several focused tools that each handle a specific task."}),"\n",(0,i.jsx)(n.p,{children:"Write detailed docstrings for your tools. The LLM uses these docstrings to understand what each tool does and when to use it. Include descriptions of all parameters, return values, and any important behavior or limitations."}),"\n",(0,i.jsx)(n.p,{children:"Always return structured error responses. When something goes wrong, your tool should return a dictionary with a status field indicating failure and a message explaining what went wrong. This allows the LLM to understand the error and potentially retry with different parameters or inform the user about the issue."}),"\n",(0,i.jsx)(n.p,{children:"Use consistent logging for debugging and monitoring. Log important events, parameter values, and results. This makes it much easier to troubleshoot issues when your agent is running in production."}),"\n",(0,i.jsx)(n.h3,{id:"configuration",children:"Configuration"}),"\n",(0,i.jsx)(n.p,{children:"Use environment variables for sensitive data like API keys, database passwords, and other credentials. Never hardcode sensitive information in your configuration files or source code."}),"\n",(0,i.jsx)(n.p,{children:"Use Pydantic models for configuration validation. This catches configuration errors early and provides clear error messages when something is wrong. It also serves as documentation for what configuration options are available."}),"\n",(0,i.jsx)(n.p,{children:"Comment your configuration files thoroughly. YAML files can become complex, and clear comments help other developers (and your future self) understand what each section does and why it's configured that way."}),"\n",(0,i.jsx)(n.h3,{id:"testing",children:"Testing"}),"\n",(0,i.jsxs)(n.p,{children:["Write unit tests for your tool functions independently. Test them with various inputs, including edge cases and error conditions. Mock the ",(0,i.jsx)(n.code,{children:"tool_context"})," and ",(0,i.jsx)(n.code,{children:"tool_config"})," parameters to isolate your tool logic from the framework."]}),"\n",(0,i.jsx)(n.p,{children:"Write integration tests that test your agent with real Agent Mesh infrastructure. These tests verify that your configuration is correct and that your tools work properly when called by the LLM."}),"\n",(0,i.jsx)(n.p,{children:"Mock external dependencies for reliable testing. If your tools call external APIs or databases, create mock versions for testing. This makes your tests faster and more reliable because they don't depend on external services being available."})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>r});var o=t(6540);const i={},s=o.createContext(i);function a(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunksolace_agenitc_mesh_docs=self.webpackChunksolace_agenitc_mesh_docs||[]).push([[6963],{7586:(e,a,n)=>{n.r(a),n.d(a,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>t,toc:()=>c});const t=JSON.parse('{"id":"documentation/developing/tutorials/sql-database","title":"SQL Database Integration","description":"This tutorial sets up a SQL database agent in Agent Mesh, which allows the Agent Mesh agent to answer natural language queries about a sample coffee company database. This tutorial provides some sample data to set up an SQLite database, but you can use the same approach to connect to other database types, such as MySQL or PostgreSQL.","source":"@site/docs/documentation/developing/tutorials/sql-database.md","sourceDirName":"documentation/developing/tutorials","slug":"/documentation/developing/tutorials/sql-database","permalink":"/solace-agent-mesh/docs/documentation/developing/tutorials/sql-database","draft":false,"unlisted":false,"editUrl":"https://github.com/SolaceLabs/solace-agent-mesh/edit/main/docs/docs/documentation/developing/tutorials/sql-database.md","tags":[],"version":"current","sidebarPosition":40,"frontMatter":{"title":"SQL Database Integration","sidebar_position":40},"sidebar":"docSidebar","previous":{"title":"Amazon Bedrock Agents","permalink":"/solace-agent-mesh/docs/documentation/developing/tutorials/bedrock-agents"},"next":{"title":"MongoDB Integration","permalink":"/solace-agent-mesh/docs/documentation/developing/tutorials/mongodb-integration"}}');var s=n(4848),i=n(8453);const o={title:"SQL Database Integration",sidebar_position:40},r="SQL Database Integration",l={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Adding the SQL Database Plugin",id:"adding-the-sql-database-plugin",level:2},{value:"Downloading Example Data",id:"downloading-example-data",level:2},{value:"Using wget",id:"using-wget",level:4},{value:"Using curl",id:"using-curl",level:4},{value:"Configuring the Agent",id:"configuring-the-agent",level:2},{value:"Setting the Environment Variables",id:"setting-the-environment-variables",level:2},{value:"Running the Agent",id:"running-the-agent",level:2},{value:"Interacting with the Database",id:"interacting-with-the-database",level:2},{value:"Advanced Configuration",id:"advanced-configuration",level:2},{value:"Customizing the Agent Card",id:"customizing-the-agent-card",level:2},{value:"Key Agent Card Elements",id:"key-agent-card-elements",level:3},{value:"Example of a Well-Configured Agent Card",id:"example-of-a-well-configured-agent-card",level:3}];function d(e){const a={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.header,{children:(0,s.jsx)(a.h1,{id:"sql-database-integration",children:"SQL Database Integration"})}),"\n",(0,s.jsx)(a.p,{children:"This tutorial sets up a SQL database agent in Agent Mesh, which allows the Agent Mesh agent to answer natural language queries about a sample coffee company database. This tutorial provides some sample data to set up an SQLite database, but you can use the same approach to connect to other database types, such as MySQL or PostgreSQL."}),"\n",(0,s.jsx)(a.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,s.jsx)(a.p,{children:"Before starting this tutorial, ensure that you have installed and configured Agent Mesh:"}),"\n",(0,s.jsxs)(a.ul,{children:["\n",(0,s.jsx)(a.li,{children:(0,s.jsx)(a.a,{href:"/solace-agent-mesh/docs/documentation/installing-and-configuring/installation",children:"Installed Agent Mesh and the Agent Mesh CLI"})}),"\n",(0,s.jsx)(a.li,{children:(0,s.jsx)(a.a,{href:"/solace-agent-mesh/docs/documentation/installing-and-configuring/run-project",children:"Created a new Agent Mesh project"})}),"\n",(0,s.jsx)(a.li,{children:"Access to a SQL database (local or remote)"}),"\n"]}),"\n",(0,s.jsx)(a.h2,{id:"adding-the-sql-database-plugin",children:"Adding the SQL Database Plugin"}),"\n",(0,s.jsx)(a.p,{children:"Add the SQL Database plugin to your Agent Mesh project:"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-sh",children:"sam plugin add abc-coffee-info --plugin sam-sql-database\n"})}),"\n",(0,s.jsxs)(a.p,{children:["You can use any name for your agent, in this tutorial we use ",(0,s.jsx)(a.code,{children:"abc-coffee-info"}),"."]}),"\n",(0,s.jsx)(a.p,{children:"This command:"}),"\n",(0,s.jsxs)(a.ul,{children:["\n",(0,s.jsxs)(a.li,{children:["Installs the ",(0,s.jsx)(a.code,{children:"sam-sql-database"})," plugin"]}),"\n",(0,s.jsxs)(a.li,{children:["Creates a new agent configuration file at ",(0,s.jsx)(a.code,{children:"configs/agents/abc-coffee-info.yaml"})]}),"\n"]}),"\n",(0,s.jsx)(a.h2,{id:"downloading-example-data",children:"Downloading Example Data"}),"\n",(0,s.jsx)(a.p,{children:"For this tutorial, you can use a sample SQLite database for a fictional coffee company called ABC Coffee Co."}),"\n",(0,s.jsx)(a.p,{children:"First, download the example data."}),"\n",(0,s.jsx)(a.p,{children:"You can either visit this link to download with your browser:"}),"\n",(0,s.jsx)(a.p,{children:(0,s.jsx)(a.a,{href:"https://github.com/SolaceLabs/solace-agent-mesh-core-plugins/raw/refs/heads/main/sam-sql-database/example-data/abc_coffee_co.zip",children:"https://github.com/SolaceLabs/solace-agent-mesh-core-plugins/raw/refs/heads/main/sam-sql-database/example-data/abc_coffee_co.zip"})}),"\n",(0,s.jsx)(a.p,{children:"Or you can use the command line to download the ZIP file:"}),"\n",(0,s.jsx)(a.h4,{id:"using-wget",children:"Using wget"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-sh",children:"wget https://github.com/SolaceLabs/solace-agent-mesh-core-plugins/raw/refs/heads/main/sam-sql-database/example-data/abc_coffee_co.zip\n"})}),"\n",(0,s.jsx)(a.h4,{id:"using-curl",children:"Using curl"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-sh",children:"curl -LO https://github.com/SolaceLabs/solace-agent-mesh-core-plugins/raw/refs/heads/main/sam-sql-database/example-data/abc_coffee_co.zip\n"})}),"\n",(0,s.jsx)(a.p,{children:"After downloading the ZIP file, extract it to a directory of your choice. You can use the following command to extract the ZIP file:"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-sh",children:"unzip abc_coffee_co.zip\n"})}),"\n",(0,s.jsx)(a.h2,{id:"configuring-the-agent",children:"Configuring the Agent"}),"\n",(0,s.jsxs)(a.p,{children:["Now, update the agent configuration to use the SQLite database and import the CSV files.\nOpen the ",(0,s.jsx)(a.code,{children:"configs/agents/abc-coffee-info.yaml"})," file and modify the ",(0,s.jsx)(a.code,{children:"agent_init_function.config"})," section to specify the CSV directory."]}),"\n",(0,s.jsx)(a.p,{children:"Here is what you need to modify in the configuration file:"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-yaml",children:'# Find the agent_init_function section and update the config:\nagent_init_function:\n module: "sam_sql_database.lifecycle"\n name: "initialize_sql_agent"\n config:\n db_type: "${ABC_COFFEE_INFO_DB_TYPE}"\n db_name: "${ABC_COFFEE_INFO_DB_NAME}"\n database_purpose: "${ABC_COFFEE_INFO_DB_PURPOSE}"\n data_description: "${ABC_COFFEE_INFO_DB_DESCRIPTION}"\n # Add the CSV directory path\n csv_directories:\n - /path/to/your/unzipped/data\n'})}),"\n",(0,s.jsxs)(a.p,{children:["Ensure you replace ",(0,s.jsx)(a.code,{children:"/path/to/your/unzipped/data"})," with the path where you extracted the example data. For example, if you put the ZIP file in the root directory of your Agent Mesh project, you can use ",(0,s.jsx)(a.code,{children:"abc_coffee_co"}),"."]}),"\n",(0,s.jsx)(a.h2,{id:"setting-the-environment-variables",children:"Setting the Environment Variables"}),"\n",(0,s.jsxs)(a.p,{children:["The SQL Database agent requires that you configure several environment variables. You must create or update your ",(0,s.jsx)(a.code,{children:".env"})," file with the following variables for this tutorial:"]}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-bash",children:'ABC_COFFEE_INFO_DB_TYPE=sqlite\nABC_COFFEE_INFO_DB_NAME=abc_coffee.db\nABC_COFFEE_INFO_DB_PURPOSE="ABC Coffee Co. sales and operations database"\nABC_COFFEE_INFO_DB_DESCRIPTION="Contains information about ABC Coffee Co. products, sales, customers, employees, and store locations."\n# You can leave other environment variables as unset or empty\n'})}),"\n",(0,s.jsx)(a.p,{children:"SQLite stores the database in a local file and doesn't require a username or password for access. If you're using a database such as MySQL or PostgreSQL, you'll need to provide the appropriate environment variables for them."}),"\n",(0,s.jsx)(a.h2,{id:"running-the-agent",children:"Running the Agent"}),"\n",(0,s.jsx)(a.p,{children:"Now, you can start your SQL database agent:"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-sh",children:"sam run configs/agents/abc-coffee-info.yaml\n"})}),"\n",(0,s.jsx)(a.p,{children:"The agent:"}),"\n",(0,s.jsxs)(a.ol,{children:["\n",(0,s.jsx)(a.li,{children:"Connects to the A2A control plane"}),"\n",(0,s.jsx)(a.li,{children:"Initializes the SQLite database and imports CSV data from the specified directory"}),"\n",(0,s.jsx)(a.li,{children:"Detects the database schema automatically"}),"\n",(0,s.jsx)(a.li,{children:"Registers its capabilities with the agent discovery system"}),"\n"]}),"\n",(0,s.jsx)(a.h2,{id:"interacting-with-the-database",children:"Interacting with the Database"}),"\n",(0,s.jsxs)(a.p,{children:["After your SQL database agent is running, you can interact with the ABC Coffee database through any gateway in your Agent Mesh project (such as the Web UI gateway at ",(0,s.jsx)(a.code,{children:"http://localhost:8000"}),")."]}),"\n",(0,s.jsx)(a.p,{children:"You can ask natural language questions about the ABC Coffee Co. database, such as:"}),"\n",(0,s.jsxs)(a.ul,{children:["\n",(0,s.jsx)(a.li,{children:'"How many customers does ABC Coffee have?"'}),"\n",(0,s.jsx)(a.li,{children:'"What are the top-selling products?"'}),"\n",(0,s.jsx)(a.li,{children:'"Show me the sales by region"'}),"\n",(0,s.jsx)(a.li,{children:'"List all orders from the last 30 days"'}),"\n",(0,s.jsx)(a.li,{children:'"What products are currently low in inventory?"'}),"\n"]}),"\n",(0,s.jsx)(a.p,{children:"Try creating reports by asking questions such as:"}),"\n",(0,s.jsxs)(a.ul,{children:["\n",(0,s.jsx)(a.li,{children:'"Create a report of our sales in 2024"'}),"\n",(0,s.jsx)(a.li,{children:'"Generate a summary of customer demographics"'}),"\n"]}),"\n",(0,s.jsx)(a.p,{children:"The SQL Database agent converts your natural language questions into SQL queries, executes them against the database, and returns the results. For large result sets, the agent automatically saves the results as artifacts that you can download."}),"\n",(0,s.jsx)(a.h2,{id:"advanced-configuration",children:"Advanced Configuration"}),"\n",(0,s.jsx)(a.p,{children:"The SQL Database plugin supports many advanced configuration options. Here is a complete example based on the plugin structure:"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-yaml",children:'log:\n stdout_log_level: INFO\n log_file_level: DEBUG\n log_file: abc-coffee-info.log\n\n!include ../shared_config.yaml\n\napps:\n - name: abc-coffee-info-app\n app_module: solace_agent_mesh.agent.sac.app \n broker:\n <<: *broker_connection\n\n app_config:\n namespace: ${NAMESPACE}\n agent_name: "AbcCoffeeInfo"\n display_name: "ABC Coffee Database Agent"\n supports_streaming: false\n model: *general_model\n\n instruction: |\n You are an expert SQL assistant for the ABC Coffee Co. database.\n The database schema and query examples are provided to you.\n Your primary goal is to translate user questions into accurate SQL queries.\n If a user asks to query the database, generate the SQL and call the \'execute_sql_query\' tool.\n If the \'execute_sql_query\' tool returns an error, analyze the error message and the original SQL,\n then try to correct the SQL query and call the tool again.\n If the results are large and the tool indicates they were saved as an artifact, inform the user about the artifact.\n Always use the \'execute_sql_query\' tool to interact with the database.\n\n # Agent initialization with database setup\n agent_init_function:\n module: "sam_sql_database.lifecycle"\n name: "initialize_sql_agent"\n config:\n db_type: "${ABC_COFFEE_INFO_DB_TYPE}"\n db_name: "${ABC_COFFEE_INFO_DB_NAME}"\n database_purpose: "${ABC_COFFEE_INFO_DB_PURPOSE}"\n data_description: "${ABC_COFFEE_INFO_DB_DESCRIPTION}"\n auto_detect_schema: true\n csv_directories:\n - "abc_coffee_co" # Path to your extracted data\n query_examples:\n - natural_language: "Show all customers from New York"\n sql_query: "SELECT * FROM customers WHERE city = \'New York\';"\n - natural_language: "What are the top 5 best-selling products?"\n sql_query: "SELECT product_name, SUM(quantity) as total_sold FROM order_items JOIN products ON order_items.product_id = products.id GROUP BY product_name ORDER BY total_sold DESC LIMIT 5;"\n\n agent_cleanup_function:\n module: "sam_sql_database.lifecycle"\n name: "cleanup_sql_agent_resources"\n\n # SQL query tool\n tools:\n - tool_type: python\n component_module: "sam_sql_database.tools"\n function_name: "execute_sql_query"\n\n session_service: *default_session_service\n artifact_service: *default_artifact_service\n\n # Agent capabilities - This is what other agents see during discovery\n agent_card:\n description: "ABC Coffee Co. Database Agent - Access to comprehensive coffee shop data including customers, orders, products, inventory, and sales history. Can answer questions about business metrics, customer analytics, product performance, and operational data."\n defaultInputModes: ["text"]\n defaultOutputModes: ["text", "file"]\n skills:\n - id: "sql_query"\n name: "Coffee Shop Database Query"\n description: "Queries ABC Coffee Co. database containing customer orders, product catalog, inventory levels, sales history, and employee data."\n\n # A2A Protocol settings\n agent_card_publishing: { interval_seconds: 30 }\n agent_discovery: { enabled: true }\n inter_agent_communication:\n allow_list: ["*"]\n request_timeout_seconds: 60\n'})}),"\n",(0,s.jsx)(a.h2,{id:"customizing-the-agent-card",children:"Customizing the Agent Card"}),"\n",(0,s.jsxs)(a.p,{children:["The ",(0,s.jsx)(a.code,{children:"agent_card"})," section is crucial as it defines how other agents in your Agent Mesh ecosystem discover and understand this database agent's capabilities. When other agents use agent discovery, they can see this information to decide whether to delegate tasks to your database agent."]}),"\n",(0,s.jsx)(a.h3,{id:"key-agent-card-elements",children:"Key Agent Card Elements"}),"\n",(0,s.jsxs)(a.ol,{children:["\n",(0,s.jsxs)(a.li,{children:[(0,s.jsx)(a.strong,{children:"Description"}),": Clearly describe what data the agent has access to and what types of questions it can answer"]}),"\n",(0,s.jsxs)(a.li,{children:[(0,s.jsx)(a.strong,{children:"Skills"}),": List specific capabilities with concrete examples that show the scope of data available"]}),"\n",(0,s.jsxs)(a.li,{children:[(0,s.jsx)(a.strong,{children:"Data Context"}),": Mention the business domain, data types, and scope of information available"]}),"\n"]}),"\n",(0,s.jsx)(a.h3,{id:"example-of-a-well-configured-agent-card",children:"Example of a Well-Configured Agent Card"}),"\n",(0,s.jsx)(a.pre,{children:(0,s.jsx)(a.code,{className:"language-yaml",children:'agent_card:\n description: "ABC Coffee Co. Database Agent - Access to comprehensive coffee shop data including customers, orders, products, inventory, and sales history. Can answer questions about business metrics, customer analytics, product performance, and operational data."\n defaultInputModes: ["text"]\n defaultOutputModes: ["text", "file"]\n skills:\n - id: "sql_query"\n name: "Coffee Shop Database Query"\n description: "Queries ABC Coffee Co. database containing customer orders, product catalog, inventory levels, sales history, and employee data."\n'})}),"\n",(0,s.jsx)(a.p,{children:"This detailed information helps other agents understand:"}),"\n",(0,s.jsxs)(a.ul,{children:["\n",(0,s.jsx)(a.li,{children:"What business domain this agent covers (coffee shop operations)"}),"\n",(0,s.jsx)(a.li,{children:"What types of data are available (customers, orders, products, inventory, sales)"}),"\n",(0,s.jsx)(a.li,{children:"What kinds of questions can be answered (metrics, analytics, performance data)"}),"\n",(0,s.jsx)(a.li,{children:"Specific examples of queries that work well"}),"\n"]}),"\n",(0,s.jsx)(a.p,{children:"When configuring your own database agent, customize the description and examples to match your specific data and use cases."})]})}function h(e={}){const{wrapper:a}={...(0,i.R)(),...e.components};return a?(0,s.jsx)(a,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,a,n)=>{n.d(a,{R:()=>o,x:()=>r});var t=n(6540);const s={},i=t.createContext(s);function o(e){const a=t.useContext(i);return t.useMemo((function(){return"function"==typeof e?e(a):{...a,...e}}),[a,e])}function r(e){let a;return a=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),t.createElement(i.Provider,{value:a},e.children)}}}]);
|