solace-agent-mesh 1.11.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- solace_agent_mesh/__init__.py +0 -0
- solace_agent_mesh/agent/__init__.py +0 -0
- solace_agent_mesh/agent/adk/__init__.py +0 -0
- solace_agent_mesh/agent/adk/adk_llm.txt +226 -0
- solace_agent_mesh/agent/adk/adk_llm_detail.txt +566 -0
- solace_agent_mesh/agent/adk/alembic/README +74 -0
- solace_agent_mesh/agent/adk/alembic/env.py +77 -0
- solace_agent_mesh/agent/adk/alembic/script.py.mako +28 -0
- solace_agent_mesh/agent/adk/alembic/versions/e2902798564d_adk_session_db_upgrade.py +52 -0
- solace_agent_mesh/agent/adk/alembic.ini +112 -0
- solace_agent_mesh/agent/adk/app_llm_agent.py +52 -0
- solace_agent_mesh/agent/adk/artifacts/__init__.py +1 -0
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +171 -0
- solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +545 -0
- solace_agent_mesh/agent/adk/artifacts/s3_artifact_service.py +609 -0
- solace_agent_mesh/agent/adk/callbacks.py +2318 -0
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +406 -0
- solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +415 -0
- solace_agent_mesh/agent/adk/mcp_content_processor.py +666 -0
- solace_agent_mesh/agent/adk/models/lite_llm.py +1026 -0
- solace_agent_mesh/agent/adk/models/models_llm.txt +189 -0
- solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +132 -0
- solace_agent_mesh/agent/adk/runner.py +390 -0
- solace_agent_mesh/agent/adk/schema_migration.py +88 -0
- solace_agent_mesh/agent/adk/services.py +468 -0
- solace_agent_mesh/agent/adk/setup.py +1325 -0
- solace_agent_mesh/agent/adk/stream_parser.py +415 -0
- solace_agent_mesh/agent/adk/tool_wrapper.py +165 -0
- solace_agent_mesh/agent/agent_llm.txt +369 -0
- solace_agent_mesh/agent/agent_llm_detail.txt +1702 -0
- solace_agent_mesh/agent/protocol/__init__.py +0 -0
- solace_agent_mesh/agent/protocol/event_handlers.py +2041 -0
- solace_agent_mesh/agent/protocol/protocol_llm.txt +81 -0
- solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +92 -0
- 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/a2a_llm.txt +190 -0
- solace_agent_mesh/agent/proxies/a2a/app.py +56 -0
- solace_agent_mesh/agent/proxies/a2a/component.py +1585 -0
- solace_agent_mesh/agent/proxies/a2a/config.py +216 -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 +100 -0
- solace_agent_mesh/agent/proxies/base/base_llm.txt +148 -0
- solace_agent_mesh/agent/proxies/base/component.py +816 -0
- solace_agent_mesh/agent/proxies/base/config.py +85 -0
- solace_agent_mesh/agent/proxies/base/proxy_task_context.py +19 -0
- solace_agent_mesh/agent/proxies/proxies_llm.txt +283 -0
- solace_agent_mesh/agent/sac/__init__.py +0 -0
- solace_agent_mesh/agent/sac/app.py +595 -0
- solace_agent_mesh/agent/sac/component.py +3668 -0
- solace_agent_mesh/agent/sac/patch_adk.py +103 -0
- solace_agent_mesh/agent/sac/sac_llm.txt +189 -0
- solace_agent_mesh/agent/sac/sac_llm_detail.txt +200 -0
- solace_agent_mesh/agent/sac/task_execution_context.py +415 -0
- solace_agent_mesh/agent/testing/__init__.py +3 -0
- solace_agent_mesh/agent/testing/debug_utils.py +135 -0
- solace_agent_mesh/agent/testing/testing_llm.txt +58 -0
- solace_agent_mesh/agent/testing/testing_llm_detail.txt +68 -0
- solace_agent_mesh/agent/tools/__init__.py +16 -0
- solace_agent_mesh/agent/tools/audio_tools.py +1740 -0
- solace_agent_mesh/agent/tools/builtin_artifact_tools.py +2500 -0
- solace_agent_mesh/agent/tools/builtin_data_analysis_tools.py +244 -0
- solace_agent_mesh/agent/tools/dynamic_tool.py +396 -0
- solace_agent_mesh/agent/tools/general_agent_tools.py +572 -0
- solace_agent_mesh/agent/tools/image_tools.py +1185 -0
- solace_agent_mesh/agent/tools/peer_agent_tool.py +363 -0
- solace_agent_mesh/agent/tools/registry.py +38 -0
- solace_agent_mesh/agent/tools/test_tools.py +136 -0
- solace_agent_mesh/agent/tools/time_tools.py +126 -0
- solace_agent_mesh/agent/tools/tool_config_types.py +93 -0
- solace_agent_mesh/agent/tools/tool_definition.py +53 -0
- solace_agent_mesh/agent/tools/tools_llm.txt +276 -0
- solace_agent_mesh/agent/tools/tools_llm_detail.txt +275 -0
- solace_agent_mesh/agent/tools/web_tools.py +392 -0
- solace_agent_mesh/agent/utils/__init__.py +0 -0
- solace_agent_mesh/agent/utils/artifact_helpers.py +1353 -0
- solace_agent_mesh/agent/utils/config_parser.py +49 -0
- solace_agent_mesh/agent/utils/context_helpers.py +77 -0
- solace_agent_mesh/agent/utils/utils_llm.txt +152 -0
- solace_agent_mesh/agent/utils/utils_llm_detail.txt +149 -0
- solace_agent_mesh/assets/docs/404.html +16 -0
- solace_agent_mesh/assets/docs/assets/css/styles.8162edfb.css +1 -0
- solace_agent_mesh/assets/docs/assets/images/Solace_AI_Framework_With_Broker-85f0a306a9bcdd20b390b7a949f6d862.png +0 -0
- solace_agent_mesh/assets/docs/assets/images/sam-enterprise-credentials-b269f095349473118b2b33bdfcc40122.png +0 -0
- solace_agent_mesh/assets/docs/assets/js/032c2d61.f3d37824.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/05749d90.19ac4f35.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/0bcf40b7.c019ad46.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1001.0182a8bd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1039.0bd46aa1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/149.b797a808.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15e40e79.434bb30f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/165.6a39807d.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/165.6a39807d.js.LICENSE.txt +9 -0
- solace_agent_mesh/assets/docs/assets/js/17896441.e612dfb4.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2130.ab9fd314.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2131ec11.5c7a1f6e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2237.5e477fc6.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js.LICENSE.txt +13 -0
- solace_agent_mesh/assets/docs/assets/js/2334.1cf50a20.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/240a0364.9ad94d1b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2987107d.a80604f9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3219.adc1d663.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/341393d4.0fac2613.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3624.0eaa1fd0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/375.708d48db.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3834.b6cd790e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.28b7c67b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.2ddc75c0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/41adc471.48b12a4e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4250.95455b28.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4356.d169ab5b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4458.518e66fa.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4488.c7cc3442.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4494.6ee23046.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4855.fc4444b6.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4866.22daefc0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/4950.ca4caeda.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/509e993c.a1fbf45a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5388.7a136447.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55b7b518.29d6e75d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5607.081356f8.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5864.b0d0e9de.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.90a87880.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5e95c892.558d5167.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6063ff4c.ef84f702.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/60702c0e.a8bdd79b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6143.0a1464c9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/631738c7.fa471607.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6395.e9c73649.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/66d4869e.b77431fc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6796.51d2c9b7.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6976.379be23b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6978.ee0b945c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6a520c9d.b6e3f2ce.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6aaedf65.7253541d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.a5b36a60.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6d84eae0.fd23ba4a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6fdfefc7.99de744e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7040.cb436723.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7195.412f418a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/71da7b71.374b9d54.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/722f809d.965da774.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7280.3fb73bdb.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/7845.e33e7c4c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/7900.69516146.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/81a99df0.2484b8d9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/82fbfb93.161823a5.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8356.8a379c04.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8567.4732c6b7.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8573.cb04eda5.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8577.1d54e766.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8591.5d015485.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/8591.5d015485.js.LICENSE.txt +61 -0
- solace_agent_mesh/assets/docs/assets/js/8709.7ecd4047.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8731.6c1dbf0c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8908.f9d1b506.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8b032486.91a91afc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9157.b4093d07.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/924ffdeb.975e428a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9278.a4fd875d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/945fb41e.6f4cdffd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/94e8668d.16083b3f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9616.b75c2f6d.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9793.c6d16376.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9bb13469.b2333011.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9e9d0a82.570c057b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a7bd4aaa.2204d2f7.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a94703ab.3e5fbcb3.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ab9708a8.245ae0ef.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/aba21aa0.c42a534c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ad71b5ed.af3ecfd1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ad87452a.9d73dad6.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c198a0dc.8f31f867.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c93cbaa0.0e0d8baf.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cab03b5b.6a073091.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.07e170dd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ceb2a7a6.5d92d7d0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/da0b5bad.b62f7b08.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/db924877.e98d12a1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd817ffc.c37a755e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd81e2b8.b682e9c2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/de5f4c65.e8241890.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/de915948.44a432bc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e04b235d.52cb25ed.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.b1068f9b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.1476f570.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e6f9706b.4488e34c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.250993bf.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ff4d71f2.74710fc1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.7acf7ace.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/main.7acf7ace.js.LICENSE.txt +81 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.9e0813a2.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +154 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +99 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +90 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +107 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +166 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +101 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +219 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +92 -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/projects/index.html +182 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +147 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +345 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +52 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +83 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +84 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +25 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +47 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +85 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +60 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +49 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +144 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +191 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +128 -0
- 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/developing/tutorials/bedrock-agents/index.html +267 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +142 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +116 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +86 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +164 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +140 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +57 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +72 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +102 -0
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +115 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +86 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +67 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +37 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +86 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +324 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +247 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +440 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +184 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +62 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +75 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +54 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +85 -0
- 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/artifact-storage/index.html +290 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +78 -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 +78 -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/installing-and-configuring/session-storage/index.html +251 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +88 -0
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +100 -0
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +52 -0
- solace_agent_mesh/assets/docs/img/Solace_AI_Framework_With_Broker.png +0 -0
- solace_agent_mesh/assets/docs/img/logo.png +0 -0
- solace_agent_mesh/assets/docs/img/sac-flows.png +0 -0
- solace_agent_mesh/assets/docs/img/sac_parts_of_a_component.png +0 -0
- solace_agent_mesh/assets/docs/img/sam-enterprise-credentials.png +0 -0
- solace_agent_mesh/assets/docs/img/solace-logo-text.svg +18 -0
- solace_agent_mesh/assets/docs/img/solace-logo.png +0 -0
- solace_agent_mesh/assets/docs/lunr-index-1765810064709.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -0
- solace_agent_mesh/assets/docs/search-doc-1765810064709.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -0
- solace_agent_mesh/assets/docs/sitemap.xml +1 -0
- solace_agent_mesh/cli/__init__.py +1 -0
- solace_agent_mesh/cli/commands/__init__.py +0 -0
- solace_agent_mesh/cli/commands/add_cmd/__init__.py +15 -0
- solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +250 -0
- solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +729 -0
- solace_agent_mesh/cli/commands/add_cmd/gateway_cmd.py +322 -0
- solace_agent_mesh/cli/commands/add_cmd/web_add_agent_step.py +102 -0
- solace_agent_mesh/cli/commands/add_cmd/web_add_gateway_step.py +114 -0
- solace_agent_mesh/cli/commands/docs_cmd.py +60 -0
- solace_agent_mesh/cli/commands/eval_cmd.py +46 -0
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +439 -0
- solace_agent_mesh/cli/commands/init_cmd/broker_step.py +201 -0
- solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
- solace_agent_mesh/cli/commands/init_cmd/directory_step.py +28 -0
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +238 -0
- solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +365 -0
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +464 -0
- solace_agent_mesh/cli/commands/init_cmd/project_files_step.py +38 -0
- solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +119 -0
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +215 -0
- solace_agent_mesh/cli/commands/plugin_cmd/__init__.py +20 -0
- solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +137 -0
- solace_agent_mesh/cli/commands/plugin_cmd/build_cmd.py +86 -0
- solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +144 -0
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +306 -0
- solace_agent_mesh/cli/commands/plugin_cmd/install_cmd.py +283 -0
- solace_agent_mesh/cli/commands/plugin_cmd/official_registry.py +175 -0
- solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +305 -0
- solace_agent_mesh/cli/commands/run_cmd.py +215 -0
- solace_agent_mesh/cli/main.py +52 -0
- solace_agent_mesh/cli/utils.py +262 -0
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-Dj3JtK42.js +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/client-ZKk9kEJ5.js +25 -0
- solace_agent_mesh/client/webui/frontend/static/assets/favicon-BLgzUch9.ico +0 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-BcUaNZ-Q.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-vjch4RYc.js +435 -0
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-BNV4kZN0.js +535 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +15 -0
- solace_agent_mesh/client/webui/frontend/static/index.html +16 -0
- solace_agent_mesh/client/webui/frontend/static/mockServiceWorker.js +336 -0
- solace_agent_mesh/client/webui/frontend/static/ui-version.json +6 -0
- solace_agent_mesh/common/__init__.py +1 -0
- solace_agent_mesh/common/a2a/__init__.py +241 -0
- solace_agent_mesh/common/a2a/a2a_llm.txt +175 -0
- solace_agent_mesh/common/a2a/a2a_llm_detail.txt +193 -0
- solace_agent_mesh/common/a2a/artifact.py +368 -0
- solace_agent_mesh/common/a2a/events.py +213 -0
- solace_agent_mesh/common/a2a/message.py +375 -0
- solace_agent_mesh/common/a2a/protocol.py +689 -0
- solace_agent_mesh/common/a2a/task.py +127 -0
- solace_agent_mesh/common/a2a/translation.py +655 -0
- solace_agent_mesh/common/a2a/types.py +55 -0
- solace_agent_mesh/common/a2a_spec/a2a.json +2576 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +445 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +736 -0
- solace_agent_mesh/common/a2a_spec/schemas/agent_progress_update.json +18 -0
- solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +48 -0
- solace_agent_mesh/common/a2a_spec/schemas/feedback_event.json +51 -0
- solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +41 -0
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +330 -0
- solace_agent_mesh/common/a2a_spec/schemas/tool_invocation_start.json +26 -0
- solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +48 -0
- solace_agent_mesh/common/agent_registry.py +122 -0
- solace_agent_mesh/common/common_llm.txt +230 -0
- solace_agent_mesh/common/common_llm_detail.txt +2562 -0
- solace_agent_mesh/common/constants.py +6 -0
- solace_agent_mesh/common/data_parts.py +150 -0
- solace_agent_mesh/common/exceptions.py +49 -0
- solace_agent_mesh/common/middleware/__init__.py +12 -0
- solace_agent_mesh/common/middleware/config_resolver.py +132 -0
- solace_agent_mesh/common/middleware/middleware_llm.txt +174 -0
- solace_agent_mesh/common/middleware/middleware_llm_detail.txt +185 -0
- solace_agent_mesh/common/middleware/registry.py +127 -0
- solace_agent_mesh/common/oauth/__init__.py +17 -0
- solace_agent_mesh/common/oauth/oauth_client.py +408 -0
- solace_agent_mesh/common/oauth/utils.py +50 -0
- solace_agent_mesh/common/sac/__init__.py +0 -0
- solace_agent_mesh/common/sac/sac_llm.txt +71 -0
- solace_agent_mesh/common/sac/sac_llm_detail.txt +82 -0
- solace_agent_mesh/common/sac/sam_component_base.py +730 -0
- solace_agent_mesh/common/sam_events/__init__.py +9 -0
- solace_agent_mesh/common/sam_events/event_service.py +208 -0
- solace_agent_mesh/common/sam_events/sam_events_llm.txt +104 -0
- solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +115 -0
- solace_agent_mesh/common/services/__init__.py +4 -0
- solace_agent_mesh/common/services/employee_service.py +164 -0
- solace_agent_mesh/common/services/identity_service.py +134 -0
- solace_agent_mesh/common/services/providers/__init__.py +4 -0
- solace_agent_mesh/common/services/providers/local_file_identity_service.py +151 -0
- solace_agent_mesh/common/services/providers/providers_llm.txt +81 -0
- solace_agent_mesh/common/services/services_llm.txt +368 -0
- solace_agent_mesh/common/services/services_llm_detail.txt +459 -0
- solace_agent_mesh/common/utils/__init__.py +7 -0
- solace_agent_mesh/common/utils/artifact_utils.py +31 -0
- solace_agent_mesh/common/utils/asyncio_macos_fix.py +88 -0
- solace_agent_mesh/common/utils/embeds/__init__.py +33 -0
- solace_agent_mesh/common/utils/embeds/constants.py +56 -0
- solace_agent_mesh/common/utils/embeds/converter.py +447 -0
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +220 -0
- solace_agent_mesh/common/utils/embeds/evaluators.py +395 -0
- solace_agent_mesh/common/utils/embeds/modifiers.py +793 -0
- solace_agent_mesh/common/utils/embeds/resolver.py +967 -0
- solace_agent_mesh/common/utils/embeds/types.py +23 -0
- solace_agent_mesh/common/utils/in_memory_cache.py +108 -0
- solace_agent_mesh/common/utils/initializer.py +52 -0
- solace_agent_mesh/common/utils/log_formatters.py +64 -0
- solace_agent_mesh/common/utils/message_utils.py +80 -0
- solace_agent_mesh/common/utils/mime_helpers.py +172 -0
- solace_agent_mesh/common/utils/push_notification_auth.py +135 -0
- solace_agent_mesh/common/utils/pydantic_utils.py +159 -0
- solace_agent_mesh/common/utils/rbac_utils.py +69 -0
- solace_agent_mesh/common/utils/templates/__init__.py +8 -0
- solace_agent_mesh/common/utils/templates/liquid_renderer.py +210 -0
- solace_agent_mesh/common/utils/templates/template_resolver.py +161 -0
- solace_agent_mesh/common/utils/type_utils.py +28 -0
- solace_agent_mesh/common/utils/utils_llm.txt +335 -0
- solace_agent_mesh/common/utils/utils_llm_detail.txt +572 -0
- solace_agent_mesh/config_portal/__init__.py +0 -0
- solace_agent_mesh/config_portal/backend/__init__.py +0 -0
- solace_agent_mesh/config_portal/backend/common.py +77 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/__init__.py +0 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +24 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/models.py +49 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/registry_manager.py +166 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog/scraper.py +521 -0
- solace_agent_mesh/config_portal/backend/plugin_catalog_server.py +217 -0
- solace_agent_mesh/config_portal/backend/server.py +644 -0
- solace_agent_mesh/config_portal/frontend/static/client/Solace_community_logo.png +0 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-DiOiAjzL.js +103 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/components-Rk0n-9cK.js +140 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/entry.client-mvZjNKiz.js +19 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/index-DzNKzXrc.js +68 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-ba77705e.js +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-B17tZKK7.css +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-V2BeTIUc.js +10 -0
- solace_agent_mesh/config_portal/frontend/static/client/favicon.ico +0 -0
- solace_agent_mesh/config_portal/frontend/static/client/index.html +7 -0
- solace_agent_mesh/core_a2a/__init__.py +1 -0
- solace_agent_mesh/core_a2a/core_a2a_llm.txt +90 -0
- solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +101 -0
- solace_agent_mesh/core_a2a/service.py +307 -0
- solace_agent_mesh/evaluation/__init__.py +0 -0
- solace_agent_mesh/evaluation/evaluator.py +691 -0
- solace_agent_mesh/evaluation/message_organizer.py +553 -0
- solace_agent_mesh/evaluation/report/benchmark_info.html +35 -0
- solace_agent_mesh/evaluation/report/chart_section.html +141 -0
- solace_agent_mesh/evaluation/report/detailed_breakdown.html +28 -0
- solace_agent_mesh/evaluation/report/modal.html +59 -0
- solace_agent_mesh/evaluation/report/modal_chart_functions.js +411 -0
- solace_agent_mesh/evaluation/report/modal_script.js +296 -0
- solace_agent_mesh/evaluation/report/modal_styles.css +340 -0
- solace_agent_mesh/evaluation/report/performance_metrics_styles.css +93 -0
- solace_agent_mesh/evaluation/report/templates/footer.html +2 -0
- solace_agent_mesh/evaluation/report/templates/header.html +340 -0
- solace_agent_mesh/evaluation/report_data_processor.py +970 -0
- solace_agent_mesh/evaluation/report_generator.py +607 -0
- solace_agent_mesh/evaluation/run.py +954 -0
- 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 +776 -0
- solace_agent_mesh/evaluation/summary_builder.py +880 -0
- solace_agent_mesh/gateway/__init__.py +0 -0
- solace_agent_mesh/gateway/adapter/__init__.py +1 -0
- solace_agent_mesh/gateway/adapter/base.py +143 -0
- solace_agent_mesh/gateway/adapter/types.py +221 -0
- solace_agent_mesh/gateway/base/__init__.py +1 -0
- solace_agent_mesh/gateway/base/app.py +345 -0
- solace_agent_mesh/gateway/base/base_llm.txt +226 -0
- solace_agent_mesh/gateway/base/base_llm_detail.txt +235 -0
- solace_agent_mesh/gateway/base/component.py +2030 -0
- solace_agent_mesh/gateway/base/task_context.py +75 -0
- solace_agent_mesh/gateway/gateway_llm.txt +369 -0
- solace_agent_mesh/gateway/gateway_llm_detail.txt +3885 -0
- solace_agent_mesh/gateway/generic/__init__.py +1 -0
- solace_agent_mesh/gateway/generic/app.py +50 -0
- solace_agent_mesh/gateway/generic/component.py +727 -0
- solace_agent_mesh/gateway/http_sse/__init__.py +0 -0
- solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +345 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +87 -0
- solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20250910_d5b3f8f2e9a0_create_initial_database.py +58 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20250911_b1c2d3e4f5g6_add_database_indexes.py +83 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20250916_f6e7d8c9b0a1_convert_timestamps_to_epoch_and_align_columns.py +412 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251006_98882922fa59_add_tasks_events_feedback_chat_tasks.py +190 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251015_add_session_performance_indexes.py +70 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_project_users_table.py +72 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +109 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +26 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_projects_table.py +135 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251108_create_prompt_tables_with_sharing.py +154 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251115_add_parent_task_id.py +32 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251126_add_background_task_fields.py +47 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251202_add_versioned_fields_to_prompts.py +52 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +161 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +109 -0
- solace_agent_mesh/gateway/http_sse/app.py +351 -0
- solace_agent_mesh/gateway/http_sse/component.py +2360 -0
- solace_agent_mesh/gateway/http_sse/components/__init__.py +7 -0
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +105 -0
- solace_agent_mesh/gateway/http_sse/components/task_logger_forwarder.py +109 -0
- solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +110 -0
- solace_agent_mesh/gateway/http_sse/dependencies.py +653 -0
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +299 -0
- solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +3278 -0
- solace_agent_mesh/gateway/http_sse/main.py +789 -0
- solace_agent_mesh/gateway/http_sse/repository/__init__.py +46 -0
- solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +102 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/__init__.py +11 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/chat_task.py +75 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +221 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/feedback.py +20 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/project.py +81 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +47 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session.py +66 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session_history.py +0 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/task.py +32 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/task_event.py +21 -0
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +125 -0
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +239 -0
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +34 -0
- solace_agent_mesh/gateway/http_sse/repository/models/base.py +7 -0
- solace_agent_mesh/gateway/http_sse/repository/models/chat_task_model.py +31 -0
- solace_agent_mesh/gateway/http_sse/repository/models/feedback_model.py +21 -0
- solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +257 -0
- solace_agent_mesh/gateway/http_sse/repository/models/project_model.py +51 -0
- solace_agent_mesh/gateway/http_sse/repository/models/project_user_model.py +75 -0
- solace_agent_mesh/gateway/http_sse/repository/models/prompt_model.py +159 -0
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +53 -0
- solace_agent_mesh/gateway/http_sse/repository/models/task_event_model.py +25 -0
- solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +39 -0
- solace_agent_mesh/gateway/http_sse/repository/project_repository.py +172 -0
- solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +186 -0
- solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +308 -0
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +268 -0
- solace_agent_mesh/gateway/http_sse/repository/task_repository.py +248 -0
- solace_agent_mesh/gateway/http_sse/routers/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +74 -0
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +1137 -0
- solace_agent_mesh/gateway/http_sse/routers/auth.py +311 -0
- solace_agent_mesh/gateway/http_sse/routers/config.py +371 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/__init__.py +10 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +450 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/project_dto.py +69 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/prompt_dto.py +255 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +15 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/project_requests.py +48 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +133 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +33 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/task_requests.py +58 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/__init__.py +18 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/base_responses.py +42 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +31 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +123 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +33 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/task_responses.py +30 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/version_responses.py +31 -0
- solace_agent_mesh/gateway/http_sse/routers/feedback.py +168 -0
- solace_agent_mesh/gateway/http_sse/routers/people.py +38 -0
- solace_agent_mesh/gateway/http_sse/routers/projects.py +767 -0
- solace_agent_mesh/gateway/http_sse/routers/prompts.py +1415 -0
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +312 -0
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +634 -0
- solace_agent_mesh/gateway/http_sse/routers/speech.py +355 -0
- solace_agent_mesh/gateway/http_sse/routers/sse.py +230 -0
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +1089 -0
- solace_agent_mesh/gateway/http_sse/routers/users.py +83 -0
- solace_agent_mesh/gateway/http_sse/routers/version.py +343 -0
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +1220 -0
- solace_agent_mesh/gateway/http_sse/services/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/services/agent_card_service.py +71 -0
- solace_agent_mesh/gateway/http_sse/services/audio_service.py +1227 -0
- solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +186 -0
- solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +273 -0
- solace_agent_mesh/gateway/http_sse/services/feedback_service.py +250 -0
- solace_agent_mesh/gateway/http_sse/services/people_service.py +78 -0
- solace_agent_mesh/gateway/http_sse/services/project_service.py +930 -0
- solace_agent_mesh/gateway/http_sse/services/prompt_builder_assistant.py +303 -0
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +303 -0
- solace_agent_mesh/gateway/http_sse/services/session_service.py +702 -0
- solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +593 -0
- solace_agent_mesh/gateway/http_sse/services/task_service.py +119 -0
- solace_agent_mesh/gateway/http_sse/session_manager.py +219 -0
- solace_agent_mesh/gateway/http_sse/shared/__init__.py +146 -0
- solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
- solace_agent_mesh/gateway/http_sse/shared/base_repository.py +252 -0
- solace_agent_mesh/gateway/http_sse/shared/database_exceptions.py +274 -0
- solace_agent_mesh/gateway/http_sse/shared/database_helpers.py +43 -0
- solace_agent_mesh/gateway/http_sse/shared/enums.py +40 -0
- solace_agent_mesh/gateway/http_sse/shared/error_dto.py +107 -0
- solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +217 -0
- solace_agent_mesh/gateway/http_sse/shared/exceptions.py +192 -0
- solace_agent_mesh/gateway/http_sse/shared/pagination.py +138 -0
- solace_agent_mesh/gateway/http_sse/shared/response_utils.py +134 -0
- solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +319 -0
- solace_agent_mesh/gateway/http_sse/shared/timestamp_utils.py +97 -0
- solace_agent_mesh/gateway/http_sse/shared/types.py +50 -0
- solace_agent_mesh/gateway/http_sse/shared/utils.py +22 -0
- solace_agent_mesh/gateway/http_sse/sse_event_buffer.py +88 -0
- solace_agent_mesh/gateway/http_sse/sse_manager.py +491 -0
- solace_agent_mesh/gateway/http_sse/utils/__init__.py +1 -0
- solace_agent_mesh/gateway/http_sse/utils/artifact_copy_utils.py +370 -0
- solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +72 -0
- solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +47 -0
- solace_agent_mesh/llm.txt +228 -0
- solace_agent_mesh/llm_detail.txt +2835 -0
- solace_agent_mesh/services/__init__.py +0 -0
- solace_agent_mesh/services/platform/__init__.py +18 -0
- solace_agent_mesh/services/platform/alembic/env.py +85 -0
- solace_agent_mesh/services/platform/alembic/script.py.mako +28 -0
- solace_agent_mesh/services/platform/alembic.ini +109 -0
- solace_agent_mesh/services/platform/api/__init__.py +3 -0
- solace_agent_mesh/services/platform/api/dependencies.py +147 -0
- solace_agent_mesh/services/platform/api/main.py +280 -0
- solace_agent_mesh/services/platform/api/middleware.py +51 -0
- solace_agent_mesh/services/platform/api/routers/__init__.py +24 -0
- solace_agent_mesh/services/platform/app.py +114 -0
- solace_agent_mesh/services/platform/component.py +235 -0
- solace_agent_mesh/solace_agent_mesh_llm.txt +362 -0
- solace_agent_mesh/solace_agent_mesh_llm_detail.txt +8599 -0
- solace_agent_mesh/templates/agent_template.yaml +53 -0
- solace_agent_mesh/templates/eval_backend_template.yaml +54 -0
- solace_agent_mesh/templates/gateway_app_template.py +75 -0
- solace_agent_mesh/templates/gateway_component_template.py +484 -0
- solace_agent_mesh/templates/gateway_config_template.yaml +38 -0
- solace_agent_mesh/templates/logging_config_template.yaml +48 -0
- solace_agent_mesh/templates/main_orchestrator.yaml +66 -0
- solace_agent_mesh/templates/plugin_agent_config_template.yaml +122 -0
- solace_agent_mesh/templates/plugin_custom_config_template.yaml +27 -0
- solace_agent_mesh/templates/plugin_custom_template.py +10 -0
- solace_agent_mesh/templates/plugin_gateway_config_template.yaml +60 -0
- solace_agent_mesh/templates/plugin_pyproject_template.toml +32 -0
- solace_agent_mesh/templates/plugin_readme_template.md +12 -0
- solace_agent_mesh/templates/plugin_tool_config_template.yaml +109 -0
- solace_agent_mesh/templates/plugin_tools_template.py +224 -0
- solace_agent_mesh/templates/shared_config.yaml +112 -0
- solace_agent_mesh/templates/templates_llm.txt +147 -0
- solace_agent_mesh/templates/webui.yaml +177 -0
- solace_agent_mesh-1.11.2.dist-info/METADATA +504 -0
- solace_agent_mesh-1.11.2.dist-info/RECORD +624 -0
- solace_agent_mesh-1.11.2.dist-info/WHEEL +4 -0
- solace_agent_mesh-1.11.2.dist-info/entry_points.txt +3 -0
- solace_agent_mesh-1.11.2.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,1089 @@
|
|
|
1
|
+
"""
|
|
2
|
+
API Router for submitting and managing tasks to agents.
|
|
3
|
+
Includes background task status endpoints.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
import yaml
|
|
10
|
+
from a2a.types import (
|
|
11
|
+
CancelTaskRequest,
|
|
12
|
+
SendMessageRequest,
|
|
13
|
+
SendMessageSuccessResponse,
|
|
14
|
+
SendStreamingMessageRequest,
|
|
15
|
+
SendStreamingMessageSuccessResponse,
|
|
16
|
+
)
|
|
17
|
+
from fastapi import APIRouter, Depends, HTTPException, Query, Response, status
|
|
18
|
+
from fastapi import Request as FastAPIRequest
|
|
19
|
+
from pydantic import BaseModel
|
|
20
|
+
from sqlalchemy.orm import Session as DBSession
|
|
21
|
+
|
|
22
|
+
from ....gateway.http_sse.services.project_service import ProjectService
|
|
23
|
+
|
|
24
|
+
from ....agent.utils.artifact_helpers import (
|
|
25
|
+
get_artifact_info_list,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
from ....common import a2a
|
|
29
|
+
from ....gateway.http_sse.dependencies import (
|
|
30
|
+
get_db,
|
|
31
|
+
get_project_service_optional,
|
|
32
|
+
get_sac_component,
|
|
33
|
+
get_session_business_service,
|
|
34
|
+
get_session_manager,
|
|
35
|
+
get_task_repository,
|
|
36
|
+
get_task_service,
|
|
37
|
+
get_user_config,
|
|
38
|
+
get_user_id,
|
|
39
|
+
)
|
|
40
|
+
from ....gateway.http_sse.repository.entities import Task
|
|
41
|
+
from ....gateway.http_sse.repository.interfaces import ITaskRepository
|
|
42
|
+
from ....gateway.http_sse.repository.task_repository import TaskRepository
|
|
43
|
+
from ....gateway.http_sse.services.session_service import SessionService
|
|
44
|
+
from ....gateway.http_sse.services.task_service import TaskService
|
|
45
|
+
from ....gateway.http_sse.session_manager import SessionManager
|
|
46
|
+
from ....gateway.http_sse.shared.pagination import PaginationParams
|
|
47
|
+
from ....gateway.http_sse.shared.types import UserId
|
|
48
|
+
from ..utils.stim_utils import create_stim_from_task_data
|
|
49
|
+
|
|
50
|
+
if TYPE_CHECKING:
|
|
51
|
+
from ....gateway.http_sse.component import WebUIBackendComponent
|
|
52
|
+
|
|
53
|
+
router = APIRouter()
|
|
54
|
+
|
|
55
|
+
log = logging.getLogger(__name__)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Background Task Status Models and Endpoints
|
|
59
|
+
class TaskStatusResponse(BaseModel):
|
|
60
|
+
"""Response model for task status queries."""
|
|
61
|
+
task: Task
|
|
62
|
+
is_running: bool
|
|
63
|
+
is_background: bool
|
|
64
|
+
can_reconnect: bool
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@router.get("/tasks/{task_id}/status", response_model=TaskStatusResponse, tags=["Tasks"])
|
|
68
|
+
async def get_task_status(
|
|
69
|
+
task_id: str,
|
|
70
|
+
db: DBSession = Depends(get_db),
|
|
71
|
+
):
|
|
72
|
+
"""
|
|
73
|
+
Get the current status of a task.
|
|
74
|
+
Used by frontend to check if a background task is still running.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
task_id: The task ID to query
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Task status information including whether it's running and can be reconnected to
|
|
81
|
+
"""
|
|
82
|
+
log_prefix = f"[GET /api/v1/tasks/{task_id}/status] "
|
|
83
|
+
log.debug("%sQuerying task status", log_prefix)
|
|
84
|
+
|
|
85
|
+
repo = TaskRepository()
|
|
86
|
+
task = repo.find_by_id(db, task_id)
|
|
87
|
+
|
|
88
|
+
if not task:
|
|
89
|
+
raise HTTPException(status_code=404, detail=f"Task {task_id} not found")
|
|
90
|
+
|
|
91
|
+
# Determine if task is still running
|
|
92
|
+
is_running = task.status in [None, "running", "pending"] and task.end_time is None
|
|
93
|
+
|
|
94
|
+
# Check if it's a background task
|
|
95
|
+
is_background = task.background_execution_enabled or False
|
|
96
|
+
|
|
97
|
+
# Can reconnect if it's a background task and still running
|
|
98
|
+
can_reconnect = is_background and is_running
|
|
99
|
+
|
|
100
|
+
log.info(
|
|
101
|
+
"%sTask status: running=%s, background=%s, can_reconnect=%s",
|
|
102
|
+
log_prefix,
|
|
103
|
+
is_running,
|
|
104
|
+
is_background,
|
|
105
|
+
can_reconnect,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
return TaskStatusResponse(
|
|
109
|
+
task=task,
|
|
110
|
+
is_running=is_running,
|
|
111
|
+
is_background=is_background,
|
|
112
|
+
can_reconnect=can_reconnect
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@router.get("/tasks/background/active", tags=["Tasks"])
|
|
117
|
+
async def get_active_background_tasks(
|
|
118
|
+
user_id: str = Query(..., description="User ID to filter tasks"),
|
|
119
|
+
db: DBSession = Depends(get_db),
|
|
120
|
+
):
|
|
121
|
+
"""
|
|
122
|
+
Get all active background tasks for a user.
|
|
123
|
+
Used by frontend on session load to detect running background tasks.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
user_id: The user ID to filter by
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
List of active background tasks
|
|
130
|
+
"""
|
|
131
|
+
log_prefix = "[GET /api/v1/tasks/background/active] "
|
|
132
|
+
log.debug("%sQuerying active background tasks for user %s", log_prefix, user_id)
|
|
133
|
+
|
|
134
|
+
repo = TaskRepository()
|
|
135
|
+
|
|
136
|
+
# Get all background tasks
|
|
137
|
+
all_background_tasks = repo.find_background_tasks_by_status(db, status=None)
|
|
138
|
+
|
|
139
|
+
# Filter by user and running status
|
|
140
|
+
active_tasks = [
|
|
141
|
+
task for task in all_background_tasks
|
|
142
|
+
if task.user_id == user_id
|
|
143
|
+
and task.status in [None, "running", "pending"]
|
|
144
|
+
and task.end_time is None
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
log.info("%sFound %d active background tasks for user %s", log_prefix, len(active_tasks), user_id)
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
"tasks": active_tasks,
|
|
151
|
+
"count": len(active_tasks)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# =============================================================================
|
|
156
|
+
# Project Context Injection Helper
|
|
157
|
+
# =============================================================================
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
async def _inject_project_context(
|
|
161
|
+
project_id: str,
|
|
162
|
+
message_text: str,
|
|
163
|
+
user_id: str,
|
|
164
|
+
session_id: str,
|
|
165
|
+
project_service: ProjectService,
|
|
166
|
+
component: "WebUIBackendComponent",
|
|
167
|
+
log_prefix: str,
|
|
168
|
+
inject_full_context: bool = True,
|
|
169
|
+
) -> str:
|
|
170
|
+
"""
|
|
171
|
+
Helper function to inject project context and copy artifacts to session.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
inject_full_context: If True, injects full project context (name, description, instructions).
|
|
175
|
+
If False, only copies new artifacts without modifying message text.
|
|
176
|
+
This allows existing sessions to get new project files without
|
|
177
|
+
re-injecting the full context on every message.
|
|
178
|
+
|
|
179
|
+
Returns the modified message text with project context injected (if inject_full_context=True).
|
|
180
|
+
"""
|
|
181
|
+
if not project_id or not message_text:
|
|
182
|
+
return message_text
|
|
183
|
+
|
|
184
|
+
from ....gateway.http_sse.dependencies import SessionLocal
|
|
185
|
+
from ..utils.artifact_copy_utils import copy_project_artifacts_to_session
|
|
186
|
+
|
|
187
|
+
if SessionLocal is None:
|
|
188
|
+
log.warning(
|
|
189
|
+
"%sProject context injection skipped: database not configured", log_prefix
|
|
190
|
+
)
|
|
191
|
+
return message_text
|
|
192
|
+
|
|
193
|
+
db = SessionLocal()
|
|
194
|
+
artifact_service = None
|
|
195
|
+
should_clear_pending_flags = False
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
project = project_service.get_project(db, project_id, user_id)
|
|
199
|
+
if not project:
|
|
200
|
+
return message_text
|
|
201
|
+
|
|
202
|
+
context_parts = []
|
|
203
|
+
|
|
204
|
+
# Only inject full context for new sessions
|
|
205
|
+
if inject_full_context:
|
|
206
|
+
# Start with clear workspace framing
|
|
207
|
+
context_parts.append(
|
|
208
|
+
f'You are working in the project workspace: "{project.name}"'
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
# Add system prompt if exists
|
|
212
|
+
if project.system_prompt and project.system_prompt.strip():
|
|
213
|
+
context_parts.append(f"\n{project.system_prompt.strip()}")
|
|
214
|
+
|
|
215
|
+
# Add project description if exists
|
|
216
|
+
if project.description and project.description.strip():
|
|
217
|
+
context_parts.append(f"\nProject Description: {project.description.strip()}")
|
|
218
|
+
|
|
219
|
+
# Always copy project artifacts to session (for both new and existing sessions)
|
|
220
|
+
# This ensures new project files are available to existing sessions
|
|
221
|
+
artifact_service = component.get_shared_artifact_service()
|
|
222
|
+
if artifact_service:
|
|
223
|
+
try:
|
|
224
|
+
artifacts_copied, new_artifact_names = await copy_project_artifacts_to_session(
|
|
225
|
+
project_id=project_id,
|
|
226
|
+
user_id=user_id,
|
|
227
|
+
session_id=session_id,
|
|
228
|
+
project_service=project_service,
|
|
229
|
+
component=component,
|
|
230
|
+
db=db,
|
|
231
|
+
log_prefix=log_prefix,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
if inject_full_context and artifacts_copied > 0:
|
|
235
|
+
# need to clear the pending flags even if injection fails
|
|
236
|
+
should_clear_pending_flags = True
|
|
237
|
+
|
|
238
|
+
# Get artifact descriptions for context injection
|
|
239
|
+
if artifacts_copied > 0 or inject_full_context:
|
|
240
|
+
source_user_id = project.user_id
|
|
241
|
+
project_artifacts_session_id = f"project-{project.id}"
|
|
242
|
+
|
|
243
|
+
project_artifacts = await get_artifact_info_list(
|
|
244
|
+
artifact_service=artifact_service,
|
|
245
|
+
app_name=project_service.app_name,
|
|
246
|
+
user_id=source_user_id,
|
|
247
|
+
session_id=project_artifacts_session_id,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
if project_artifacts:
|
|
251
|
+
# For new sessions - all files
|
|
252
|
+
all_artifact_descriptions = []
|
|
253
|
+
# For existing sessions - only new files
|
|
254
|
+
new_artifact_descriptions = []
|
|
255
|
+
|
|
256
|
+
for artifact_info in project_artifacts:
|
|
257
|
+
# Build description for all artifacts (for new sessions)
|
|
258
|
+
desc_str = f"- {artifact_info.filename}"
|
|
259
|
+
if artifact_info.description:
|
|
260
|
+
desc_str += f": {artifact_info.description}"
|
|
261
|
+
all_artifact_descriptions.append(desc_str)
|
|
262
|
+
|
|
263
|
+
# Track new artifacts for existing sessions
|
|
264
|
+
if artifact_info.filename in new_artifact_names:
|
|
265
|
+
new_artifact_descriptions.append(desc_str)
|
|
266
|
+
|
|
267
|
+
# Add artifact descriptions to context
|
|
268
|
+
files_added_header = (
|
|
269
|
+
"\nNew Files Added to Session:\n"
|
|
270
|
+
"The following files have been added to your session (in addition to any files already present):\n"
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
if inject_full_context and all_artifact_descriptions:
|
|
274
|
+
# New session: show all project files
|
|
275
|
+
artifacts_context = files_added_header + "\n".join(all_artifact_descriptions)
|
|
276
|
+
context_parts.append(artifacts_context)
|
|
277
|
+
elif not inject_full_context and new_artifact_descriptions:
|
|
278
|
+
# Existing session: notify about newly added files
|
|
279
|
+
new_files_context = files_added_header + "\n".join(new_artifact_descriptions)
|
|
280
|
+
context_parts.append(new_files_context)
|
|
281
|
+
|
|
282
|
+
except Exception as e:
|
|
283
|
+
log.warning(
|
|
284
|
+
"%sFailed to copy project artifacts to session: %s", log_prefix, e
|
|
285
|
+
)
|
|
286
|
+
# Do not fail the entire request, just log the warning
|
|
287
|
+
|
|
288
|
+
# Inject all gathered context into the message, ending with user query
|
|
289
|
+
# Only modify message text if we're injecting full context (new sessions)
|
|
290
|
+
modified_message_text = message_text
|
|
291
|
+
if context_parts:
|
|
292
|
+
project_context = "\n".join(context_parts)
|
|
293
|
+
modified_message_text = f"{project_context}\n\nUSER QUERY:\n{message_text}"
|
|
294
|
+
log.debug("%sInjected full project context for project: %s", log_prefix, project_id)
|
|
295
|
+
else:
|
|
296
|
+
log.debug("%sSkipped full context injection for existing session, but ensured new artifacts are copied", log_prefix)
|
|
297
|
+
|
|
298
|
+
return modified_message_text
|
|
299
|
+
|
|
300
|
+
except Exception as e:
|
|
301
|
+
log.warning("%sFailed to inject project context: %s", log_prefix, e)
|
|
302
|
+
# Continue without injection - don't fail the request
|
|
303
|
+
return message_text
|
|
304
|
+
finally:
|
|
305
|
+
# Clear the pending project context flags from all artifacts
|
|
306
|
+
if should_clear_pending_flags and artifact_service:
|
|
307
|
+
from ..utils.artifact_copy_utils import clear_pending_project_context
|
|
308
|
+
try:
|
|
309
|
+
await clear_pending_project_context(
|
|
310
|
+
user_id=user_id,
|
|
311
|
+
session_id=session_id,
|
|
312
|
+
artifact_service=artifact_service,
|
|
313
|
+
app_name=project_service.app_name,
|
|
314
|
+
db=db,
|
|
315
|
+
log_prefix=log_prefix,
|
|
316
|
+
)
|
|
317
|
+
log.debug("%sCleared pending project context flags", log_prefix)
|
|
318
|
+
except Exception as e:
|
|
319
|
+
log.warning("%sFailed to clear pending project context flags: %s", log_prefix, e)
|
|
320
|
+
|
|
321
|
+
db.close()
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
async def _submit_task(
|
|
325
|
+
request: FastAPIRequest,
|
|
326
|
+
payload: SendMessageRequest | SendStreamingMessageRequest,
|
|
327
|
+
session_manager: SessionManager,
|
|
328
|
+
component: "WebUIBackendComponent",
|
|
329
|
+
project_service: ProjectService | None,
|
|
330
|
+
is_streaming: bool,
|
|
331
|
+
session_service: SessionService | None = None,
|
|
332
|
+
):
|
|
333
|
+
"""
|
|
334
|
+
Helper to submit a task, handling both streaming and non-streaming cases.
|
|
335
|
+
|
|
336
|
+
Also handles project context injection.
|
|
337
|
+
"""
|
|
338
|
+
log_prefix = f"[POST /api/v1/message:{'stream' if is_streaming else 'send'}] "
|
|
339
|
+
|
|
340
|
+
agent_name = None
|
|
341
|
+
project_id = None
|
|
342
|
+
if payload.params and payload.params.message and payload.params.message.metadata:
|
|
343
|
+
agent_name = payload.params.message.metadata.get("agent_name")
|
|
344
|
+
project_id = payload.params.message.metadata.get("project_id")
|
|
345
|
+
|
|
346
|
+
if not agent_name:
|
|
347
|
+
raise HTTPException(
|
|
348
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
349
|
+
detail="Missing 'agent_name' in request payload message metadata.",
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
log.info("%sReceived request for agent: %s", log_prefix, agent_name)
|
|
353
|
+
|
|
354
|
+
try:
|
|
355
|
+
user_identity = await component.authenticate_and_enrich_user(request)
|
|
356
|
+
if user_identity is None:
|
|
357
|
+
log.warning("%sUser authentication failed. Denying request.", log_prefix)
|
|
358
|
+
raise HTTPException(
|
|
359
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
360
|
+
detail="User authentication failed or identity not found.",
|
|
361
|
+
)
|
|
362
|
+
log.debug(
|
|
363
|
+
"%sAuthenticated user identity: %s",
|
|
364
|
+
log_prefix,
|
|
365
|
+
user_identity.get("id", "unknown"),
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
client_id = session_manager.get_a2a_client_id(request)
|
|
369
|
+
|
|
370
|
+
# Use session ID from frontend request (contextId per A2A spec) instead of cookie-based session
|
|
371
|
+
# Handle various falsy values: None, empty string, whitespace-only string
|
|
372
|
+
frontend_session_id = None
|
|
373
|
+
if (
|
|
374
|
+
hasattr(payload.params.message, "context_id")
|
|
375
|
+
and payload.params.message.context_id
|
|
376
|
+
):
|
|
377
|
+
context_id = payload.params.message.context_id
|
|
378
|
+
if isinstance(context_id, str) and context_id.strip():
|
|
379
|
+
frontend_session_id = context_id.strip()
|
|
380
|
+
|
|
381
|
+
user_id = user_identity.get("id")
|
|
382
|
+
from ....gateway.http_sse.dependencies import SessionLocal
|
|
383
|
+
|
|
384
|
+
# If project_id not in metadata, check if session has a project_id in database
|
|
385
|
+
# This handles cases where sessions are moved to projects after creation
|
|
386
|
+
if not project_id and session_service and frontend_session_id:
|
|
387
|
+
if SessionLocal is not None:
|
|
388
|
+
db = SessionLocal()
|
|
389
|
+
try:
|
|
390
|
+
session_details = session_service.get_session_details(
|
|
391
|
+
db, frontend_session_id, user_id
|
|
392
|
+
)
|
|
393
|
+
if session_details and session_details.project_id:
|
|
394
|
+
project_id = session_details.project_id
|
|
395
|
+
log.info(
|
|
396
|
+
"%sFound project_id %s from session database for session %s",
|
|
397
|
+
log_prefix,
|
|
398
|
+
project_id,
|
|
399
|
+
frontend_session_id,
|
|
400
|
+
)
|
|
401
|
+
except Exception as e:
|
|
402
|
+
log.warning(
|
|
403
|
+
"%sFailed to lookup session project_id: %s", log_prefix, e
|
|
404
|
+
)
|
|
405
|
+
finally:
|
|
406
|
+
db.close()
|
|
407
|
+
|
|
408
|
+
if frontend_session_id:
|
|
409
|
+
session_id = frontend_session_id
|
|
410
|
+
log.info(
|
|
411
|
+
"%sUsing session ID from frontend request: %s", log_prefix, session_id
|
|
412
|
+
)
|
|
413
|
+
else:
|
|
414
|
+
# Create new session when frontend doesn't provide one
|
|
415
|
+
session_id = session_manager.create_new_session_id(request)
|
|
416
|
+
log.debug(
|
|
417
|
+
"%sNo valid session ID from frontend, created new session: %s",
|
|
418
|
+
log_prefix,
|
|
419
|
+
session_id,
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
# Immediately create session in database if persistence is enabled
|
|
423
|
+
# This ensures the session exists before any other operations (like artifact listing)
|
|
424
|
+
if SessionLocal is not None and session_service is not None:
|
|
425
|
+
db = SessionLocal()
|
|
426
|
+
try:
|
|
427
|
+
session_service.create_session(
|
|
428
|
+
db=db,
|
|
429
|
+
user_id=user_id,
|
|
430
|
+
agent_id=agent_name,
|
|
431
|
+
session_id=session_id,
|
|
432
|
+
project_id=project_id,
|
|
433
|
+
)
|
|
434
|
+
db.commit()
|
|
435
|
+
log.debug(
|
|
436
|
+
"%sCreated session in database: %s", log_prefix, session_id
|
|
437
|
+
)
|
|
438
|
+
except Exception as e:
|
|
439
|
+
db.rollback()
|
|
440
|
+
log.warning(
|
|
441
|
+
"%sFailed to create session in database: %s", log_prefix, e
|
|
442
|
+
)
|
|
443
|
+
finally:
|
|
444
|
+
db.close()
|
|
445
|
+
|
|
446
|
+
log.info(
|
|
447
|
+
"%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
# Extract message text and apply project context injection
|
|
451
|
+
message_text = ""
|
|
452
|
+
if payload.params and payload.params.message:
|
|
453
|
+
parts = a2a.get_parts_from_message(payload.params.message)
|
|
454
|
+
for part in parts:
|
|
455
|
+
if hasattr(part, "text"):
|
|
456
|
+
message_text = part.text
|
|
457
|
+
break
|
|
458
|
+
|
|
459
|
+
# Project context injection - always inject for project sessions to ensure new files are available
|
|
460
|
+
# Skip if project_service is None (persistence disabled)
|
|
461
|
+
modified_message = payload.params.message
|
|
462
|
+
if project_service and project_id and message_text:
|
|
463
|
+
# Determine if we should inject full context:
|
|
464
|
+
should_inject_full_context = not frontend_session_id
|
|
465
|
+
|
|
466
|
+
# Check if there are artifacts with pending project context
|
|
467
|
+
if frontend_session_id and not should_inject_full_context:
|
|
468
|
+
from ..utils.artifact_copy_utils import has_pending_project_context
|
|
469
|
+
from ....gateway.http_sse.dependencies import SessionLocal
|
|
470
|
+
|
|
471
|
+
artifact_service = component.get_shared_artifact_service()
|
|
472
|
+
if artifact_service and SessionLocal:
|
|
473
|
+
db = SessionLocal()
|
|
474
|
+
try:
|
|
475
|
+
has_pending = await has_pending_project_context(
|
|
476
|
+
user_id=client_id,
|
|
477
|
+
session_id=session_id,
|
|
478
|
+
artifact_service=artifact_service,
|
|
479
|
+
app_name=component.gateway_id,
|
|
480
|
+
db=db,
|
|
481
|
+
)
|
|
482
|
+
if has_pending:
|
|
483
|
+
should_inject_full_context = True
|
|
484
|
+
log.info(
|
|
485
|
+
"%sDetected pending project context for session %s, will inject full context",
|
|
486
|
+
log_prefix,
|
|
487
|
+
session_id,
|
|
488
|
+
)
|
|
489
|
+
finally:
|
|
490
|
+
db.close()
|
|
491
|
+
|
|
492
|
+
modified_message_text = await _inject_project_context(
|
|
493
|
+
project_id=project_id,
|
|
494
|
+
message_text=message_text,
|
|
495
|
+
user_id=user_id,
|
|
496
|
+
session_id=session_id,
|
|
497
|
+
project_service=project_service,
|
|
498
|
+
component=component,
|
|
499
|
+
log_prefix=log_prefix,
|
|
500
|
+
inject_full_context=should_inject_full_context,
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
# Update the message with project context if it was modified
|
|
504
|
+
if modified_message_text != message_text:
|
|
505
|
+
# Create new text part with project context
|
|
506
|
+
new_text_part = a2a.create_text_part(modified_message_text)
|
|
507
|
+
|
|
508
|
+
# Get existing parts and replace the first text part with the modified one
|
|
509
|
+
existing_parts = a2a.get_parts_from_message(payload.params.message)
|
|
510
|
+
new_parts = []
|
|
511
|
+
text_part_replaced = False
|
|
512
|
+
|
|
513
|
+
for part in existing_parts:
|
|
514
|
+
if hasattr(part, "text") and not text_part_replaced:
|
|
515
|
+
new_parts.append(new_text_part)
|
|
516
|
+
text_part_replaced = True
|
|
517
|
+
else:
|
|
518
|
+
new_parts.append(part)
|
|
519
|
+
|
|
520
|
+
# If no text part was found, add the new text part at the beginning
|
|
521
|
+
if not text_part_replaced:
|
|
522
|
+
new_parts.insert(0, new_text_part)
|
|
523
|
+
|
|
524
|
+
# Update the message with the new parts
|
|
525
|
+
modified_message = a2a.update_message_parts(
|
|
526
|
+
payload.params.message, new_parts
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
# Use the helper to get the unwrapped parts from the modified message (with project context if applied).
|
|
530
|
+
a2a_parts = a2a.get_parts_from_message(modified_message)
|
|
531
|
+
|
|
532
|
+
external_req_ctx = {
|
|
533
|
+
"app_name_for_artifacts": component.gateway_id,
|
|
534
|
+
"user_id_for_artifacts": client_id,
|
|
535
|
+
"a2a_session_id": session_id, # This may have been updated by persistence layer
|
|
536
|
+
"user_id_for_a2a": client_id,
|
|
537
|
+
"target_agent_name": agent_name,
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
task_id = await component.submit_a2a_task(
|
|
541
|
+
target_agent_name=agent_name,
|
|
542
|
+
a2a_parts=a2a_parts,
|
|
543
|
+
external_request_context=external_req_ctx,
|
|
544
|
+
user_identity=user_identity,
|
|
545
|
+
is_streaming=is_streaming,
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
log.info("%sTask submitted successfully. TaskID: %s", log_prefix, task_id)
|
|
549
|
+
|
|
550
|
+
task_object = a2a.create_initial_task(
|
|
551
|
+
task_id=task_id,
|
|
552
|
+
context_id=session_id,
|
|
553
|
+
agent_name=agent_name,
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
if is_streaming:
|
|
557
|
+
# The task_object already contains the contextId from create_initial_task
|
|
558
|
+
return a2a.create_send_streaming_message_success_response(
|
|
559
|
+
result=task_object, request_id=payload.id
|
|
560
|
+
)
|
|
561
|
+
else:
|
|
562
|
+
return a2a.create_send_message_success_response(
|
|
563
|
+
result=task_object, request_id=payload.id
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
except PermissionError as pe:
|
|
567
|
+
log.warning("%sPermission denied: %s", log_prefix, str(pe))
|
|
568
|
+
raise HTTPException(
|
|
569
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
570
|
+
detail=str(pe),
|
|
571
|
+
)
|
|
572
|
+
except Exception as e:
|
|
573
|
+
log.exception("%sUnexpected error submitting task: %s", log_prefix, e)
|
|
574
|
+
error_resp = a2a.create_internal_error(
|
|
575
|
+
message="Unexpected server error: %s" % e
|
|
576
|
+
)
|
|
577
|
+
raise HTTPException(
|
|
578
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
579
|
+
detail=error_resp.model_dump(exclude_none=True),
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
@router.get("/tasks", response_model=list[Task], tags=["Tasks"])
|
|
584
|
+
async def search_tasks(
|
|
585
|
+
request: FastAPIRequest,
|
|
586
|
+
start_date: str | None = None,
|
|
587
|
+
end_date: str | None = None,
|
|
588
|
+
page: int = 1,
|
|
589
|
+
page_size: int = 20,
|
|
590
|
+
query_user_id: str | None = None,
|
|
591
|
+
db: DBSession = Depends(get_db),
|
|
592
|
+
user_id: UserId = Depends(get_user_id),
|
|
593
|
+
user_config: dict = Depends(get_user_config),
|
|
594
|
+
repo: ITaskRepository = Depends(get_task_repository),
|
|
595
|
+
):
|
|
596
|
+
"""
|
|
597
|
+
Lists and filters historical tasks by date.
|
|
598
|
+
- Regular users can only view their own tasks.
|
|
599
|
+
- Users with the 'tasks:read:all' scope can view any user's tasks by providing `query_user_id`.
|
|
600
|
+
"""
|
|
601
|
+
log_prefix = "[GET /api/v1/tasks] "
|
|
602
|
+
log.info("%sRequest from user %s", log_prefix, user_id)
|
|
603
|
+
|
|
604
|
+
target_user_id = user_id
|
|
605
|
+
can_query_all = user_config.get("scopes", {}).get("tasks:read:all", False)
|
|
606
|
+
|
|
607
|
+
if query_user_id:
|
|
608
|
+
if can_query_all:
|
|
609
|
+
target_user_id = query_user_id
|
|
610
|
+
log.info(
|
|
611
|
+
"%sAdmin user %s is querying for user %s",
|
|
612
|
+
log_prefix,
|
|
613
|
+
user_id,
|
|
614
|
+
target_user_id,
|
|
615
|
+
)
|
|
616
|
+
else:
|
|
617
|
+
raise HTTPException(
|
|
618
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
619
|
+
detail="You do not have permission to query for other users' tasks.",
|
|
620
|
+
)
|
|
621
|
+
elif can_query_all:
|
|
622
|
+
target_user_id = "*"
|
|
623
|
+
log.info("%sAdmin user %s is querying for all users.", log_prefix, user_id)
|
|
624
|
+
|
|
625
|
+
start_time_ms = None
|
|
626
|
+
if start_date:
|
|
627
|
+
try:
|
|
628
|
+
start_time_ms = int(datetime.fromisoformat(start_date).timestamp() * 1000)
|
|
629
|
+
except ValueError:
|
|
630
|
+
raise HTTPException(
|
|
631
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
632
|
+
detail="Invalid start_date format. Use ISO 8601 format.",
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
end_time_ms = None
|
|
636
|
+
if end_date:
|
|
637
|
+
try:
|
|
638
|
+
end_time_ms = int(datetime.fromisoformat(end_date).timestamp() * 1000)
|
|
639
|
+
except ValueError:
|
|
640
|
+
raise HTTPException(
|
|
641
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
642
|
+
detail="Invalid end_date format. Use ISO 8601 format.",
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
pagination = PaginationParams(page_number=page, page_size=page_size)
|
|
646
|
+
|
|
647
|
+
try:
|
|
648
|
+
tasks = repo.search(
|
|
649
|
+
db,
|
|
650
|
+
user_id=target_user_id,
|
|
651
|
+
start_date=start_time_ms,
|
|
652
|
+
end_date=end_time_ms,
|
|
653
|
+
pagination=pagination,
|
|
654
|
+
)
|
|
655
|
+
return tasks
|
|
656
|
+
except Exception as e:
|
|
657
|
+
log.exception("%sError searching for tasks: %s", log_prefix, e)
|
|
658
|
+
raise HTTPException(
|
|
659
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
660
|
+
detail="An error occurred while searching for tasks.",
|
|
661
|
+
)
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
@router.get("/tasks/{task_id}/events", tags=["Tasks"])
|
|
665
|
+
async def get_task_events(
|
|
666
|
+
task_id: str,
|
|
667
|
+
request: FastAPIRequest,
|
|
668
|
+
db: DBSession = Depends(get_db),
|
|
669
|
+
user_id: UserId = Depends(get_user_id),
|
|
670
|
+
user_config: dict = Depends(get_user_config),
|
|
671
|
+
repo: ITaskRepository = Depends(get_task_repository),
|
|
672
|
+
):
|
|
673
|
+
"""
|
|
674
|
+
Retrieves the complete event history for a task and all its child tasks as JSON.
|
|
675
|
+
Returns events in the same format as the SSE stream for workflow visualization.
|
|
676
|
+
Recursively loads all descendant tasks to enable full workflow rendering.
|
|
677
|
+
"""
|
|
678
|
+
log_prefix = f"[GET /api/v1/tasks/{task_id}/events] "
|
|
679
|
+
log.info("%sRequest from user %s", log_prefix, user_id)
|
|
680
|
+
|
|
681
|
+
try:
|
|
682
|
+
result = repo.find_by_id_with_events(db, task_id)
|
|
683
|
+
if not result:
|
|
684
|
+
raise HTTPException(
|
|
685
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
686
|
+
detail=f"Task with ID '{task_id}' not found.",
|
|
687
|
+
)
|
|
688
|
+
|
|
689
|
+
task, events = result
|
|
690
|
+
|
|
691
|
+
can_read_all = user_config.get("scopes", {}).get("tasks:read:all", False)
|
|
692
|
+
if task.user_id != user_id and not can_read_all:
|
|
693
|
+
raise HTTPException(
|
|
694
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
695
|
+
detail="You do not have permission to view this task.",
|
|
696
|
+
)
|
|
697
|
+
|
|
698
|
+
# Transform task events into A2AEventSSEPayload format for the frontend
|
|
699
|
+
# Need to reconstruct the SSE structure from stored data
|
|
700
|
+
formatted_events = []
|
|
701
|
+
|
|
702
|
+
for event in events:
|
|
703
|
+
# event.payload contains the raw A2A JSON-RPC message
|
|
704
|
+
# event.created_time is epoch milliseconds
|
|
705
|
+
# event.direction is simplified (request, response, status, error, etc)
|
|
706
|
+
|
|
707
|
+
# Convert timestamp from epoch milliseconds to ISO 8601
|
|
708
|
+
from datetime import datetime, timezone
|
|
709
|
+
timestamp_dt = datetime.fromtimestamp(event.created_time / 1000, tz=timezone.utc)
|
|
710
|
+
timestamp_iso = timestamp_dt.isoformat()
|
|
711
|
+
|
|
712
|
+
# Extract metadata from payload using similar logic to SSE component
|
|
713
|
+
payload = event.payload
|
|
714
|
+
message_id = payload.get("id")
|
|
715
|
+
source_entity = "unknown"
|
|
716
|
+
target_entity = "unknown"
|
|
717
|
+
method = "N/A"
|
|
718
|
+
|
|
719
|
+
# Parse based on direction
|
|
720
|
+
if event.direction == "request":
|
|
721
|
+
# It's a request - extract target from message metadata
|
|
722
|
+
method = payload.get("method", "N/A")
|
|
723
|
+
if "params" in payload and "message" in payload.get("params", {}):
|
|
724
|
+
message = payload["params"]["message"]
|
|
725
|
+
if isinstance(message, dict) and "metadata" in message:
|
|
726
|
+
target_entity = message["metadata"].get("agent_name", "unknown")
|
|
727
|
+
elif event.direction in ["status", "response", "error"]:
|
|
728
|
+
# It's a response - extract source from result metadata
|
|
729
|
+
if "result" in payload:
|
|
730
|
+
result = payload["result"]
|
|
731
|
+
if isinstance(result, dict):
|
|
732
|
+
# Check for agent_name in metadata
|
|
733
|
+
if "metadata" in result:
|
|
734
|
+
source_entity = result["metadata"].get("agent_name", "unknown")
|
|
735
|
+
# For status updates, check the message inside
|
|
736
|
+
if "message" in result:
|
|
737
|
+
message = result["message"]
|
|
738
|
+
if isinstance(message, dict) and "metadata" in message:
|
|
739
|
+
if source_entity == "unknown":
|
|
740
|
+
source_entity = message["metadata"].get("agent_name", "unknown")
|
|
741
|
+
|
|
742
|
+
# Map stored direction to SSE direction format
|
|
743
|
+
direction_map = {
|
|
744
|
+
"request": "request",
|
|
745
|
+
"response": "task",
|
|
746
|
+
"status": "status-update",
|
|
747
|
+
"error": "error_response",
|
|
748
|
+
}
|
|
749
|
+
sse_direction = direction_map.get(event.direction, event.direction)
|
|
750
|
+
|
|
751
|
+
# Build the A2AEventSSEPayload structure
|
|
752
|
+
formatted_event = {
|
|
753
|
+
"event_type": "a2a_message",
|
|
754
|
+
"timestamp": timestamp_iso,
|
|
755
|
+
"solace_topic": event.topic,
|
|
756
|
+
"direction": sse_direction,
|
|
757
|
+
"source_entity": source_entity,
|
|
758
|
+
"target_entity": target_entity,
|
|
759
|
+
"message_id": message_id,
|
|
760
|
+
"task_id": task_id,
|
|
761
|
+
"payload_summary": {
|
|
762
|
+
"method": method,
|
|
763
|
+
"params_preview": None,
|
|
764
|
+
},
|
|
765
|
+
"full_payload": payload,
|
|
766
|
+
}
|
|
767
|
+
formatted_events.append(formatted_event)
|
|
768
|
+
|
|
769
|
+
# Use database-level query to get all related tasks efficiently
|
|
770
|
+
related_task_ids = repo.find_all_by_parent_chain(db, task_id)
|
|
771
|
+
log.info(
|
|
772
|
+
"%sFound %d related tasks for task_id %s",
|
|
773
|
+
log_prefix,
|
|
774
|
+
len(related_task_ids),
|
|
775
|
+
task_id,
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
# Load and format all related tasks
|
|
779
|
+
all_tasks = {}
|
|
780
|
+
all_tasks[task_id] = {
|
|
781
|
+
"events": formatted_events,
|
|
782
|
+
"initial_request_text": task.initial_request_text or "",
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
# Load remaining related tasks
|
|
786
|
+
for tid in related_task_ids:
|
|
787
|
+
if tid == task_id:
|
|
788
|
+
continue # Already loaded
|
|
789
|
+
|
|
790
|
+
task_result = repo.find_by_id_with_events(db, tid)
|
|
791
|
+
if not task_result:
|
|
792
|
+
continue
|
|
793
|
+
|
|
794
|
+
related_task, related_events = task_result
|
|
795
|
+
|
|
796
|
+
# Check permissions for each related task
|
|
797
|
+
if related_task.user_id != user_id and not can_read_all:
|
|
798
|
+
log.warning(
|
|
799
|
+
"%sSkipping related task %s due to permission check",
|
|
800
|
+
log_prefix,
|
|
801
|
+
tid,
|
|
802
|
+
)
|
|
803
|
+
continue
|
|
804
|
+
|
|
805
|
+
# Format events for this related task
|
|
806
|
+
related_formatted_events = []
|
|
807
|
+
|
|
808
|
+
for event in related_events:
|
|
809
|
+
from datetime import datetime, timezone
|
|
810
|
+
|
|
811
|
+
timestamp_dt = datetime.fromtimestamp(
|
|
812
|
+
event.created_time / 1000, tz=timezone.utc
|
|
813
|
+
)
|
|
814
|
+
timestamp_iso = timestamp_dt.isoformat()
|
|
815
|
+
payload = event.payload
|
|
816
|
+
message_id = payload.get("id")
|
|
817
|
+
source_entity = "unknown"
|
|
818
|
+
target_entity = "unknown"
|
|
819
|
+
method = "N/A"
|
|
820
|
+
|
|
821
|
+
if event.direction == "request":
|
|
822
|
+
method = payload.get("method", "N/A")
|
|
823
|
+
if "params" in payload and "message" in payload.get("params", {}):
|
|
824
|
+
message = payload["params"]["message"]
|
|
825
|
+
if isinstance(message, dict) and "metadata" in message:
|
|
826
|
+
target_entity = message["metadata"].get(
|
|
827
|
+
"agent_name", "unknown"
|
|
828
|
+
)
|
|
829
|
+
elif event.direction in ["status", "response", "error"]:
|
|
830
|
+
if "result" in payload:
|
|
831
|
+
result = payload["result"]
|
|
832
|
+
if isinstance(result, dict):
|
|
833
|
+
if "metadata" in result:
|
|
834
|
+
source_entity = result["metadata"].get(
|
|
835
|
+
"agent_name", "unknown"
|
|
836
|
+
)
|
|
837
|
+
if "message" in result:
|
|
838
|
+
message = result["message"]
|
|
839
|
+
if isinstance(message, dict) and "metadata" in message:
|
|
840
|
+
if source_entity == "unknown":
|
|
841
|
+
source_entity = message["metadata"].get(
|
|
842
|
+
"agent_name", "unknown"
|
|
843
|
+
)
|
|
844
|
+
|
|
845
|
+
direction_map = {
|
|
846
|
+
"request": "request",
|
|
847
|
+
"response": "task",
|
|
848
|
+
"status": "status-update",
|
|
849
|
+
"error": "error_response",
|
|
850
|
+
}
|
|
851
|
+
sse_direction = direction_map.get(event.direction, event.direction)
|
|
852
|
+
|
|
853
|
+
formatted_event = {
|
|
854
|
+
"event_type": "a2a_message",
|
|
855
|
+
"timestamp": timestamp_iso,
|
|
856
|
+
"solace_topic": event.topic,
|
|
857
|
+
"direction": sse_direction,
|
|
858
|
+
"source_entity": source_entity,
|
|
859
|
+
"target_entity": target_entity,
|
|
860
|
+
"message_id": message_id,
|
|
861
|
+
"task_id": tid,
|
|
862
|
+
"payload_summary": {"method": method, "params_preview": None},
|
|
863
|
+
"full_payload": payload,
|
|
864
|
+
}
|
|
865
|
+
related_formatted_events.append(formatted_event)
|
|
866
|
+
|
|
867
|
+
all_tasks[tid] = {
|
|
868
|
+
"events": related_formatted_events,
|
|
869
|
+
"initial_request_text": related_task.initial_request_text or "",
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
# Return all tasks (parent + children) for the frontend to process
|
|
873
|
+
return {"tasks": all_tasks}
|
|
874
|
+
|
|
875
|
+
except HTTPException:
|
|
876
|
+
# Re-raise HTTPExceptions (404, 403, etc.) without modification
|
|
877
|
+
raise
|
|
878
|
+
except Exception as e:
|
|
879
|
+
log.exception("%sError retrieving task events: %s", log_prefix, e)
|
|
880
|
+
raise HTTPException(
|
|
881
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
882
|
+
detail="An error occurred while retrieving the task events.",
|
|
883
|
+
)
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
@router.get("/tasks/{task_id}", tags=["Tasks"])
|
|
887
|
+
async def get_task_as_stim_file(
|
|
888
|
+
task_id: str,
|
|
889
|
+
request: FastAPIRequest,
|
|
890
|
+
db: DBSession = Depends(get_db),
|
|
891
|
+
user_id: UserId = Depends(get_user_id),
|
|
892
|
+
user_config: dict = Depends(get_user_config),
|
|
893
|
+
repo: ITaskRepository = Depends(get_task_repository),
|
|
894
|
+
):
|
|
895
|
+
"""
|
|
896
|
+
Retrieves the complete event history for a task and all its child tasks, returning it as a `.stim` file.
|
|
897
|
+
"""
|
|
898
|
+
log_prefix = f"[GET /api/v1/tasks/{task_id}] "
|
|
899
|
+
log.info("%sRequest from user %s", log_prefix, user_id)
|
|
900
|
+
|
|
901
|
+
try:
|
|
902
|
+
# Find all related task IDs (parent chain + all children)
|
|
903
|
+
related_task_ids = repo.find_all_by_parent_chain(db, task_id)
|
|
904
|
+
|
|
905
|
+
if not related_task_ids:
|
|
906
|
+
raise HTTPException(
|
|
907
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
908
|
+
detail=f"Task with ID '{task_id}' not found.",
|
|
909
|
+
)
|
|
910
|
+
|
|
911
|
+
# Load all tasks and their events
|
|
912
|
+
tasks_dict = {}
|
|
913
|
+
events_dict = {}
|
|
914
|
+
can_read_all = user_config.get("scopes", {}).get("tasks:read:all", False)
|
|
915
|
+
|
|
916
|
+
for tid in related_task_ids:
|
|
917
|
+
result = repo.find_by_id_with_events(db, tid)
|
|
918
|
+
if result:
|
|
919
|
+
task, events = result
|
|
920
|
+
|
|
921
|
+
# Check permissions for each task
|
|
922
|
+
if task.user_id != user_id and not can_read_all:
|
|
923
|
+
raise HTTPException(
|
|
924
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
925
|
+
detail="You do not have permission to view this task.",
|
|
926
|
+
)
|
|
927
|
+
|
|
928
|
+
tasks_dict[tid] = task
|
|
929
|
+
events_dict[tid] = events
|
|
930
|
+
|
|
931
|
+
if task_id not in tasks_dict:
|
|
932
|
+
raise HTTPException(
|
|
933
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
934
|
+
detail=f"Task with ID '{task_id}' not found.",
|
|
935
|
+
)
|
|
936
|
+
|
|
937
|
+
# Determine the root task (the one without a parent)
|
|
938
|
+
root_task_id = task_id
|
|
939
|
+
for tid, task in tasks_dict.items():
|
|
940
|
+
if task.parent_task_id is None:
|
|
941
|
+
root_task_id = tid
|
|
942
|
+
break
|
|
943
|
+
|
|
944
|
+
# Format into .stim structure with all tasks
|
|
945
|
+
from ..utils.stim_utils import create_stim_from_task_hierarchy
|
|
946
|
+
stim_data = create_stim_from_task_hierarchy(tasks_dict, events_dict, root_task_id)
|
|
947
|
+
|
|
948
|
+
yaml_content = yaml.dump(
|
|
949
|
+
stim_data,
|
|
950
|
+
sort_keys=False,
|
|
951
|
+
allow_unicode=True,
|
|
952
|
+
indent=2,
|
|
953
|
+
default_flow_style=False,
|
|
954
|
+
)
|
|
955
|
+
|
|
956
|
+
return Response(
|
|
957
|
+
content=yaml_content,
|
|
958
|
+
media_type="application/yaml",
|
|
959
|
+
headers={"Content-Disposition": f'attachment; filename="{root_task_id}.stim"'},
|
|
960
|
+
)
|
|
961
|
+
|
|
962
|
+
except HTTPException:
|
|
963
|
+
# Re-raise HTTPExceptions (404, 403, etc.) without modification
|
|
964
|
+
raise
|
|
965
|
+
except Exception as e:
|
|
966
|
+
log.exception("%sError retrieving task: %s", log_prefix, e)
|
|
967
|
+
raise HTTPException(
|
|
968
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
969
|
+
detail="An error occurred while retrieving the task.",
|
|
970
|
+
)
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
@router.post("/message:send", response_model=SendMessageSuccessResponse)
|
|
974
|
+
async def send_task_to_agent(
|
|
975
|
+
request: FastAPIRequest,
|
|
976
|
+
payload: SendMessageRequest,
|
|
977
|
+
session_manager: SessionManager = Depends(get_session_manager),
|
|
978
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
979
|
+
project_service: ProjectService | None = Depends(get_project_service_optional),
|
|
980
|
+
):
|
|
981
|
+
"""
|
|
982
|
+
Submits a non-streaming task request to the specified agent.
|
|
983
|
+
Accepts application/json.
|
|
984
|
+
"""
|
|
985
|
+
return await _submit_task(
|
|
986
|
+
request=request,
|
|
987
|
+
payload=payload,
|
|
988
|
+
session_manager=session_manager,
|
|
989
|
+
component=component,
|
|
990
|
+
project_service=project_service,
|
|
991
|
+
is_streaming=False,
|
|
992
|
+
session_service=None,
|
|
993
|
+
)
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
@router.post("/message:stream", response_model=SendStreamingMessageSuccessResponse)
|
|
997
|
+
async def subscribe_task_from_agent(
|
|
998
|
+
request: FastAPIRequest,
|
|
999
|
+
payload: SendStreamingMessageRequest,
|
|
1000
|
+
session_manager: SessionManager = Depends(get_session_manager),
|
|
1001
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
1002
|
+
project_service: ProjectService | None = Depends(get_project_service_optional),
|
|
1003
|
+
session_service: SessionService = Depends(get_session_business_service),
|
|
1004
|
+
):
|
|
1005
|
+
"""
|
|
1006
|
+
Submits a streaming task request to the specified agent.
|
|
1007
|
+
Accepts application/json.
|
|
1008
|
+
The client should subsequently connect to the SSE endpoint using the returned taskId.
|
|
1009
|
+
"""
|
|
1010
|
+
return await _submit_task(
|
|
1011
|
+
request=request,
|
|
1012
|
+
payload=payload,
|
|
1013
|
+
session_manager=session_manager,
|
|
1014
|
+
component=component,
|
|
1015
|
+
project_service=project_service,
|
|
1016
|
+
is_streaming=True,
|
|
1017
|
+
session_service=session_service,
|
|
1018
|
+
)
|
|
1019
|
+
|
|
1020
|
+
|
|
1021
|
+
@router.post("/tasks/{taskId}:cancel", status_code=status.HTTP_202_ACCEPTED)
|
|
1022
|
+
async def cancel_agent_task(
|
|
1023
|
+
request: FastAPIRequest,
|
|
1024
|
+
taskId: str,
|
|
1025
|
+
payload: CancelTaskRequest,
|
|
1026
|
+
session_manager: SessionManager = Depends(get_session_manager),
|
|
1027
|
+
task_service: TaskService = Depends(get_task_service),
|
|
1028
|
+
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
1029
|
+
):
|
|
1030
|
+
"""
|
|
1031
|
+
Sends a cancellation request for a specific task to the specified agent.
|
|
1032
|
+
Returns 202 Accepted, as cancellation is asynchronous.
|
|
1033
|
+
Returns 404 if the task context is not found.
|
|
1034
|
+
"""
|
|
1035
|
+
log_prefix = f"[POST /api/v1/tasks/{taskId}:cancel] "
|
|
1036
|
+
log.info("%sReceived cancellation request.", log_prefix)
|
|
1037
|
+
|
|
1038
|
+
if taskId != payload.params.id:
|
|
1039
|
+
raise HTTPException(
|
|
1040
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
1041
|
+
detail="Task ID in URL path does not match task ID in payload.",
|
|
1042
|
+
)
|
|
1043
|
+
|
|
1044
|
+
context = component.task_context_manager.get_context(taskId)
|
|
1045
|
+
if not context:
|
|
1046
|
+
log.warning(
|
|
1047
|
+
"%sNo active task context found for task ID: %s",
|
|
1048
|
+
log_prefix,
|
|
1049
|
+
taskId,
|
|
1050
|
+
)
|
|
1051
|
+
raise HTTPException(
|
|
1052
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
1053
|
+
detail=f"No active task context found for task ID: {taskId}",
|
|
1054
|
+
)
|
|
1055
|
+
|
|
1056
|
+
agent_name = context.get("target_agent_name")
|
|
1057
|
+
if not agent_name:
|
|
1058
|
+
log.error(
|
|
1059
|
+
"%sCould not determine target agent for task %s. Context is missing 'target_agent_name'.",
|
|
1060
|
+
log_prefix,
|
|
1061
|
+
taskId,
|
|
1062
|
+
)
|
|
1063
|
+
raise HTTPException(
|
|
1064
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
1065
|
+
detail="Could not determine target agent for the task.",
|
|
1066
|
+
)
|
|
1067
|
+
|
|
1068
|
+
log.info("%sTarget agent for cancellation is '%s'", log_prefix, agent_name)
|
|
1069
|
+
|
|
1070
|
+
try:
|
|
1071
|
+
client_id = session_manager.get_a2a_client_id(request)
|
|
1072
|
+
|
|
1073
|
+
log.info("%sUsing ClientID: %s", log_prefix, client_id)
|
|
1074
|
+
|
|
1075
|
+
await task_service.cancel_task(agent_name, taskId, client_id, client_id)
|
|
1076
|
+
|
|
1077
|
+
log.info("%sCancellation request published successfully.", log_prefix)
|
|
1078
|
+
|
|
1079
|
+
return {"message": "Cancellation request sent"}
|
|
1080
|
+
|
|
1081
|
+
except Exception as e:
|
|
1082
|
+
log.exception("%sUnexpected error sending cancellation: %s", log_prefix, e)
|
|
1083
|
+
error_resp = a2a.create_internal_error(
|
|
1084
|
+
message="Unexpected server error: %s" % e
|
|
1085
|
+
)
|
|
1086
|
+
raise HTTPException(
|
|
1087
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
1088
|
+
detail=error_resp.model_dump(exclude_none=True),
|
|
1089
|
+
)
|