solace-agent-mesh 1.0.9__py3-none-any.whl → 1.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of solace-agent-mesh might be problematic. Click here for more details.

Files changed (220) hide show
  1. solace_agent_mesh/agent/adk/adk_llm.txt +182 -42
  2. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +171 -0
  3. solace_agent_mesh/agent/adk/callbacks.py +165 -104
  4. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +0 -18
  5. solace_agent_mesh/agent/adk/models/models_llm.txt +104 -55
  6. solace_agent_mesh/agent/adk/runner.py +25 -17
  7. solace_agent_mesh/agent/adk/services.py +3 -3
  8. solace_agent_mesh/agent/adk/setup.py +11 -0
  9. solace_agent_mesh/agent/adk/stream_parser.py +8 -1
  10. solace_agent_mesh/agent/adk/tool_wrapper.py +10 -3
  11. solace_agent_mesh/agent/agent_llm.txt +355 -18
  12. solace_agent_mesh/agent/protocol/event_handlers.py +460 -317
  13. solace_agent_mesh/agent/protocol/protocol_llm.txt +54 -7
  14. solace_agent_mesh/agent/sac/app.py +2 -2
  15. solace_agent_mesh/agent/sac/component.py +211 -517
  16. solace_agent_mesh/agent/sac/sac_llm.txt +133 -63
  17. solace_agent_mesh/agent/testing/testing_llm.txt +25 -58
  18. solace_agent_mesh/agent/tools/peer_agent_tool.py +15 -11
  19. solace_agent_mesh/agent/tools/tools_llm.txt +234 -69
  20. solace_agent_mesh/agent/utils/artifact_helpers.py +35 -1
  21. solace_agent_mesh/agent/utils/utils_llm.txt +90 -105
  22. solace_agent_mesh/assets/docs/404.html +3 -3
  23. solace_agent_mesh/assets/docs/assets/js/6e0db977.39a79ca9.js +1 -0
  24. solace_agent_mesh/assets/docs/assets/js/{75384d09.ccd480c4.js → 75384d09.bf78fbdb.js} +1 -1
  25. solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +1 -0
  26. solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +1 -0
  27. solace_agent_mesh/assets/docs/assets/js/main.08d30374.js +2 -0
  28. solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +1 -0
  29. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +4 -4
  30. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +4 -4
  31. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +4 -4
  32. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
  33. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +4 -4
  34. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +4 -4
  35. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
  36. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +4 -4
  37. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +4 -4
  38. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +4 -4
  39. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +4 -4
  40. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +4 -4
  41. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
  42. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +4 -4
  43. solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +105 -0
  44. solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html +53 -0
  45. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +4 -4
  46. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +4 -4
  47. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +4 -4
  48. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
  49. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +4 -4
  50. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +4 -4
  51. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +4 -4
  52. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +4 -4
  53. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +4 -4
  54. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +4 -4
  55. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +4 -4
  56. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +4 -4
  57. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +4 -4
  58. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +4 -4
  59. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +4 -4
  60. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +4 -4
  61. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +4 -4
  62. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +4 -4
  63. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
  64. solace_agent_mesh/assets/docs/lunr-index-1757433031159.json +1 -0
  65. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  66. solace_agent_mesh/assets/docs/search-doc-1757433031159.json +1 -0
  67. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  68. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  69. solace_agent_mesh/cli/__init__.py +1 -1
  70. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
  71. solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
  72. solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
  73. solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
  74. solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
  75. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
  76. solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
  77. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
  78. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
  79. solace_agent_mesh/cli/commands/run_cmd.py +5 -3
  80. solace_agent_mesh/cli/utils.py +68 -12
  81. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-vY5eu2lI.js +1 -0
  82. solace_agent_mesh/client/webui/frontend/static/assets/client-BeBkzgWW.js +25 -0
  83. solace_agent_mesh/client/webui/frontend/static/assets/main-Bjys1KQs.js +339 -0
  84. solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
  85. solace_agent_mesh/client/webui/frontend/static/assets/vendor-CE0AeXyK.js +395 -0
  86. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
  87. solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
  88. solace_agent_mesh/common/a2a/__init__.py +213 -0
  89. solace_agent_mesh/common/a2a/a2a_llm.txt +182 -0
  90. solace_agent_mesh/common/a2a/artifact.py +328 -0
  91. solace_agent_mesh/common/a2a/events.py +183 -0
  92. solace_agent_mesh/common/a2a/message.py +307 -0
  93. solace_agent_mesh/common/a2a/protocol.py +513 -0
  94. solace_agent_mesh/common/a2a/task.py +127 -0
  95. solace_agent_mesh/common/a2a/translation.py +653 -0
  96. solace_agent_mesh/common/a2a/types.py +54 -0
  97. solace_agent_mesh/common/a2a_spec/a2a.json +2576 -0
  98. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +407 -0
  99. solace_agent_mesh/common/a2a_spec/schemas/agent_progress_update.json +18 -0
  100. solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +31 -0
  101. solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +18 -0
  102. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +235 -0
  103. solace_agent_mesh/common/a2a_spec/schemas/tool_invocation_start.json +26 -0
  104. solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +25 -0
  105. solace_agent_mesh/common/agent_registry.py +1 -1
  106. solace_agent_mesh/common/common_llm.txt +192 -70
  107. solace_agent_mesh/common/data_parts.py +99 -0
  108. solace_agent_mesh/common/middleware/middleware_llm.txt +17 -17
  109. solace_agent_mesh/common/sac/__init__.py +0 -0
  110. solace_agent_mesh/common/sac/sac_llm.txt +71 -0
  111. solace_agent_mesh/common/sac/sam_component_base.py +252 -0
  112. solace_agent_mesh/common/services/providers/providers_llm.txt +51 -84
  113. solace_agent_mesh/common/services/services_llm.txt +206 -26
  114. solace_agent_mesh/common/utils/artifact_utils.py +29 -0
  115. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +176 -80
  116. solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
  117. solace_agent_mesh/common/utils/utils_llm.txt +323 -42
  118. solace_agent_mesh/config_portal/backend/common.py +2 -2
  119. solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +1 -1
  120. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
  121. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
  122. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  123. solace_agent_mesh/core_a2a/core_a2a_llm.txt +10 -8
  124. solace_agent_mesh/core_a2a/service.py +20 -44
  125. solace_agent_mesh/evaluation/message_organizer.py +35 -56
  126. solace_agent_mesh/evaluation/run.py +26 -5
  127. solace_agent_mesh/evaluation/subscriber.py +35 -10
  128. solace_agent_mesh/evaluation/summary_builder.py +27 -34
  129. solace_agent_mesh/gateway/base/app.py +27 -1
  130. solace_agent_mesh/gateway/base/base_llm.txt +177 -72
  131. solace_agent_mesh/gateway/base/component.py +294 -523
  132. solace_agent_mesh/gateway/gateway_llm.txt +299 -58
  133. solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
  134. solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
  135. solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
  136. solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
  137. solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
  138. solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
  139. solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
  140. solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
  141. solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
  142. solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
  143. solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
  144. solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
  145. solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
  146. solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
  147. solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
  148. solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
  149. solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
  150. solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
  151. solace_agent_mesh/gateway/http_sse/app.py +31 -1
  152. solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
  153. solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
  154. solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
  155. solace_agent_mesh/gateway/http_sse/component.py +371 -236
  156. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +29 -29
  157. solace_agent_mesh/gateway/http_sse/dependencies.py +142 -39
  158. solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
  159. solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
  160. solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
  161. solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
  162. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +272 -36
  163. solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
  164. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
  165. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
  166. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
  167. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
  168. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
  169. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
  170. solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
  171. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
  172. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
  173. solace_agent_mesh/gateway/http_sse/main.py +293 -91
  174. solace_agent_mesh/gateway/http_sse/routers/agents.py +1 -1
  175. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +137 -56
  176. solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
  177. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +231 -5
  178. solace_agent_mesh/gateway/http_sse/routers/tasks.py +199 -171
  179. solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
  180. solace_agent_mesh/gateway/http_sse/services/agent_service.py +1 -1
  181. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +89 -135
  182. solace_agent_mesh/gateway/http_sse/services/task_service.py +2 -5
  183. solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
  184. solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
  185. solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
  186. solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
  187. solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
  188. solace_agent_mesh/solace_agent_mesh_llm.txt +362 -0
  189. solace_agent_mesh/templates/gateway_component_template.py +149 -98
  190. solace_agent_mesh/templates/shared_config.yaml +4 -5
  191. solace_agent_mesh/templates/webui.yaml +8 -10
  192. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/METADATA +9 -6
  193. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/RECORD +197 -141
  194. solace_agent_mesh/assets/docs/assets/js/f284c35a.731836ad.js +0 -1
  195. solace_agent_mesh/assets/docs/assets/js/main.3d0e7879.js +0 -2
  196. solace_agent_mesh/assets/docs/assets/js/runtime~main.05d19492.js +0 -1
  197. solace_agent_mesh/assets/docs/lunr-index-1757091012487.json +0 -1
  198. solace_agent_mesh/assets/docs/search-doc-1757091012487.json +0 -1
  199. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
  200. solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
  201. solace_agent_mesh/client/webui/frontend/static/assets/main-D0FnP_W4.css +0 -1
  202. solace_agent_mesh/client/webui/frontend/static/assets/main-Do32sFPX.js +0 -708
  203. solace_agent_mesh/common/a2a_protocol.py +0 -564
  204. solace_agent_mesh/common/client/__init__.py +0 -4
  205. solace_agent_mesh/common/client/card_resolver.py +0 -21
  206. solace_agent_mesh/common/client/client.py +0 -85
  207. solace_agent_mesh/common/client/client_llm.txt +0 -133
  208. solace_agent_mesh/common/server/__init__.py +0 -4
  209. solace_agent_mesh/common/server/server.py +0 -122
  210. solace_agent_mesh/common/server/server_llm.txt +0 -169
  211. solace_agent_mesh/common/server/task_manager.py +0 -291
  212. solace_agent_mesh/common/server/utils.py +0 -28
  213. solace_agent_mesh/common/types.py +0 -411
  214. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
  215. solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -80
  216. solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
  217. /solace_agent_mesh/assets/docs/assets/js/{main.3d0e7879.js.LICENSE.txt → main.08d30374.js.LICENSE.txt} +0 -0
  218. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/WHEEL +0 -0
  219. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/entry_points.txt +0 -0
  220. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -16,9 +16,6 @@ from google.adk.artifacts import BaseArtifactService
