solace-agent-mesh 1.6.3__py3-none-any.whl → 1.7.1__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/adk_llm.txt +12 -18
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +1 -1
- solace_agent_mesh/agent/adk/callbacks.py +138 -20
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +2 -0
- solace_agent_mesh/agent/adk/models/lite_llm.py +38 -5
- solace_agent_mesh/agent/adk/models/models_llm.txt +82 -35
- solace_agent_mesh/agent/adk/runner.py +9 -0
- solace_agent_mesh/agent/adk/stream_parser.py +6 -1
- solace_agent_mesh/agent/adk/tool_wrapper.py +3 -0
- solace_agent_mesh/agent/agent_llm.txt +61 -70
- solace_agent_mesh/agent/protocol/event_handlers.py +29 -1
- solace_agent_mesh/agent/protocol/protocol_llm.txt +1 -1
- solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +190 -0
- solace_agent_mesh/agent/proxies/base/base_llm.txt +148 -0
- solace_agent_mesh/agent/proxies/proxies_llm.txt +283 -0
- solace_agent_mesh/agent/sac/app.py +22 -0
- solace_agent_mesh/agent/sac/component.py +76 -40
- solace_agent_mesh/agent/sac/sac_llm.txt +1 -1
- solace_agent_mesh/agent/sac/task_execution_context.py +21 -0
- solace_agent_mesh/agent/testing/testing_llm.txt +2 -1
- solace_agent_mesh/agent/tools/builtin_artifact_tools.py +13 -148
- solace_agent_mesh/agent/tools/dynamic_tool.py +2 -0
- solace_agent_mesh/agent/tools/tools_llm.txt +93 -80
- solace_agent_mesh/agent/tools/tools_llm_detail.txt +3 -2
- solace_agent_mesh/agent/utils/artifact_helpers.py +4 -0
- solace_agent_mesh/agent/utils/utils_llm.txt +16 -2
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/05749d90.c70b2be9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15e40e79.36003774.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2987107d.a80604f9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.e4870a49.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.b63ee53a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.45b32c2b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/631738c7.fa471607.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6a520c9d.b6e3f2ce.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.a5b36a60.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/71da7b71.374b9d54.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8b032486.91a91afc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/94e8668d.09ed9234.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{ab9708a8.3e6dd091.js → ab9708a8.245ae0ef.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/ad87452a.9d73dad6.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.f902fad8.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/dd817ffc.c37a755e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd81e2b8.b682e9c2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/de915948.44a432bc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e04b235d.c9c50c7b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.d11c67a7.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{e6f9706b.e74a984d.js → e6f9706b.045d0fa1.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.5099c51e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ff4d71f2.74710fc1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.f213fe0c.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.d9606d6a.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +18 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/components/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +196 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +6 -7
- solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +4 -4
- 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 +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +160 -169
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +59 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +62 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +10 -6
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +440 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +27 -4
- 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 +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +5 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +3 -3
- 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 +9 -9
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +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 +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +3 -3
- solace_agent_mesh/assets/docs/lunr-index-1762283454666.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1762283454666.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/docs_cmd.py +4 -1
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-D4_RMYRh.js → authCallback-tcIFZLis.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-UZ3qU6Bq.js → client-CRYdKo2Q.js} +3 -3
- solace_agent_mesh/client/webui/frontend/static/assets/main-CojeY_1w.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-ILja9MCG.js +353 -0
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-CINwxvwV.js +470 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
- solace_agent_mesh/common/a2a/a2a_llm.txt +13 -20
- solace_agent_mesh/common/a2a/protocol.py +5 -0
- solace_agent_mesh/common/a2a/types.py +1 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +49 -11
- solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +23 -6
- solace_agent_mesh/common/a2a_spec/schemas/feedback_event.json +51 -0
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +26 -9
- solace_agent_mesh/common/common_llm.txt +13 -34
- solace_agent_mesh/common/data_parts.py +20 -4
- solace_agent_mesh/common/middleware/middleware_llm.txt +1 -1
- solace_agent_mesh/common/sac/sac_llm.txt +1 -1
- solace_agent_mesh/common/sam_events/sam_events_llm.txt +1 -1
- solace_agent_mesh/common/services/employee_service.py +1 -1
- solace_agent_mesh/common/services/providers/providers_llm.txt +3 -2
- solace_agent_mesh/common/services/services_llm.txt +9 -4
- solace_agent_mesh/common/utils/embeds/constants.py +1 -0
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +1 -1
- solace_agent_mesh/common/utils/embeds/modifiers.py +2 -1
- solace_agent_mesh/common/utils/embeds/resolver.py +58 -6
- solace_agent_mesh/common/utils/embeds/types.py +8 -0
- solace_agent_mesh/common/utils/utils_llm.txt +5 -6
- solace_agent_mesh/core_a2a/core_a2a_llm.txt +1 -1
- 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/app.py +29 -2
- solace_agent_mesh/gateway/base/base_llm.txt +10 -8
- solace_agent_mesh/gateway/base/component.py +573 -142
- solace_agent_mesh/gateway/gateway_llm.txt +55 -59
- 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 +650 -0
- solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +99 -49
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_fulltext_search_indexes.py +92 -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 +150 -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/versions_llm.txt +26 -20
- solace_agent_mesh/gateway/http_sse/app.py +0 -14
- solace_agent_mesh/gateway/http_sse/component.py +17 -56
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +1 -1
- solace_agent_mesh/gateway/http_sse/dependencies.py +21 -3
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +8 -8
- solace_agent_mesh/gateway/http_sse/main.py +23 -5
- solace_agent_mesh/gateway/http_sse/repository/__init__.py +19 -1
- solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +56 -98
- 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 +23 -1
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +47 -0
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +112 -4
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -1
- solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +51 -60
- 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/session_model.py +7 -1
- solace_agent_mesh/gateway/http_sse/repository/project_repository.py +172 -0
- solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +186 -0
- solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +125 -157
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +269 -8
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +143 -51
- solace_agent_mesh/gateway/http_sse/routers/config.py +69 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +198 -94
- 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 +68 -18
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +13 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +30 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +51 -35
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +2 -0
- solace_agent_mesh/gateway/http_sse/routers/feedback.py +133 -2
- solace_agent_mesh/gateway/http_sse/routers/projects.py +542 -0
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +9 -11
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +154 -3
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +296 -4
- solace_agent_mesh/gateway/http_sse/services/project_service.py +403 -0
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +16 -10
- solace_agent_mesh/gateway/http_sse/services/session_service.py +178 -6
- solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +2 -3
- solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +48 -14
- solace_agent_mesh/solace_agent_mesh_llm.txt +1 -1
- {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/METADATA +3 -5
- {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/RECORD +218 -175
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.76654dd9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/631738c7.7c4594c9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/71da7b71.ddbdfbe2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/8024126c.56e59919.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/94e8668d.3b883666.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/da0b5bad.d08a9466.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.6b9493d0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e92d0134.4f395c6b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.720d2ef2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.ed05b14d.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.a8a75e0b.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1761744323675.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1761744323675.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main--3yJYl7S.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-DojKHS49.js +0 -342
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-DSqhjwq_.js +0 -405
- /solace_agent_mesh/assets/docs/assets/js/{main.ed05b14d.js.LICENSE.txt → main.f213fe0c.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -11,6 +11,7 @@ Once initialized, the `AppLlmAgent` (a custom agent class) is managed by the `ru
|
|
|
11
11
|
- **Direct files:**
|
|
12
12
|
- `__init__.py`: Standard Python package initializer
|
|
13
13
|
- `adk_llm.txt`: Documentation file containing developer guide content
|
|
14
|
+
- `adk_llm_detail.txt`: Concatenated LLM summary file from all subdirectories
|
|
14
15
|
- `app_llm_agent.py`: Defines a custom `LlmAgent` subclass that holds a reference to its host component
|
|
15
16
|
- `callbacks.py`: Provides a rich set of ADK callback functions for dynamic instructions, metadata injection, and Solace integration
|
|
16
17
|
- `embed_resolving_mcp_toolset.py`: Custom MCPToolset that resolves embeds in tool parameters before calling MCP tools
|
|
@@ -158,10 +159,11 @@ from solace_agent_mesh.agent.adk.artifacts.s3_artifact_service import S3Artifact
|
|
|
158
159
|
|
|
159
160
|
#### models/
|
|
160
161
|
**Purpose:** Contains concrete `BaseLlm` implementations for interfacing with various LLM providers
|
|
161
|
-
**Key Exports:** `LiteLlm` class for broad model provider compatibility
|
|
162
|
+
**Key Exports:** `LiteLlm` class for broad model provider compatibility, `OAuth2ClientCredentialsTokenManager` for OAuth authentication
|
|
162
163
|
**Import Examples:**
|
|
163
164
|
```python
|
|
164
165
|
from solace_agent_mesh.agent.adk.models.lite_llm import LiteLlm
|
|
166
|
+
from solace_agent_mesh.agent.adk.models.oauth2_token_manager import OAuth2ClientCredentialsTokenManager
|
|
165
167
|
```
|
|
166
168
|
|
|
167
169
|
## Complete Usage Guide
|
|
@@ -198,7 +200,8 @@ from solace_agent_mesh.agent.adk.models.lite_llm import LiteLlm
|
|
|
198
200
|
llm = LiteLlm(
|
|
199
201
|
model="gpt-4-turbo",
|
|
200
202
|
temperature=0.7,
|
|
201
|
-
max_completion_tokens=1000
|
|
203
|
+
max_completion_tokens=1000,
|
|
204
|
+
cache_strategy="5m"
|
|
202
205
|
)
|
|
203
206
|
|
|
204
207
|
# Anthropic
|
|
@@ -212,21 +215,12 @@ llm = LiteLlm(
|
|
|
212
215
|
model="gemini-pro",
|
|
213
216
|
temperature=0.3
|
|
214
217
|
)
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### 3. Artifact Service Usage
|
|
218
218
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
artifact_service = FilesystemArtifactService(base_path="/tmp/artifacts")
|
|
226
|
-
|
|
227
|
-
# Or initialize S3 artifact service
|
|
228
|
-
artifact_service = S3ArtifactService(bucket_name="my-artifacts-bucket")
|
|
229
|
-
|
|
230
|
-
# Save an artifact
|
|
219
|
+
# With OAuth authentication
|
|
220
|
+
llm = LiteLlm(
|
|
221
|
+
model="custom-model",
|
|
222
|
+
oauth_token_url="https://auth.example.com/oauth/token",
|
|
223
|
+
oauth_client_id="your-client-id",
|
|
224
|
+
oauth_client_secret="your-client-secret",
|
|
231
225
|
|
|
232
|
-
# content_hash:
|
|
226
|
+
# content_hash: c689f024368fe41a8310f8060beb396353bdb6708fb095fd2a1857ab21e68b50
|
|
@@ -170,13 +170,40 @@ async def process_artifact_blocks_callback(
|
|
|
170
170
|
event.params,
|
|
171
171
|
)
|
|
172
172
|
filename = event.params.get("filename", "unknown_artifact")
|
|
173
|
+
if filename == "unknown_artifact":
|
|
174
|
+
log.warning(
|
|
175
|
+
"%s Fenced artifact block started without a 'filename' parameter.",
|
|
176
|
+
log_identifier,
|
|
177
|
+
)
|
|
178
|
+
description = event.params.get("description")
|
|
179
|
+
if filename == "unknown_artifact":
|
|
180
|
+
log.warning(
|
|
181
|
+
"%s Fenced artifact block started without a 'filename' parameter.",
|
|
182
|
+
log_identifier,
|
|
183
|
+
)
|
|
173
184
|
if a2a_context:
|
|
185
|
+
status_text = f"Receiving artifact `{filename}`..."
|
|
186
|
+
if description:
|
|
187
|
+
status_text = (
|
|
188
|
+
f"Receiving artifact `{filename}`: {description}"
|
|
189
|
+
)
|
|
174
190
|
progress_data = AgentProgressUpdateData(
|
|
175
|
-
status_text=
|
|
191
|
+
status_text=status_text
|
|
176
192
|
)
|
|
177
193
|
await _publish_data_part_status_update(
|
|
178
194
|
host_component, a2a_context, progress_data
|
|
179
195
|
)
|
|
196
|
+
# Also send an initial in-progress event to create the UI bubble
|
|
197
|
+
artifact_progress_data = ArtifactCreationProgressData(
|
|
198
|
+
filename=filename,
|
|
199
|
+
description=description,
|
|
200
|
+
status="in-progress",
|
|
201
|
+
bytes_transferred=0,
|
|
202
|
+
artifact_chunk=None,
|
|
203
|
+
)
|
|
204
|
+
await _publish_data_part_status_update(
|
|
205
|
+
host_component, a2a_context, artifact_progress_data
|
|
206
|
+
)
|
|
180
207
|
params_str = " ".join(
|
|
181
208
|
[f'{k}="{v}"' for k, v in event.params.items()]
|
|
182
209
|
)
|
|
@@ -189,12 +216,19 @@ async def process_artifact_blocks_callback(
|
|
|
189
216
|
log_identifier,
|
|
190
217
|
event.buffered_size,
|
|
191
218
|
)
|
|
192
|
-
params =
|
|
219
|
+
params = event.params
|
|
193
220
|
filename = params.get("filename", "unknown_artifact")
|
|
221
|
+
if filename == "unknown_artifact":
|
|
222
|
+
log.warning(
|
|
223
|
+
"%s Fenced artifact block progressed without a 'filename' parameter.",
|
|
224
|
+
log_identifier,
|
|
225
|
+
)
|
|
194
226
|
if a2a_context:
|
|
195
227
|
progress_data = ArtifactCreationProgressData(
|
|
196
228
|
filename=filename,
|
|
197
|
-
|
|
229
|
+
description=params.get("description"),
|
|
230
|
+
status="in-progress",
|
|
231
|
+
bytes_transferred=event.buffered_size,
|
|
198
232
|
artifact_chunk=event.chunk,
|
|
199
233
|
)
|
|
200
234
|
await _publish_data_part_status_update(
|
|
@@ -236,6 +270,18 @@ async def process_artifact_blocks_callback(
|
|
|
236
270
|
"original_text": original_text,
|
|
237
271
|
}
|
|
238
272
|
)
|
|
273
|
+
if a2a_context:
|
|
274
|
+
if not filename or not filename.strip():
|
|
275
|
+
filename = "unknown_artifact"
|
|
276
|
+
progress_data = ArtifactCreationProgressData(
|
|
277
|
+
filename=filename or "unknown_artifact",
|
|
278
|
+
description=params.get("description"),
|
|
279
|
+
status="failed",
|
|
280
|
+
bytes_transferred=0,
|
|
281
|
+
)
|
|
282
|
+
await _publish_data_part_status_update(
|
|
283
|
+
host_component, a2a_context, progress_data
|
|
284
|
+
)
|
|
239
285
|
continue
|
|
240
286
|
|
|
241
287
|
kwargs_for_call = {
|
|
@@ -257,7 +303,6 @@ async def process_artifact_blocks_callback(
|
|
|
257
303
|
log_identifier,
|
|
258
304
|
params["schema_max_keys"],
|
|
259
305
|
)
|
|
260
|
-
|
|
261
306
|
wrapped_creator = ADKToolWrapper(
|
|
262
307
|
original_func=_internal_create_artifact,
|
|
263
308
|
tool_config=None, # No specific config for this internal tool
|
|
@@ -299,9 +344,33 @@ async def process_artifact_blocks_callback(
|
|
|
299
344
|
log_identifier,
|
|
300
345
|
e_track,
|
|
301
346
|
)
|
|
347
|
+
# Publish completion status immediately via SSE
|
|
348
|
+
if a2a_context:
|
|
349
|
+
progress_data = ArtifactCreationProgressData(
|
|
350
|
+
filename=filename,
|
|
351
|
+
description=params.get("description"),
|
|
352
|
+
status="completed",
|
|
353
|
+
bytes_transferred=len(event.content),
|
|
354
|
+
mime_type=params.get("mime_type"),
|
|
355
|
+
version=version_for_tool,
|
|
356
|
+
)
|
|
357
|
+
await _publish_data_part_status_update(
|
|
358
|
+
host_component, a2a_context, progress_data
|
|
359
|
+
)
|
|
302
360
|
else:
|
|
303
361
|
status_for_tool = "error"
|
|
304
362
|
version_for_tool = 0
|
|
363
|
+
# Publish failure status immediately via SSE
|
|
364
|
+
if a2a_context:
|
|
365
|
+
progress_data = ArtifactCreationProgressData(
|
|
366
|
+
filename=filename,
|
|
367
|
+
description=params.get("description"),
|
|
368
|
+
status="failed",
|
|
369
|
+
bytes_transferred=len(event.content),
|
|
370
|
+
)
|
|
371
|
+
await _publish_data_part_status_update(
|
|
372
|
+
host_component, a2a_context, progress_data
|
|
373
|
+
)
|
|
305
374
|
|
|
306
375
|
session.state["completed_artifact_blocks_list"].append(
|
|
307
376
|
{
|
|
@@ -347,6 +416,11 @@ async def process_artifact_blocks_callback(
|
|
|
347
416
|
)
|
|
348
417
|
params = event.params
|
|
349
418
|
filename = params.get("filename", "unknown_artifact")
|
|
419
|
+
if filename == "unknown_artifact":
|
|
420
|
+
log.warning(
|
|
421
|
+
"%s Unterminated fenced artifact block is missing a valid 'filename'. Failing operation.",
|
|
422
|
+
log_identifier,
|
|
423
|
+
)
|
|
350
424
|
if (
|
|
351
425
|
"completed_artifact_blocks_list" not in session.state
|
|
352
426
|
or session.state["completed_artifact_blocks_list"] is None
|
|
@@ -775,21 +849,55 @@ def _generate_fenced_artifact_instruction() -> str:
|
|
|
775
849
|
close_delim = ARTIFACT_BLOCK_DELIMITER_CLOSE
|
|
776
850
|
return f"""\
|
|
777
851
|
**Creating Text-Based Artifacts:**
|
|
778
|
-
To create an artifact from content you generate (like code, a report, or a document), you MUST use a special `save_artifact` block. This is the only reliable way to ensure your content is saved correctly.
|
|
779
852
|
|
|
780
|
-
**
|
|
853
|
+
**When to Create Text-based Artifacts:**
|
|
854
|
+
Create an artifact when the content provides value as a standalone file:
|
|
855
|
+
- Content with special formatting (HTML, Markdown, CSS, structured markup) that requires proper rendering
|
|
856
|
+
- Content explicitly intended for use outside this conversation (reports, emails, presentations, reference documents)
|
|
857
|
+
- Structured reference content users will save or follow (schedules, guides, templates)
|
|
858
|
+
- Content that will be edited, expanded, or reused
|
|
859
|
+
- Substantial text documents
|
|
860
|
+
- Technical documentation meant as reference material
|
|
861
|
+
|
|
862
|
+
**When NOT to Create Text-based Artifacts:**
|
|
863
|
+
- Simple answers, explanations, or conversational responses
|
|
864
|
+
- Brief advice, opinions, or quick information
|
|
865
|
+
- Short lists, summaries, or single paragraphs
|
|
866
|
+
- Temporary content only relevant to the immediate conversation
|
|
867
|
+
- Basic explanations that don't require reference material
|
|
868
|
+
|
|
869
|
+
**Behaviour of created artifacts:**
|
|
870
|
+
- they are sent back to the UI inline with the text and show up as an interactive file component
|
|
871
|
+
- the user can easily see the content so there is no need to return or embed it again.
|
|
872
|
+
- do not embed the same artifact again, since the user already has it to expand and view
|
|
873
|
+
|
|
874
|
+
**How to create artifacts:**
|
|
875
|
+
To create an artifact from content you generate (like code, a report, or a document), you MUST use a fenced artifact block with the EXACT syntax shown below. This is the only reliable way to ensure your content is saved correctly.
|
|
876
|
+
|
|
877
|
+
**EXACT SYNTAX (copy this pattern exactly):**
|
|
781
878
|
{open_delim}save_artifact: filename="your_filename.ext" mime_type="text/plain" description="A brief description."
|
|
782
879
|
The full content you want to save goes here.
|
|
783
880
|
It can span multiple lines.
|
|
784
881
|
{close_delim}
|
|
785
882
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
883
|
+
**CRITICAL FORMATTING RULES:**
|
|
884
|
+
1. The opening delimiter MUST be EXACTLY three angle brackets: `{open_delim}` (not `{open_delim[0:2]}` or `{open_delim[0:1]}`)
|
|
885
|
+
2. Immediately after the opening delimiter, write `save_artifact:` with a colon and NO space before the colon
|
|
886
|
+
3. Parameters (filename, mime_type, description) must be on the SAME line as the opening delimiter
|
|
887
|
+
4. All parameter values **MUST** be enclosed in double quotes: `filename="example.txt"`
|
|
888
|
+
5. You **MUST NOT** use double quotes `"` inside parameter values. Use single quotes or rephrase instead
|
|
889
|
+
6. After all parameters, press enter/newline, then write your content
|
|
890
|
+
7. Close the block with EXACTLY three angle brackets: `{close_delim}` on its own line
|
|
891
|
+
8. Do NOT surround the block with triple backticks (```). The delimiters `{open_delim}` and `{close_delim}` are sufficient
|
|
892
|
+
|
|
893
|
+
**COMMON ERRORS TO AVOID:**
|
|
894
|
+
❌ WRONG: `{open_delim[0:2]}save_artifact:` (only 2 angle brackets)
|
|
895
|
+
❌ WRONG: `{open_delim[0:1]}save_artifact:` (only 1 angle bracket)
|
|
896
|
+
❌ WRONG: `{open_delim}save_artifact` (missing colon)
|
|
897
|
+
✅ CORRECT: `{open_delim}save_artifact: filename="test.txt" mime_type="text/plain"`
|
|
898
|
+
|
|
899
|
+
The system will automatically save the content and give you a confirmation in the next turn by way of an automatically injected _notify_artifact_save tool call.
|
|
900
|
+
"""
|
|
793
901
|
|
|
794
902
|
|
|
795
903
|
def _generate_artifact_creation_instruction() -> str:
|
|
@@ -828,7 +936,7 @@ def _generate_embed_instruction(
|
|
|
828
936
|
)
|
|
829
937
|
|
|
830
938
|
base_instruction = f"""\
|
|
831
|
-
You can use dynamic embeds in your text responses and tool parameters using the syntax {open_delim}type:expression {chain_delim} format{close_delim}. This allows you to
|
|
939
|
+
You can use dynamic embeds in your text responses and tool parameters using the syntax {open_delim}type:expression {chain_delim} format{close_delim}. NOTE that this differs from 'save_artifact', which has different delimiters. This allows you to
|
|
832
940
|
always have correct information in your output. Specifically, make sure you always use embeds for math, even if it is simple. You will make mistakes if you try to do math yourself.
|
|
833
941
|
Use HTML entities to escape the delimiters.
|
|
834
942
|
This host resolves the following embed types *early* (before sending to the LLM or tool): {early_types}. This means the embed is replaced with its resolved value.
|
|
@@ -836,10 +944,18 @@ This host resolves the following embed types *early* (before sending to the LLM
|
|
|
836
944
|
- `{open_delim}datetime:format_or_keyword{close_delim}`: Inserts current date/time. Use Python strftime format (e.g., `%Y-%m-%d`) or keywords (`iso`, `timestamp`, `date`, `time`, `now`).
|
|
837
945
|
- `{open_delim}uuid:{close_delim}`: Inserts a random UUID.
|
|
838
946
|
- `{open_delim}artifact_meta:filename[:version]{close_delim}`: Inserts a summary of the artifact's metadata (latest version if unspecified).
|
|
839
|
-
- `{open_delim}status_update:Your message here{close_delim}`: Generates an immediate, distinct status message event that is displayed to the user (e.g., 'Thinking...', 'Searching database...'). This message appears in a status area, not as part of the main chat conversation. Use this to provide interim feedback during processing.
|
|
947
|
+
- `{open_delim}status_update:Your message here{close_delim}`: Generates an immediate, distinct status message event that is displayed to the user (e.g., 'Thinking...', 'Searching database...'). This message appears in a status area, not as part of the main chat conversation. Use this to provide interim feedback during processing.
|
|
948
|
+
|
|
949
|
+
Examples:
|
|
950
|
+
- `{open_delim}status_update:Analyzing data...{close_delim}` (Shows 'Analyzing data...' as a status update)
|
|
951
|
+
- `The result of 23.5 * 4.2 is {open_delim}math:23.5 * 4.2 | .2f{close_delim}` (Embeds calculated result with 2 decimal places)
|
|
952
|
+
|
|
953
|
+
The following embeds are resolved *late* (by the gateway before final display):
|
|
954
|
+
- `{open_delim}artifact_return:filename[:version]{close_delim}`: **This is the primary way to return an artifact to the user.** It attaches the specified artifact to the message. The embed itself is removed from the text. Use this instead of describing a file and expecting the user to download it. Note: artifact_return is not necessary if the artifact was just created by you in this same response, since newly created artifacts are automatically attached to your message."""
|
|
840
955
|
|
|
841
956
|
artifact_content_instruction = f"""
|
|
842
957
|
- `{open_delim}artifact_content:filename[:version] {chain_delim} modifier1:value1 {chain_delim} ... {chain_delim} format:output_format{close_delim}`: Embeds artifact content after applying a chain of modifiers. This is resolved *late* (typically by a gateway before final display).
|
|
958
|
+
- If this embed resolves to binary content (like an image), it will be automatically converted into an attached file, similar to `artifact_return`.
|
|
843
959
|
- Use `{chain_delim}` to separate the artifact identifier from the modifier steps and the final format step.
|
|
844
960
|
- Available modifiers: {modifier_list}.
|
|
845
961
|
- The `format:output_format` step *must* be the last step in the chain. Supported formats include `text`, `datauri`, `json`, `json_pretty`, `csv`. Formatting as datauri, will include the data URI prefix, so do not add it yourself.
|
|
@@ -860,7 +976,8 @@ This host resolves the following embed types *early* (before sending to the LLM
|
|
|
860
976
|
- `{open_delim}artifact_content:products.csv {chain_delim} apply_to_template:product_table.html.mustache {chain_delim} format:text{close_delim}` (CSV is auto-parsed to `headers` and `data_rows` for the HTML template)
|
|
861
977
|
- `{open_delim}artifact_content:config.json {chain_delim} jsonpath:$.userPreferences.theme {chain_delim} format:text{close_delim}` (Extract a single value from a JSON artifact)
|
|
862
978
|
- `{open_delim}artifact_content:sensor_readings.csv {chain_delim} filter_rows_eq:status:critical {chain_delim} select_cols:timestamp,sensor_id,value {chain_delim} format:csv{close_delim}` (Filter critical sensor readings and select specific columns, output as CSV)
|
|
863
|
-
- `{open_delim}artifact_content:server.log {chain_delim} tail:100 {chain_delim} grep:WARN {chain_delim} format:text{close_delim}` (Get warning lines from the last 100 lines of a log file)
|
|
979
|
+
- `{open_delim}artifact_content:server.log {chain_delim} tail:100 {chain_delim} grep:WARN {chain_delim} format:text{close_delim}` (Get warning lines from the last 100 lines of a log file)
|
|
980
|
+
"""
|
|
864
981
|
|
|
865
982
|
final_instruction = base_instruction
|
|
866
983
|
if include_artifact_content:
|
|
@@ -882,6 +999,10 @@ def _generate_tool_instructions_from_registry(
|
|
|
882
999
|
|
|
883
1000
|
instructions_by_category = defaultdict(list)
|
|
884
1001
|
for tool in sorted(active_tools, key=lambda t: (t.category, t.name)):
|
|
1002
|
+
# Skip internal tools (those starting with underscore)
|
|
1003
|
+
if tool.name.startswith("_"):
|
|
1004
|
+
continue
|
|
1005
|
+
|
|
885
1006
|
param_parts = []
|
|
886
1007
|
if tool.parameters and tool.parameters.properties:
|
|
887
1008
|
for name, schema in tool.parameters.properties.items():
|
|
@@ -947,15 +1068,12 @@ Simple, direct requests like 'create an image of a dog' or 'write an email to th
|
|
|
947
1068
|
|
|
948
1069
|
If a plan is created:
|
|
949
1070
|
1. It should be a terse, hierarchical list describing the steps needed, with each checkbox item on its own line.
|
|
950
|
-
2. Use '
|
|
1071
|
+
2. Use '⬜' for pending items, '✅' for completed items, and '❌' for cancelled items.
|
|
951
1072
|
3. If the plan changes significantly during execution, restate the updated plan.
|
|
952
1073
|
4. As items are completed, update the plan to check them off.
|
|
953
1074
|
|
|
954
1075
|
"""
|
|
955
1076
|
injected_instructions.append(planning_instruction)
|
|
956
|
-
log.debug("%s Added hardcoded planning instructions.", log_identifier)
|
|
957
|
-
artifact_creation_instruction = _generate_artifact_creation_instruction()
|
|
958
|
-
injected_instructions.append(artifact_creation_instruction)
|
|
959
1077
|
fenced_artifact_instruction = _generate_fenced_artifact_instruction()
|
|
960
1078
|
injected_instructions.append(fenced_artifact_instruction)
|
|
961
1079
|
|
|
@@ -23,6 +23,7 @@ from ...common.utils.embeds import (
|
|
|
23
23
|
evaluate_embed,
|
|
24
24
|
resolve_embeds_in_string,
|
|
25
25
|
)
|
|
26
|
+
from ...common.utils.embeds.types import ResolutionMode
|
|
26
27
|
from ..utils.context_helpers import get_original_session_id
|
|
27
28
|
|
|
28
29
|
log = logging.getLogger(__name__)
|
|
@@ -184,6 +185,7 @@ class EmbedResolvingMCPTool(_BaseMcpToolClass):
|
|
|
184
185
|
context=resolution_context,
|
|
185
186
|
resolver_func=evaluate_embed,
|
|
186
187
|
types_to_resolve=EARLY_EMBED_TYPES.union(LATE_EMBED_TYPES),
|
|
188
|
+
resolution_mode=ResolutionMode.TOOL_PARAMETER,
|
|
187
189
|
log_identifier=log_identifier,
|
|
188
190
|
config=self._tool_config,
|
|
189
191
|
)
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import base64
|
|
18
|
+
import hashlib
|
|
18
19
|
import json
|
|
19
20
|
import logging
|
|
20
21
|
from typing import Any
|
|
@@ -144,6 +145,38 @@ def _safe_json_serialize(obj) -> str:
|
|
|
144
145
|
return str(obj)
|
|
145
146
|
|
|
146
147
|
|
|
148
|
+
def _truncate_tool_call_id(tool_call_id: str, max_length: int = 40) -> str:
|
|
149
|
+
"""Truncates tool call ID to meet OpenAI's maximum length requirement.
|
|
150
|
+
|
|
151
|
+
OpenAI requires tool_call_id to be at most 40 characters. If the ID exceeds
|
|
152
|
+
this limit, we create a deterministic hash-based truncation to ensure:
|
|
153
|
+
1. The ID stays within the limit
|
|
154
|
+
2. The same input always produces the same output (deterministic)
|
|
155
|
+
3. Collisions are extremely unlikely
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
tool_call_id: The original tool call ID
|
|
159
|
+
max_length: Maximum allowed length (default: 40 for OpenAI)
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Truncated tool call ID that meets the length requirement
|
|
163
|
+
"""
|
|
164
|
+
if len(tool_call_id) <= max_length:
|
|
165
|
+
return tool_call_id
|
|
166
|
+
|
|
167
|
+
# Use first part of ID + hash of full ID to maintain uniqueness
|
|
168
|
+
# Format: prefix_hash where prefix is from original and hash ensures uniqueness
|
|
169
|
+
prefix_length = max_length - 33 # Reserve 33 chars for hash (32) + underscore (1)
|
|
170
|
+
if prefix_length < 1:
|
|
171
|
+
prefix_length = 1
|
|
172
|
+
|
|
173
|
+
prefix = tool_call_id[:prefix_length]
|
|
174
|
+
# Use SHA256 and take first 32 hex characters for uniqueness
|
|
175
|
+
hash_suffix = hashlib.sha256(tool_call_id.encode()).hexdigest()[:32]
|
|
176
|
+
|
|
177
|
+
return f"{prefix}_{hash_suffix}"
|
|
178
|
+
|
|
179
|
+
|
|
147
180
|
def _content_to_message_param(
|
|
148
181
|
content: types.Content,
|
|
149
182
|
) -> Union[Message, list[Message]]:
|
|
@@ -165,7 +198,7 @@ def _content_to_message_param(
|
|
|
165
198
|
tool_messages.append(
|
|
166
199
|
ChatCompletionToolMessage(
|
|
167
200
|
role="tool",
|
|
168
|
-
tool_call_id=part.function_response.id,
|
|
201
|
+
tool_call_id=_truncate_tool_call_id(part.function_response.id),
|
|
169
202
|
content=_safe_json_serialize(part.function_response.response),
|
|
170
203
|
)
|
|
171
204
|
)
|
|
@@ -185,7 +218,7 @@ def _content_to_message_param(
|
|
|
185
218
|
tool_calls.append(
|
|
186
219
|
ChatCompletionAssistantToolCall(
|
|
187
220
|
type="function",
|
|
188
|
-
id=part.function_call.id,
|
|
221
|
+
id=_truncate_tool_call_id(part.function_call.id),
|
|
189
222
|
function=Function(
|
|
190
223
|
name=part.function_call.name,
|
|
191
224
|
arguments=_safe_json_serialize(part.function_call.args),
|
|
@@ -464,7 +497,7 @@ def _message_to_generate_content_response(
|
|
|
464
497
|
name=tool_call.function.name,
|
|
465
498
|
args=json.loads(tool_call.function.arguments or "{}"),
|
|
466
499
|
)
|
|
467
|
-
part.function_call.id = tool_call.id
|
|
500
|
+
part.function_call.id = _truncate_tool_call_id(tool_call.id)
|
|
468
501
|
parts.append(part)
|
|
469
502
|
except json.JSONDecodeError as e:
|
|
470
503
|
logger.error(
|
|
@@ -887,7 +920,7 @@ class LiteLlm(BaseLlm):
|
|
|
887
920
|
tool_calls.append(
|
|
888
921
|
ChatCompletionMessageToolCall(
|
|
889
922
|
type="function",
|
|
890
|
-
id=func_data["id"],
|
|
923
|
+
id=_truncate_tool_call_id(func_data["id"]),
|
|
891
924
|
function=Function(
|
|
892
925
|
name=func_data["name"],
|
|
893
926
|
arguments=func_data["args"],
|
|
@@ -916,7 +949,7 @@ class LiteLlm(BaseLlm):
|
|
|
916
949
|
tool_calls.append(
|
|
917
950
|
ChatCompletionMessageToolCall(
|
|
918
951
|
type="function",
|
|
919
|
-
id=func_data["id"],
|
|
952
|
+
id=_truncate_tool_call_id(func_data["id"]),
|
|
920
953
|
function=Function(
|
|
921
954
|
name=func_data["name"],
|
|
922
955
|
arguments=func_data["args"],
|
|
@@ -5,6 +5,7 @@ This directory contains concrete implementations of the `BaseLlm` interface, pro
|
|
|
5
5
|
|
|
6
6
|
## Files Overview
|
|
7
7
|
- `lite_llm.py` - LLM client using the `litellm` library to support hundreds of models from different providers
|
|
8
|
+
- `oauth2_token_manager.py` - OAuth 2.0 Client Credentials token manager for LLM authentication
|
|
8
9
|
|
|
9
10
|
## Developer API Reference
|
|
10
11
|
|
|
@@ -14,7 +15,7 @@ This directory contains concrete implementations of the `BaseLlm` interface, pro
|
|
|
14
15
|
**Import:** `from solace_agent_mesh.agent.adk.models.lite_llm import LiteLlm`
|
|
15
16
|
|
|
16
17
|
**Classes:**
|
|
17
|
-
- `LiteLlm(model: str, **kwargs)` - Wrapper around `litellm` supporting any model it recognizes
|
|
18
|
+
- `LiteLlm(model: str, cache_strategy: str = "5m", **kwargs)` - Wrapper around `litellm` supporting any model it recognizes
|
|
18
19
|
- `generate_content_async(llm_request: LlmRequest, stream: bool = False) -> AsyncGenerator[LlmResponse, None]` - Generates content asynchronously with optional streaming
|
|
19
20
|
- `supported_models() -> list[str]` - Returns list of supported models (empty for LiteLlm due to dynamic model support)
|
|
20
21
|
- `model: str` - The name of the LiteLlm model
|
|
@@ -64,7 +65,8 @@ async def main():
|
|
|
64
65
|
llm = LiteLlm(
|
|
65
66
|
model="gpt-4-turbo",
|
|
66
67
|
temperature=0.7,
|
|
67
|
-
max_completion_tokens=150
|
|
68
|
+
max_completion_tokens=150,
|
|
69
|
+
cache_strategy="5m" # Options: "none", "5m", "1h"
|
|
68
70
|
)
|
|
69
71
|
|
|
70
72
|
# Create a request
|
|
@@ -96,47 +98,92 @@ async def main():
|
|
|
96
98
|
if response.usage_metadata:
|
|
97
99
|
print(f"\nTotal tokens: {response.usage_metadata.total_token_count}")
|
|
98
100
|
|
|
99
|
-
# Example with
|
|
100
|
-
async def
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"location": Schema(type=Type.STRING, description="City name"),
|
|
111
|
-
"unit": Schema(type=Type.STRING, description="Temperature unit")
|
|
112
|
-
},
|
|
113
|
-
required=["location"]
|
|
114
|
-
)
|
|
101
|
+
# Example with OAuth authentication
|
|
102
|
+
async def oauth_example():
|
|
103
|
+
llm = LiteLlm(
|
|
104
|
+
model="custom-model",
|
|
105
|
+
oauth_token_url="https://auth.example.com/oauth/token",
|
|
106
|
+
oauth_client_id="your-client-id",
|
|
107
|
+
oauth_client_secret="your-client-secret",
|
|
108
|
+
oauth_scope="llm.read llm.write",
|
|
109
|
+
oauth_ca_cert="/path/to/ca.crt", # Optional
|
|
110
|
+
oauth_token_refresh_buffer_seconds=300, # Optional
|
|
111
|
+
oauth_max_retries=3 # Optional
|
|
115
112
|
)
|
|
116
113
|
|
|
117
|
-
llm = LiteLlm(model="gpt-4-turbo")
|
|
118
|
-
|
|
119
114
|
request = LlmRequest(
|
|
120
|
-
contents=[
|
|
121
|
-
Content(
|
|
122
|
-
role="user",
|
|
123
|
-
parts=[Part.from_text("What's the weather like in Tokyo?")]
|
|
124
|
-
)
|
|
125
|
-
],
|
|
126
|
-
config=LlmConfig(
|
|
127
|
-
tools=[Tool(function_declarations=[get_weather_func])]
|
|
128
|
-
)
|
|
115
|
+
contents=[Content(role="user", parts=[Part.from_text("Hello!")])]
|
|
129
116
|
)
|
|
130
117
|
|
|
131
118
|
async for response in llm.generate_content_async(request):
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
119
|
+
print(response.text)
|
|
120
|
+
|
|
121
|
+
if __name__ == "__main__":
|
|
122
|
+
asyncio.run(main())
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### oauth2_token_manager.py
|
|
126
|
+
**Purpose:** Provides OAuth 2.0 Client Credentials flow implementation for LLM authentication with automatic token management, caching, and refresh capabilities.
|
|
127
|
+
|
|
128
|
+
**Import:** `from solace_agent_mesh.agent.adk.models.oauth2_token_manager import OAuth2ClientCredentialsTokenManager`
|
|
129
|
+
|
|
130
|
+
**Classes:**
|
|
131
|
+
- `OAuth2ClientCredentialsTokenManager(token_url: str, client_id: str, client_secret: str, scope: Optional[str] = None, ca_cert_path: Optional[str] = None, refresh_buffer_seconds: int = 300, max_retries: int = 3)` - Manages OAuth 2.0 Client Credentials tokens with caching and automatic refresh
|
|
132
|
+
- `get_token() -> str` - Get a valid OAuth 2.0 access token (async)
|
|
133
|
+
- `token_url: str` - OAuth 2.0 token endpoint URL
|
|
134
|
+
- `client_id: str` - OAuth client identifier
|
|
135
|
+
- `client_secret: str` - OAuth client secret
|
|
136
|
+
- `scope: Optional[str]` - OAuth scope (space-separated string)
|
|
137
|
+
- `ca_cert_path: Optional[str]` - Path to custom CA certificate file
|
|
138
|
+
- `refresh_buffer_seconds: int` - Seconds before actual expiry to refresh token
|
|
139
|
+
- `max_retries: int` - Maximum number of retry attempts for token requests
|
|
140
|
+
|
|
141
|
+
**Usage Examples:**
|
|
142
|
+
```python
|
|
143
|
+
import asyncio
|
|
144
|
+
from solace_agent_mesh.agent.adk.models.oauth2_token_manager import OAuth2ClientCredentialsTokenManager
|
|
145
|
+
|
|
146
|
+
async def main():
|
|
147
|
+
# Initialize OAuth token manager
|
|
148
|
+
token_manager = OAuth2ClientCredentialsTokenManager(
|
|
149
|
+
token_url="https://auth.example.com/oauth/token",
|
|
150
|
+
client_id="your-client-id",
|
|
151
|
+
client_secret="your-client-secret",
|
|
152
|
+
scope="llm.read llm.write", # Optional
|
|
153
|
+
ca_cert_path="/path/to/ca.crt", # Optional for custom CA
|
|
154
|
+
refresh_buffer_seconds=300, # Refresh 5 minutes before expiry
|
|
155
|
+
max_retries=3 # Retry failed requests up to 3 times
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
# Get a valid access token
|
|
160
|
+
access_token = await token_manager.get_token()
|
|
161
|
+
print(f"Access token: {access_token[:20]}...")
|
|
162
|
+
|
|
163
|
+
# Token is automatically cached and reused
|
|
164
|
+
# Subsequent calls will return cached token if still valid
|
|
165
|
+
cached_token = await token_manager.get_token()
|
|
166
|
+
print(f"Cached token: {cached_token[:20]}...")
|
|
167
|
+
|
|
168
|
+
except Exception as e:
|
|
169
|
+
print(f"Failed to get OAuth token: {e}")
|
|
170
|
+
|
|
171
|
+
# Example with custom SSL configuration
|
|
172
|
+
async def custom_ssl_example():
|
|
173
|
+
token_manager = OAuth2ClientCredentialsTokenManager(
|
|
174
|
+
token_url="https://secure-auth.example.com/oauth/token",
|
|
175
|
+
client_id="client-123",
|
|
176
|
+
client_secret="secret-456",
|
|
177
|
+
ca_cert_path="/etc/ssl/certs/custom-ca.pem", # Custom CA certificate
|
|
178
|
+
refresh_buffer_seconds=600, # Refresh 10 minutes early
|
|
179
|
+
max_retries=5 # More retries for unreliable networks
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
token = await token_manager.get_token()
|
|
183
|
+
print(f"Token obtained with custom SSL: {token[:20]}...")
|
|
136
184
|
|
|
137
185
|
if __name__ == "__main__":
|
|
138
186
|
asyncio.run(main())
|
|
139
|
-
# asyncio.run(function_calling_example())
|
|
140
187
|
```
|
|
141
188
|
|
|
142
|
-
# content_hash:
|
|
189
|
+
# content_hash: 29d771563355d8e4b320350d4fe586f19717d8b16707487efb4372125d5e0f10
|
|
@@ -124,6 +124,15 @@ async def run_adk_async_task_thread_wrapper(
|
|
|
124
124
|
a2a_context,
|
|
125
125
|
)
|
|
126
126
|
|
|
127
|
+
# Mark task as paused if it's waiting for peer response or user input
|
|
128
|
+
if task_context and is_paused:
|
|
129
|
+
task_context.set_paused(True)
|
|
130
|
+
log.debug(
|
|
131
|
+
"%s Task %s marked as paused, waiting for peer response or user input.",
|
|
132
|
+
component.log_identifier,
|
|
133
|
+
logical_task_id,
|
|
134
|
+
)
|
|
135
|
+
|
|
127
136
|
log.debug(
|
|
128
137
|
"%s ADK task %s awaited and completed (Paused: %s).",
|
|
129
138
|
component.log_identifier,
|
|
@@ -46,6 +46,7 @@ class BlockStartedEvent(ParserEvent):
|
|
|
46
46
|
class BlockProgressedEvent(ParserEvent):
|
|
47
47
|
"""Emitted periodically while content is being buffered for a block."""
|
|
48
48
|
|
|
49
|
+
params: Dict[str, Any]
|
|
49
50
|
buffered_size: int
|
|
50
51
|
chunk: str
|
|
51
52
|
|
|
@@ -216,6 +217,10 @@ class FencedBlockStreamParser:
|
|
|
216
217
|
self._last_progress_update_size : current_size
|
|
217
218
|
]
|
|
218
219
|
events.append(
|
|
219
|
-
BlockProgressedEvent(
|
|
220
|
+
BlockProgressedEvent(
|
|
221
|
+
params=self._block_params,
|
|
222
|
+
buffered_size=current_size,
|
|
223
|
+
chunk=new_chunk,
|
|
224
|
+
)
|
|
220
225
|
)
|
|
221
226
|
self._last_progress_update_size = current_size
|
|
@@ -15,6 +15,7 @@ from ...common.utils.embeds import (
|
|
|
15
15
|
LATE_EMBED_TYPES,
|
|
16
16
|
EMBED_DELIMITER_OPEN,
|
|
17
17
|
)
|
|
18
|
+
from ...common.utils.embeds.types import ResolutionMode
|
|
18
19
|
|
|
19
20
|
log = logging.getLogger(__name__)
|
|
20
21
|
|
|
@@ -102,6 +103,7 @@ class ADKToolWrapper:
|
|
|
102
103
|
context=context_for_embeds,
|
|
103
104
|
resolver_func=evaluate_embed,
|
|
104
105
|
types_to_resolve=self._types_to_resolve,
|
|
106
|
+
resolution_mode=ResolutionMode.TOOL_PARAMETER,
|
|
105
107
|
log_identifier=log_identifier,
|
|
106
108
|
config=self._tool_config,
|
|
107
109
|
)
|
|
@@ -123,6 +125,7 @@ class ADKToolWrapper:
|
|
|
123
125
|
context=context_for_embeds,
|
|
124
126
|
resolver_func=evaluate_embed,
|
|
125
127
|
types_to_resolve=self._types_to_resolve,
|
|
128
|
+
resolution_mode=ResolutionMode.TOOL_PARAMETER,
|
|
126
129
|
log_identifier=log_identifier,
|
|
127
130
|
config=self._tool_config,
|
|
128
131
|
)
|