16
16
  from google.adk.agents.callback_context import CallbackContext
17
17
  from google.adk.models.llm_request import LlmRequest
18
18
  from google.adk.models.llm_response import LlmResponse
19
- from ...common.a2a_protocol import (
20
- A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY,
21
- )
22
19
  from google.genai import types as adk_types
23
20
  from google.adk.tools.mcp_tool import MCPTool
24
21
  from solace_ai_connector.common.log import log
@@ -48,14 +45,14 @@ from ...common.utils.embeds import (
48
45
 
49
46
  from ...common.utils.embeds.modifiers import MODIFIER_IMPLEMENTATIONS
50
47
 
51
- if TYPE_CHECKING:
52
- from ..sac.component import SamAgentComponent
53
-
54
- from ...common.types import (
55
- TaskStatusUpdateEvent,
56
- TaskStatus,
57
- TaskState,
58
- Message as A2AMessage,
48
+ from ...common import a2a
49
+ from ...common.a2a.types import ContentPart
50
+ from ...common.data_parts import (
51
+ AgentProgressUpdateData,
52
+ ArtifactCreationProgressData,
53
+ LlmInvocationData,
54
+ ToolInvocationStartData,
55
+ ToolResultData,
59
56
  )
60
57
 
61
58
  from ...agent.utils.artifact_helpers import (
@@ -68,6 +65,7 @@ from ..tools.builtin_artifact_tools import _internal_create_artifact
68
65
  from ...agent.adk.tool_wrapper import ADKToolWrapper
69
66
 
70
67
  # Import the new parser and its events
68
+ from pydantic import BaseModel
71
69
  from ...agent.adk.stream_parser import (
72
70
  FencedBlockStreamParser,
73
71
  BlockStartedEvent,
@@ -78,6 +76,44 @@ from ...agent.adk.stream_parser import (
78
76
  ARTIFACT_BLOCK_DELIMITER_CLOSE,
79
77
  )
80
78
 
79
+ A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY = "temp:llm_stream_chunks_processed"
80
+
81
+ if TYPE_CHECKING:
82
+ from ..sac.component import SamAgentComponent
83
+
84
+
85
+ async def _publish_data_part_status_update(
86
+ host_component: "SamAgentComponent",
87
+ a2a_context: Dict[str, Any],
88
+ data_part_model: BaseModel,
89
+ ):
90
+ """Helper to construct and publish a TaskStatusUpdateEvent with a DataPart."""
91
+ logical_task_id = a2a_context.get("logical_task_id")
92
+ context_id = a2a_context.get("contextId")
93
+
94
+ status_update_event = a2a.create_data_signal_event(
95
+ task_id=logical_task_id,
96
+ context_id=context_id,
97
+ signal_data=data_part_model,
98
+ agent_name=host_component.agent_name,
99
+ )
100
+
101
+ loop = host_component.get_async_loop()
102
+ if loop and loop.is_running():
103
+ asyncio.run_coroutine_threadsafe(
104
+ host_component._publish_status_update_with_buffer_flush(
105
+ status_update_event,
106
+ a2a_context,
107
+ skip_buffer_flush=False,
108
+ ),
109
+ loop,
110
+ )
111
+ else:
112
+ log.error(
113
+ "%s Async loop not available. Cannot publish status update.",
114
+ host_component.log_identifier,
115
+ )
116
+
81
117
 
82
118
  async def process_artifact_blocks_callback(
83
119
  callback_context: CallbackContext,
@@ -132,8 +168,11 @@ async def process_artifact_blocks_callback(
132
168
  )
133
169
  filename = event.params.get("filename", "unknown_artifact")
134
170
  if a2a_context:
135
- await host_component._publish_agent_status_signal_update(
136
- f"Receiving artifact `{filename}`...", a2a_context
171
+ progress_data = AgentProgressUpdateData(
172
+ status_text=f"Receiving artifact `{filename}`..."
173
+ )
174
+ await _publish_data_part_status_update(
175
+ host_component, a2a_context, progress_data
137
176
  )
138
177
  params_str = " ".join(
139
178
  [f'{k}="{v}"' for k, v in event.params.items()]
@@ -149,10 +188,14 @@ async def process_artifact_blocks_callback(
149
188
  )
150
189
  params = parser._block_params
151
190
  filename = params.get("filename", "unknown_artifact")
152
- status_message = f"Creating artifact `{filename}` ({event.buffered_size}B saved)..."
153
191
  if a2a_context:
154
- await host_component._publish_agent_status_signal_update(
155
- status_message, a2a_context
192
+ progress_data = ArtifactCreationProgressData(
193
+ filename=filename,
194
+ bytes_saved=event.buffered_size,
195
+ artifact_chunk=event.chunk,
196
+ )
197
+ await _publish_data_part_status_update(
198
+ host_component, a2a_context, progress_data
156
199
  )
157
200
 
158
201
  elif isinstance(event, BlockCompletedEvent):
@@ -217,6 +260,7 @@ async def process_artifact_blocks_callback(
217
260
  tool_config=None, # No specific config for this internal tool
218
261
  tool_name="_internal_create_artifact",
219
262
  origin="internal",
263
+ resolution_type="early",
220
264
  )
221
265
  save_result = await wrapped_creator(**kwargs_for_call)
222
266
 
@@ -694,8 +738,7 @@ async def manage_large_mcp_tool_responses_callback(
694
738
 
695
739
  if needs_saving_as_artifact and (
696
740
  save_result
697
- and save_result.status
698
- in [McpSaveStatus.SUCCESS, McpSaveStatus.PARTIAL_SUCCESS]
741
+ and save_result.status in [McpSaveStatus.SUCCESS, McpSaveStatus.PARTIAL_SUCCESS]
699
742
  ):
700
743
  if needs_truncation_for_llm:
701
744
  final_llm_response_dict["status"] = "processed_saved_and_truncated"
@@ -1345,20 +1388,10 @@ def solace_llm_invocation_callback(
1345
1388
  )
1346
1389
  return None
1347
1390
 
1348
- try:
1349
- from ...common.a2a_protocol import A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY
1350
-
1351
- callback_context.state[A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY] = False
1352
- log.debug(
1353
- "%s Reset %s to False.", log_identifier, A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY
1354
- )
1355
- except Exception as e_flag_reset:
1356
- log.error(
1357
- "%s Error resetting %s: %s",
1358
- log_identifier,
1359
- A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY,
1360
- e_flag_reset,
1361
- )
1391
+ callback_context.state[A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY] = False
1392
+ log.debug(
1393
+ "%s Reset %s to False.", log_identifier, A2A_LLM_STREAM_CHUNKS_PROCESSED_KEY
1394
+ )
1362
1395
 
1363
1396
  try:
1364
1397
  a2a_context = callback_context.state.get("a2a_context")
@@ -1369,28 +1402,15 @@ def solace_llm_invocation_callback(
1369
1402
  )
1370
1403
  return None
1371
1404
 
1372
- agent_name = host_component.get_config("agent_name", "unknown_agent")
1373
1405
  logical_task_id = a2a_context.get("logical_task_id")
1374
-
1375
- llm_invocation_metadata = {
1376
- "type": "llm_invocation",
1377
- "data": llm_request.model_dump(exclude_none=True),
1378
- }
1379
- a2a_message = A2AMessage(
1380
- role="agent",
1381
- parts=[],
1382
- metadata=llm_invocation_metadata,
1383
- )
1384
- task_status = TaskStatus(
1385
- state=TaskState.WORKING,
1386
- message=a2a_message,
1387
- timestamp=datetime.now(timezone.utc),
1388
- )
1389
- status_update_event = TaskStatusUpdateEvent(
1390
- id=logical_task_id,
1391
- status=task_status,
1392
- final=False,
1393
- metadata={"agent_name": agent_name},
1406
+ context_id = a2a_context.get("contextId")
1407
+
1408
+ llm_data = LlmInvocationData(request=llm_request.model_dump(exclude_none=True))
1409
+ status_update_event = a2a.create_data_signal_event(
1410
+ task_id=logical_task_id,
1411
+ context_id=context_id,
1412
+ signal_data=llm_data,
1413
+ agent_name=host_component.agent_name,
1394
1414
  )
1395
1415
 
1396
1416
  loop = host_component.get_async_loop()
@@ -1454,20 +1474,23 @@ def solace_llm_response_callback(
1454
1474
  agent_name = host_component.get_config("agent_name", "unknown_agent")
1455
1475
  logical_task_id = a2a_context.get("logical_task_id")
1456
1476
 
1457
- llm_response_metadata = {
1477
+ llm_response_data = {
1458
1478
  "type": "llm_response",
1459
1479
  "data": llm_response.model_dump(exclude_none=True),
1460
1480
  }
1461
- a2a_message = A2AMessage(role="agent", parts=[], metadata=llm_response_metadata)
1462
- task_status = TaskStatus(
1463
- state=TaskState.WORKING,
1464
- message=a2a_message,
1465
- timestamp=datetime.now(timezone.utc),
1481
+ # This signal doesn't have a dedicated Pydantic model, so we create the
1482
+ # DataPart directly and use the lower-level helpers.
1483
+ data_part = a2a.create_data_part(data=llm_response_data)
1484
+ a2a_message = a2a.create_agent_parts_message(
1485
+ parts=[data_part],
1486
+ task_id=logical_task_id,
1487
+ context_id=a2a_context.get("contextId"),
1466
1488
  )
1467
- status_update_event = TaskStatusUpdateEvent(
1468
- id=logical_task_id,
1469
- status=task_status,
1470
- final=True,
1489
+ status_update_event = a2a.create_status_update(
1490
+ task_id=logical_task_id,
1491
+ context_id=a2a_context.get("contextId"),
1492
+ message=a2a_message,
1493
+ is_final=False,
1471
1494
  metadata={"agent_name": agent_name},
1472
1495
  )
1473
1496
  loop = host_component.get_async_loop()
@@ -1529,8 +1552,6 @@ def notify_tool_invocation_start_callback(
1529
1552
  )
1530
1553
  return
1531
1554
 
1532
- logical_task_id = a2a_context.get("logical_task_id")
1533
-
1534
1555
  try:
1535
1556
  serializable_args = {}
1536
1557
  for k, v in args.items():
@@ -1540,57 +1561,97 @@ def notify_tool_invocation_start_callback(
1540
1561
  except TypeError:
1541
1562
  serializable_args[k] = str(v)
1542
1563
 
1543
- a2a_message_parts = []
1544
- message_metadata = {
1545
- "type": "tool_invocation_start",
1546
- "data": {
1547
- "tool_name": tool.name,
1548
- "tool_args": serializable_args,
1549
- "function_call_id": tool_context.function_call_id,
1550
- },
1551
- }
1564
+ tool_data = ToolInvocationStartData(
1565
+ tool_name=tool.name,
1566
+ tool_args=serializable_args,
1567
+ function_call_id=tool_context.function_call_id,
1568
+ )
1569
+ asyncio.run_coroutine_threadsafe(
1570
+ _publish_data_part_status_update(host_component, a2a_context, tool_data),
1571
+ host_component.get_async_loop(),
1572
+ )
1573
+ log.debug(
1574
+ "%s Scheduled tool_invocation_start notification.",
1575
+ log_identifier,
1576
+ )
1552
1577
 
1553
- a2a_message = A2AMessage(
1554
- role="agent", parts=a2a_message_parts, metadata=message_metadata
1578
+ except Exception as e:
1579
+ log.exception(
1580
+ "%s Error publishing tool_invocation_start status update: %s",
1581
+ log_identifier,
1582
+ e,
1555
1583
  )
1556
1584
 
1557
- task_status = TaskStatus(
1558
- state=TaskState.WORKING,
1559
- message=a2a_message,
1560
- timestamp=datetime.now(timezone.utc),
1585
+ return None
1586
+
1587
+
1588
+ def notify_tool_execution_result_callback(
1589
+ tool: BaseTool,
1590
+ args: Dict[str, Any],
1591
+ tool_context: ToolContext,
1592
+ tool_response: Any,
1593
+ host_component: "SamAgentComponent",
1594
+ ) -> None:
1595
+ """
1596
+ ADK after_tool_callback to send an A2A status message with the result
1597
+ of a tool's execution.
1598
+ """
1599
+ log_identifier = f"[Callback:NotifyToolResult:{tool.name}]"
1600
+ log.debug("%s Triggered for tool '%s'", log_identifier, tool.name)
1601
+
1602
+ if not host_component:
1603
+ log.error(
1604
+ "%s Host component instance not provided. Cannot send notification.",
1605
+ log_identifier,
1561
1606
  )
1607
+ return
1562
1608
 
1563
- status_update_event = TaskStatusUpdateEvent(
1564
- id=logical_task_id,
1565
- status=task_status,
1566
- final=False,
1567
- metadata={"agent_name": host_component.get_config("agent_name")},
1609
+ a2a_context = tool_context.state.get("a2a_context")
1610
+ if not a2a_context:
1611
+ log.error(
1612
+ "%s a2a_context not found in tool_context.state. Cannot send notification.",
1613
+ log_identifier,
1568
1614
  )
1615
+ return
1569
1616
 
1570
- loop = host_component.get_async_loop()
1571
- if loop and loop.is_running():
1617
+ if tool.is_long_running and not tool_response:
1618
+ log.debug(
1619
+ "%s Tool is long-running and is not yet complete. Don't notify its completion",
1620
+ log_identifier,
1621
+ )
1622
+ return
1572
1623
 
1573
- asyncio.run_coroutine_threadsafe(
1574
- host_component._publish_status_update_with_buffer_flush(
1575
- status_update_event,
1576
- a2a_context,
1577
- skip_buffer_flush=False,
1578
- ),
1579
- loop,
1580
- )
1581
- log.debug(
1582
- "%s Scheduled tool_invocation_start notification with buffer flush.",
1583
- log_identifier,
1584
- )
1624
+ try:
1625
+ # Attempt to make the response JSON serializable
1626
+ serializable_response = tool_response
1627
+ if hasattr(tool_response, "model_dump"):
1628
+ serializable_response = tool_response.model_dump(exclude_none=True)
1585
1629
  else:
1586
- log.error(
1587
- "%s Async loop not available. Cannot publish tool_invocation_start notification.",
1588
- log_identifier,
1589
- )
1630
+ try:
1631
+ # A simple check to see if it can be dumped.
1632
+ # This isn't perfect but catches many non-serializable types.
1633
+ json.dumps(tool_response)
1634
+ except (TypeError, OverflowError):
1635
+ serializable_response = str(tool_response)
1636
+
1637
+ tool_data = ToolResultData(
1638
+ tool_name=tool.name,
1639
+ result_data=serializable_response,
1640
+ function_call_id=tool_context.function_call_id,
1641
+ )
1642
+ asyncio.run_coroutine_threadsafe(
1643
+ _publish_data_part_status_update(host_component, a2a_context, tool_data),
1644
+ host_component.get_async_loop(),
1645
+ )
1646
+ log.debug(
1647
+ "%s Scheduled tool_result notification for function call ID %s.",
1648
+ log_identifier,
1649
+ tool_context.function_call_id,
1650
+ )
1590
1651
 
1591
1652
  except Exception as e:
1592
1653
  log.exception(
1593
- "%s Error publishing tool_invocation_start status update: %s",
1654
+ "%s Error publishing tool_result status update: %s",
1594
1655
  log_identifier,
1595
1656
  e,
1596
1657
  )
@@ -40,11 +40,6 @@ class EmbedResolvingMCPTool(MCPTool):
40
40
  self._original_mcp_tool = original_mcp_tool
41
41
  self._tool_config = tool_config or {}
42
42
 
43
- log.info(
44
- "Created EmbedResolvingMCPTool for '%s' with embed resolution capabilities",
45
- self.name,
46
- )
47
-
48
43
  async def _resolve_embeds_recursively(
49
44
  self,
50
45
  data: Any,
@@ -287,10 +282,6 @@ class EmbedResolvingMCPToolset(MCPToolset):
287
282
 
288
283
  # Wrap each tool with embed resolution capability
289
284
  embed_resolving_tools = []
290
- log.info(
291
- "EmbedResolvingMCPToolset: Wrapping %d MCP tools with embed resolution",
292
- len(original_tools),
293
- )
294
285
 
295
286
  for tool in original_tools:
296
287
  # Get tool-specific config
@@ -304,13 +295,4 @@ class EmbedResolvingMCPToolset(MCPToolset):
304
295
  )
305
296
  embed_resolving_tools.append(embed_resolving_tool)
306
297
 
307
- log.info(
308
- "EmbedResolvingMCPToolset: Successfully wrapped MCP tool '%s'",
309
- tool.name,
310
- )
311
-
312
- log.info(
313
- "EmbedResolvingMCPToolset: Completed wrapping %d MCP tools",
314
- len(embed_resolving_tools),
315
- )
316
298
  return embed_resolving_tools
@@ -1,94 +1,143 @@
1
- Here is the developer guide for the `models` directory.
1
+ # DEVELOPER GUIDE for models directory
2
2
 
3
3
  ## Quick Summary
4
- This directory contains concrete implementations of the `BaseLlm` interface, acting as wrappers or clients for various Large Language Model APIs. These classes translate the ADK's standard `LlmRequest` into the format required by the specific LLM backend and parse the backend's response back into a standard `LlmResponse`.
4
+ This directory contains concrete implementations of the `BaseLlm` interface, providing wrappers for various Large Language Model APIs. These classes translate the ADK's standard `LlmRequest` into provider-specific formats and parse responses back into standard `LlmResponse` objects.
5
5
 
6
6
  ## Files Overview
7
- - `lite_llm.py`: An LLM client that uses the `litellm` library to support a wide variety of models from different providers.
7
+ - `lite_llm.py` - LLM client using the `litellm` library to support hundreds of models from different providers
8
+ - `models_llm.txt` - Documentation file containing developer guide content
8
9
 
9
10
  ## Developer API Reference
10
11
 
11
12
  ### lite_llm.py
12
- **Purpose:** Provides the `LiteLlm` class, a `BaseLlm` implementation that interfaces with hundreds of LLM models through the `litellm` library. This allows developers to use models from providers like OpenAI, Anthropic, Vertex AI, etc., by simply changing the model string. Environment variables required by the target model provider must be set.
13
+ **Purpose:** Provides the `LiteLlm` class, a `BaseLlm` implementation that interfaces with hundreds of LLM models through the `litellm` library. Supports models from OpenAI, Anthropic, Vertex AI, and many other providers by simply changing the model string.
13
14
 
14
- **Import:** `from google.adk.models.lite_llm import LiteLlm`
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` that can be used with any model it supports.
18
- - `__init__(self, model: str, **kwargs)` - Initializes the `LiteLlm` client.
19
- - **model**: The name of the model as recognized by `litellm` (e.g., `"vertex_ai/gemini-1.5-pro-preview-0409"`, `"claude-3-opus-20240229"`, `"gpt-4-turbo"`).
20
- - **\*\*kwargs**: Additional arguments to pass directly to the `litellm.completion` or `litellm.acompletion` API on every call.
21
- - `async generate_content_async(llm_request: LlmRequest, stream: bool = False) -> AsyncGenerator[LlmResponse, None]` - Sends a request to the configured LLM and yields one or more responses.
22
- - **llm_request**: The request object containing conversation history, tool definitions, and configuration.
23
- - **stream**: If `True`, yields partial responses as they become available. If `False`, yields a single, complete response.
24
- - **Returns**: An async generator that yields `LlmResponse` objects.
25
- - `supported_models() -> list[str]` - Provides a list of supported models. For `LiteLlm`, this returns an empty list because `litellm` supports a vast and dynamic set of models. Refer to the `litellm` documentation for a complete list.
18
+ - `LiteLlm(model: str, **kwargs)` - Wrapper around `litellm` supporting any model it recognizes
19
+ - `generate_content_async(llm_request: LlmRequest, stream: bool = False) -> AsyncGenerator[LlmResponse, None]` - Generates content asynchronously with optional streaming
20
+ - `supported_models() -> list[str]` - Returns list of supported models (empty for LiteLlm due to dynamic model support)
21
+ - `model: str` - The name of the LiteLlm model
22
+ - `llm_client: LiteLLMClient` - The LLM client instance used for API calls
23
+
24
+ - `LiteLLMClient()` - Internal client providing completion methods for better testability
25
+ - `acompletion(model, messages, tools, **kwargs) -> Union[ModelResponse, CustomStreamWrapper]` - Asynchronous completion call
26
+ - `completion(model, messages, tools, stream=False, **kwargs) -> Union[ModelResponse, CustomStreamWrapper]` - Synchronous completion call
27
+
28
+ - `FunctionChunk(BaseModel)` - Represents a function call chunk in streaming responses
29
+ - `id: Optional[str]` - Function call ID
30
+ - `name: Optional[str]` - Function name
31
+ - `args: Optional[str]` - Function arguments as JSON string
32
+ - `index: Optional[int]` - Index of the function call
33
+
34
+ - `TextChunk(BaseModel)` - Represents a text chunk in streaming responses
35
+ - `text: str` - The text content
36
+
37
+ - `UsageMetadataChunk(BaseModel)` - Represents token usage information
38
+ - `prompt_tokens: int` - Number of tokens in the prompt
39
+ - `completion_tokens: int` - Number of tokens in the completion
40
+ - `total_tokens: int` - Total number of tokens used
41
+
42
+ **Functions:**
43
+ - `_content_to_message_param(content: types.Content) -> Union[Message, list[Message]]` - Converts ADK Content to litellm Message format
44
+ - `_get_content(parts: Iterable[types.Part]) -> Union[OpenAIMessageContent, str]` - Converts parts to litellm content format
45
+ - `_function_declaration_to_tool_param(function_declaration: types.FunctionDeclaration) -> dict` - Converts function declarations to OpenAPI spec format
46
+ - `_model_response_to_generate_content_response(response: ModelResponse) -> LlmResponse` - Converts litellm response to LlmResponse
26
47
 
27
48
  **Usage Examples:**
28
49
  ```python
29
50
  import asyncio
30
51
  import os
31
- from google.adk.models.lite_llm import LiteLlm
32
- from google.adk.models.llm_request import LlmRequest, LlmConfig
33
- from google.adk.models.types import Content, Part
34
-
35
- # Example using a Vertex AI model via litellm.
36
- # Set environment variables required by the provider.
37
- # os.environ["VERTEXAI_PROJECT"] = "your-gcp-project-id"
38
- # os.environ["VERTEXAI_LOCATION"] = "your-gcp-location"
52
+ from solace_agent_mesh.agent.adk.models.lite_llm import LiteLlm
53
+ from solace_agent_mesh.agent.adk.models.llm_request import LlmRequest, LlmConfig
54
+ from google.genai.types import Content, Part
39
55
 
40
- # Example using an OpenAI model via litellm.
41
- # os.environ["OPENAI_API_KEY"] = "your-openai-api-key"
56
+ # Set environment variables for your chosen provider
57
+ # For OpenAI:
58
+ # os.environ["OPENAI_API_KEY"] = "your-api-key"
59
+ # For Vertex AI:
60
+ # os.environ["VERTEXAI_PROJECT"] = "your-project-id"
61
+ # os.environ["VERTEXAI_LOCATION"] = "your-location"
42
62
 
43
63
  async def main():
44
- # Instantiate the LiteLlm client with a specific model.
45
- # Any additional kwargs are passed to litellm's completion call.
64
+ # Initialize LiteLlm with a specific model
46
65
  llm = LiteLlm(
47
66
  model="gpt-4-turbo",
48
- temperature=0.5,
49
- max_tokens=150
67
+ temperature=0.7,
68
+ max_completion_tokens=150
50
69
  )
51
-
52
- # Construct a request to the LLM
70
+
71
+ # Create a request
53
72
  request = LlmRequest(
54
73
  contents=[
55
74
  Content(
56
75
  role="user",
57
- parts=[Part.from_text("Why is the sky blue?")]
76
+ parts=[Part.from_text("Explain quantum computing in simple terms")]
58
77
  )
59
78
  ],
60
79
  config=LlmConfig(
61
- # The temperature set in the constructor can be overridden here
62
- temperature=0.7
80
+ temperature=0.5,
81
+ max_output_tokens=200
63
82
  )
64
83
  )
65
-
66
- print("--- Non-streaming example ---")
67
- # Get a single, complete response
84
+
85
+ # Non-streaming generation
86
+ print("=== Non-streaming ===")
68
87
  async for response in llm.generate_content_async(request, stream=False):
69
- if response.text:
70
- print(response.text)
88
+ print(f"Response: {response.text}")
71
89
  if response.usage_metadata:
72
- print(f"Token usage: {response.usage_metadata.total_token_count}")
73
-
74
- print("\n--- Streaming example ---")
75
- # Get a stream of partial responses
76
- full_response_text = ""
90
+ print(f"Tokens used: {response.usage_metadata.total_token_count}")
91
+
92
+ # Streaming generation
93
+ print("\n=== Streaming ===")
77
94
  async for response in llm.generate_content_async(request, stream=True):
78
95
  if response.text:
79
96
  print(response.text, end="", flush=True)
80
- full_response_text += response.text
81
97
  if response.usage_metadata:
82
- # Usage metadata is typically sent with the final chunk
83
- print(f"\nToken usage: {response.usage_metadata.total_token_count}")
98
+ print(f"\nTotal tokens: {response.usage_metadata.total_token_count}")
99
+
100
+ # Example with function calling
101
+ async def function_calling_example():
102
+ from google.genai.types import FunctionDeclaration, Schema, Type, Tool
103
+
104
+ # Define a function for the LLM to call
105
+ get_weather_func = FunctionDeclaration(
106
+ name="get_weather",
107
+ description="Get current weather for a location",
108
+ parameters=Schema(
109
+ type=Type.OBJECT,
110
+ properties={
111
+ "location": Schema(type=Type.STRING, description="City name"),
112
+ "unit": Schema(type=Type.STRING, description="Temperature unit")
113
+ },
114
+ required=["location"]
115
+ )
116
+ )
117
+
118
+ llm = LiteLlm(model="gpt-4-turbo")
119
+
120
+ request = LlmRequest(
121
+ contents=[
122
+ Content(
123
+ role="user",
124
+ parts=[Part.from_text("What's the weather like in Tokyo?")]
125
+ )
126
+ ],
127
+ config=LlmConfig(
128
+ tools=[Tool(function_declarations=[get_weather_func])]
129
+ )
130
+ )
131
+
132
+ async for response in llm.generate_content_async(request):
133
+ if response.function_calls:
134
+ for func_call in response.function_calls:
135
+ print(f"Function called: {func_call.name}")
136
+ print(f"Arguments: {func_call.args}")
84
137
 
85
138
  if __name__ == "__main__":
86
- # To run this example, you need to have the necessary environment variables set
87
- # for the model you choose (e.g., OPENAI_API_KEY).
88
- # You would also need to install the required provider packages, e.g.,
89
- # pip install litellm[openai]
90
- #
91
- # Since this is an async function, we run it with asyncio.
92
- # asyncio.run(main())
93
- pass
94
- ```
139
+ asyncio.run(main())
140
+ # asyncio.run(function_calling_example())
141
+ ```
142
+
143
+ # content_hash: 12789ad2e16cd9ea5a81abdd68258d9ef30520bed5c51ba8d00ea66014191964