solace-agent-mesh 1.3.3__py3-none-any.whl → 1.4.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 (80) hide show
  1. solace_agent_mesh/agent/adk/setup.py +183 -8
  2. solace_agent_mesh/agent/sac/app.py +337 -622
  3. solace_agent_mesh/agent/sac/component.py +47 -1
  4. solace_agent_mesh/agent/tools/dynamic_tool.py +36 -5
  5. solace_agent_mesh/agent/tools/tool_config_types.py +58 -0
  6. solace_agent_mesh/assets/docs/404.html +3 -3
  7. solace_agent_mesh/assets/docs/assets/js/42b3f8d8.508ae8db.js +1 -0
  8. solace_agent_mesh/assets/docs/assets/js/9a09e75d.92de8cf5.js +1 -0
  9. solace_agent_mesh/assets/docs/assets/js/{main.e82b32e6.js → main.1de3da6a.js} +2 -2
  10. solace_agent_mesh/assets/docs/assets/js/{runtime~main.aad1f874.js → runtime~main.3188e049.js} +1 -1
  11. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +3 -3
  12. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +3 -3
  13. solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
  14. solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html +3 -3
  15. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +3 -3
  16. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +3 -3
  17. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +3 -3
  18. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +3 -3
  19. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +3 -3
  20. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +3 -3
  21. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +3 -3
  22. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +3 -3
  23. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +3 -3
  24. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +3 -3
  25. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +3 -3
  26. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +3 -3
  27. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
  28. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +3 -3
  29. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +3 -3
  30. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +3 -3
  31. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +3 -3
  32. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +3 -3
  33. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +3 -3
  34. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +3 -3
  35. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +3 -3
  36. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +3 -3
  37. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +3 -3
  38. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +3 -3
  39. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +3 -3
  40. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +3 -3
  41. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +3 -3
  42. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +3 -3
  43. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +5 -5
  44. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +3 -3
  45. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +68 -3
  46. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +3 -3
  47. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +3 -3
  48. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +3 -3
  49. solace_agent_mesh/assets/docs/lunr-index-1757991496554.json +1 -0
  50. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  51. solace_agent_mesh/assets/docs/search-doc-1757991496554.json +1 -0
  52. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  53. solace_agent_mesh/cli/__init__.py +1 -1
  54. solace_agent_mesh/cli/commands/run_cmd.py +4 -7
  55. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-CAX9u8a7.js → authCallback-j1LW-wlq.js} +1 -1
  56. solace_agent_mesh/client/webui/frontend/static/assets/{client-DXU9SPI5.js → client-B9p_nFNA.js} +1 -1
  57. solace_agent_mesh/client/webui/frontend/static/assets/main-B9s_V9tJ.css +1 -0
  58. solace_agent_mesh/client/webui/frontend/static/assets/main-Dq4AJNvn.js +339 -0
  59. solace_agent_mesh/client/webui/frontend/static/assets/{vendor-B0BEKoAR.js → vendor-CS5YMf8a.js} +74 -69
  60. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  61. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  62. solace_agent_mesh/common/utils/pydantic_utils.py +56 -0
  63. solace_agent_mesh/config_portal/backend/plugin_catalog/registry_manager.py +6 -4
  64. solace_agent_mesh/gateway/base/app.py +58 -120
  65. solace_agent_mesh/gateway/http_sse/app.py +99 -150
  66. solace_agent_mesh/gateway/http_sse/component.py +57 -30
  67. solace_agent_mesh/gateway/http_sse/sse_event_buffer.py +87 -0
  68. solace_agent_mesh/gateway/http_sse/sse_manager.py +44 -23
  69. {solace_agent_mesh-1.3.3.dist-info → solace_agent_mesh-1.4.0.dist-info}/METADATA +1 -1
  70. {solace_agent_mesh-1.3.3.dist-info → solace_agent_mesh-1.4.0.dist-info}/RECORD +74 -71
  71. solace_agent_mesh/assets/docs/assets/js/42b3f8d8.3f34bf76.js +0 -1
  72. solace_agent_mesh/assets/docs/assets/js/9a09e75d.5a319fd4.js +0 -1
  73. solace_agent_mesh/assets/docs/lunr-index-1757873594308.json +0 -1
  74. solace_agent_mesh/assets/docs/search-doc-1757873594308.json +0 -1
  75. solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +0 -1
  76. solace_agent_mesh/client/webui/frontend/static/assets/main-DjoMeldu.js +0 -339
  77. /solace_agent_mesh/assets/docs/assets/js/{main.e82b32e6.js.LICENSE.txt → main.1de3da6a.js.LICENSE.txt} +0 -0
  78. {solace_agent_mesh-1.3.3.dist-info → solace_agent_mesh-1.4.0.dist-info}/WHEEL +0 -0
  79. {solace_agent_mesh-1.3.3.dist-info → solace_agent_mesh-1.4.0.dist-info}/entry_points.txt +0 -0
  80. {solace_agent_mesh-1.3.3.dist-info → solace_agent_mesh-1.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -12,7 +12,8 @@ from solace_ai_connector.common.log import log
12
12
  ensure_asyncio_compatibility()
13
13
  patch_adk()
14
14
 
15
- from typing import Any, Dict
15
+ from typing import Any, Dict, List, Optional, Union, Literal
16
+ from pydantic import Field, ValidationError, model_validator
16
17
  from solace_ai_connector.flow.app import App
17
18
 
18
19
  from ...common.a2a import (
@@ -25,6 +26,8 @@ from ...common.a2a import (
25
26
  from ...common.constants import DEFAULT_COMMUNICATION_TIMEOUT
26
27
  from ...agent.sac.component import SamAgentComponent
27
28
  from ...agent.utils.artifact_helpers import DEFAULT_SCHEMA_MAX_KEYS
29
+ from ...common.utils.pydantic_utils import SamConfigBase
30
+ from ..tools.tool_config_types import AnyToolConfig
28
31
 
29
32
  info = {
30
33
  "class_name": "SamAgentApp",
@@ -32,6 +35,323 @@ info = {
32
35
  }
33
36
 
34
37
 
38
+ # --- Pydantic Models for Configuration Validation ---
39
+
40
+
41
+ class AgentCardConfig(SamConfigBase):
42
+ """Configuration for the agent's self-description card."""
43
+
44
+ description: str = Field(
45
+ default="", description="Concise agent description for discovery."
46
+ )
47
+ defaultInputModes: List[str] = Field(
48
+ default=["text"], description="Supported input content types."
49
+ )
50
+ defaultOutputModes: List[str] = Field(
51
+ default=["text"], description="Supported output content types."
52
+ )
53
+ skills: List[Dict[str, Any]] = Field(
54
+ default_factory=list,
55
+ description="List of advertised agent skills (A2A AgentSkill structure).",
56
+ )
57
+ documentationUrl: Optional[str] = Field(
58
+ default=None, description="Optional URL for agent documentation."
59
+ )
60
+ provider: Optional[Dict[str, Any]] = Field(
61
+ default=None, description="Optional provider information (A2A AgentProvider structure)."
62
+ )
63
+
64
+
65
+ class AgentCardPublishingConfig(SamConfigBase):
66
+ """Configuration for publishing the agent card."""
67
+
68
+ interval_seconds: int = Field(
69
+ ..., description="Publish interval (seconds). <= 0 disables periodic publish."
70
+ )
71
+
72
+
73
+ class AgentDiscoveryConfig(SamConfigBase):
74
+ """Configuration for discovering other agents."""
75
+
76
+ enabled: bool = Field(default=True, description="Enable discovery and instruction injection.")
77
+
78
+
79
+ class InterAgentCommunicationConfig(SamConfigBase):
80
+ """Configuration for interacting with peer agents."""
81
+
82
+ allow_list: List[str] = Field(
83
+ default=["*"], description="Agent name patterns to allow delegation to."
84
+ )
85
+ deny_list: List[str] = Field(
86
+ default_factory=list, description="Agent name patterns to deny delegation to."
87
+ )
88
+ request_timeout_seconds: int = Field(
89
+ default=DEFAULT_COMMUNICATION_TIMEOUT, description="Timeout for peer requests (seconds)."
90
+ )
91
+
92
+
93
+ class AgentInitCleanupConfig(SamConfigBase):
94
+ """Configuration for custom agent initialization or cleanup functions."""
95
+
96
+ module: str = Field(
97
+ ...,
98
+ description="Python module path for the function (e.g., 'my_plugin.initializers').",
99
+ )
100
+ name: str = Field(..., description="Name of the function within the module.")
101
+ base_path: Optional[str] = Field(
102
+ default=None, description="Optional base path for module resolution if not in PYTHONPATH."
103
+ )
104
+ config: Dict[str, Any] = Field(
105
+ default_factory=dict, description="Configuration dictionary for the function."
106
+ )
107
+
108
+
109
+ class DataToolsConfig(SamConfigBase):
110
+ """Configuration for built-in data analysis tools."""
111
+
112
+ sqlite_memory_threshold_mb: int = Field(
113
+ default=100,
114
+ description="Size threshold (MB) for using in-memory vs. temp file SQLite DB for CSV input.",
115
+ )
116
+ max_result_preview_rows: int = Field(
117
+ default=50, description="Max rows to return in preview for SQL/JQ results."
118
+ )
119
+ max_result_preview_bytes: int = Field(
120
+ default=4096,
121
+ description="Max bytes to return in preview for SQL/JQ results (if row limit not hit first).",
122
+ )
123
+
124
+
125
+ class ExtractContentConfig(SamConfigBase):
126
+ """Configuration for the LLM-powered artifact extraction tool."""
127
+
128
+ supported_binary_mime_types: List[str] = Field(
129
+ default_factory=list,
130
+ description="List of binary MIME type patterns (e.g., 'image/png', 'image/*', 'video/mp4') that the tool should attempt to process using its internal LLM.",
131
+ )
132
+ model: Optional[Union[str, Dict[str, Any]]] = Field(
133
+ default=None,
134
+ description="Specifies the LLM for extraction. String (ADK LLMRegistry name) or dict (LiteLlm config). Defaults to agent's LLM.",
135
+ )
136
+
137
+
138
+ class McpProcessingConfig(SamConfigBase):
139
+ """Configuration for intelligent processing of MCP tool responses."""
140
+
141
+ enable_intelligent_processing: bool = Field(
142
+ default=True,
143
+ description="Enable intelligent content-aware processing of MCP responses. When disabled, falls back to raw JSON saving.",
144
+ )
145
+ enable_text_format_detection: bool = Field(
146
+ default=True,
147
+ description="Enable detection and parsing of structured text formats (CSV, JSON, YAML) within text content.",
148
+ )
149
+ enable_content_parsing: bool = Field(
150
+ default=True,
151
+ description="Enable parsing and validation of detected content formats for enhanced metadata.",
152
+ )
153
+ fallback_to_raw_on_error: bool = Field(
154
+ default=True, description="Fall back to raw JSON saving if intelligent processing fails."
155
+ )
156
+ save_raw_alongside_intelligent: bool = Field(
157
+ default=False,
158
+ description="Save both intelligent artifacts and raw JSON response for debugging/comparison.",
159
+ )
160
+ max_content_items: int = Field(
161
+ default=50,
162
+ description="Maximum number of content items to process from a single MCP response.",
163
+ )
164
+ max_single_item_size_mb: int = Field(
165
+ default=100,
166
+ description="Maximum size in MB for a single content item before skipping intelligent processing.",
167
+ )
168
+
169
+
170
+ class ArtifactServiceConfig(SamConfigBase):
171
+ """Configuration for the ADK Artifact Service."""
172
+
173
+ type: str = Field(..., description="Service type (e.g., 'memory', 'gcs', 'filesystem').")
174
+ base_path: Optional[str] = Field(
175
+ default=None, description="Base directory path (required for type 'filesystem')."
176
+ )
177
+ bucket_name: Optional[str] = Field(
178
+ default=None, description="GCS bucket name (required for type 'gcs')."
179
+ )
180
+ artifact_scope: Literal["namespace", "app", "custom"] = Field(
181
+ default="namespace", description="Process-wide scope for all artifact services."
182
+ )
183
+ artifact_scope_value: Optional[str] = Field(
184
+ default=None,
185
+ description="Custom identifier for artifact scope (required if artifact_scope is 'custom').",
186
+ )
187
+
188
+ @model_validator(mode="after")
189
+ def check_artifact_scope(self) -> "ArtifactServiceConfig":
190
+ if self.artifact_scope == "custom" and not self.artifact_scope_value:
191
+ raise ValueError(
192
+ "'artifact_scope_value' is required when 'artifact_scope' is 'custom'."
193
+ )
194
+ if self.artifact_scope != "custom" and self.artifact_scope_value:
195
+ log.warning(
196
+ "Configuration Warning: 'artifact_scope_value' is ignored when 'artifact_scope' is not 'custom'."
197
+ )
198
+ return self
199
+
200
+
201
+ class SessionServiceConfig(SamConfigBase):
202
+ """Configuration for the ADK Session Service."""
203
+
204
+ type: str = Field(..., description="Service type (e.g., 'memory', 'vertex_rag').")
205
+ default_behavior: Literal["PERSISTENT", "RUN_BASED"] = Field(
206
+ default="PERSISTENT", description="Default behavior for session service."
207
+ )
208
+
209
+
210
+ class SamAgentAppConfig(SamConfigBase):
211
+ """Pydantic model for the complete agent application configuration."""
212
+
213
+ namespace: str = Field(
214
+ ..., description="Absolute topic prefix for A2A communication (e.g., 'myorg/dev')."
215
+ )
216
+ agent_name: str = Field(..., description="Unique name for this ADK agent instance.")
217
+ model: Union[str, Dict[str, Any]] = Field(
218
+ ..., description="ADK model name (string) or BaseLlm config dict."
219
+ )
220
+ instruction: Any = Field(
221
+ default="",
222
+ description="User-provided instructions for the ADK agent (string or invoke block).",
223
+ )
224
+ global_instruction: Any = Field(
225
+ default="",
226
+ description="User-provided global instructions for the agent tree (string or invoke block).",
227
+ )
228
+ tools: List[AnyToolConfig] = Field(
229
+ default_factory=list,
230
+ description="List of tool configurations (python, mcp, built-in). Each tool can have 'required_scopes'.",
231
+ )
232
+ supports_streaming: bool = Field(
233
+ default=False, description="Whether this host supports A2A streaming (tasks/sendSubscribe)."
234
+ )
235
+ planner: Optional[Dict[str, Any]] = Field(
236
+ default=None, description="Optional configuration for an ADK planner."
237
+ )
238
+ code_executor: Optional[Dict[str, Any]] = Field(
239
+ default=None, description="Optional configuration for an ADK code executor."
240
+ )
241
+ inject_current_time: bool = Field(
242
+ default=True, description="Whether to inject the current time into the agent's instruction."
243
+ )
244
+ session_service: SessionServiceConfig = Field(
245
+ default_factory=lambda: SessionServiceConfig(type="memory"),
246
+ description="Configuration for ADK Session Service.",
247
+ )
248
+ artifact_service: ArtifactServiceConfig = Field(
249
+ default_factory=lambda: ArtifactServiceConfig(type="memory"),
250
+ description="Configuration for ADK Artifact Service.",
251
+ )
252
+ memory_service: Dict[str, Any] = Field(
253
+ default={"type": "memory"},
254
+ description="Configuration for ADK Memory Service (defaults to memory).",
255
+ )
256
+ tool_output_save_threshold_bytes: int = Field(
257
+ default=2048,
258
+ description="If any tool's processed output exceeds this size (bytes), its full content is saved as a new ADK artifact.",
259
+ )
260
+ tool_output_llm_return_max_bytes: int = Field(
261
+ default=4096,
262
+ description="Maximum size (bytes) of any tool's output content returned directly to the LLM.",
263
+ )
264
+ mcp_tool_response_save_threshold_bytes: int = Field(
265
+ default=2048,
266
+ description="Threshold in bytes above which MCP tool responses are saved as artifacts.",
267
+ )
268
+ mcp_tool_llm_return_max_bytes: int = Field(
269
+ default=4096,
270
+ description="Maximum size in bytes of MCP tool response content returned directly to the LLM.",
271
+ )
272
+ artifact_handling_mode: Literal["ignore", "embed", "reference"] = Field(
273
+ default="ignore", description="How to represent created artifacts in A2A messages."
274
+ )
275
+ schema_max_keys: int = Field(
276
+ default=DEFAULT_SCHEMA_MAX_KEYS,
277
+ ge=0,
278
+ description="Maximum number of dictionary keys to inspect during schema inference.",
279
+ )
280
+ enable_embed_resolution: bool = Field(
281
+ default=True,
282
+ description="Enable early-stage processing of dynamic embeds and inject related instructions.",
283
+ )
284
+ enable_auto_continuation: bool = Field(
285
+ default=True,
286
+ description="If true, automatically attempts to continue LLM generation if it is interrupted by a token limit.",
287
+ )
288
+ stream_batching_threshold_bytes: int = Field(
289
+ default=0,
290
+ description="Minimum size in bytes for accumulated text from LLM stream before sending a status update.",
291
+ )
292
+ max_message_size_bytes: int = Field(
293
+ default=10_000_000,
294
+ description="Maximum allowed message size in bytes before rejecting publication.",
295
+ )
296
+ enable_artifact_content_instruction: bool = Field(
297
+ default=True,
298
+ description="Inject instructions about the 'artifact_content' embed type.",
299
+ )
300
+ agent_card: AgentCardConfig = Field(
301
+ ..., description="Static definition of this agent's capabilities for discovery."
302
+ )
303
+ agent_card_publishing: AgentCardPublishingConfig = Field(
304
+ ..., description="Settings for publishing the agent card."
305
+ )
306
+ agent_discovery: AgentDiscoveryConfig = Field(
307
+ default_factory=AgentDiscoveryConfig,
308
+ description="Settings for discovering other agents and injecting related instructions.",
309
+ )
310
+ inter_agent_communication: InterAgentCommunicationConfig = Field(
311
+ default_factory=InterAgentCommunicationConfig,
312
+ description="Configuration for interacting with peer agents.",
313
+ )
314
+ inject_system_purpose: bool = Field(
315
+ default=False,
316
+ description="If true, injects the system_purpose received from the gateway into the agent's prompt.",
317
+ )
318
+ inject_response_format: bool = Field(
319
+ default=False,
320
+ description="If true, injects the response_format received from the gateway into the agent's prompt.",
321
+ )
322
+ inject_user_profile: bool = Field(
323
+ default=False,
324
+ description="If true, injects the user_profile received from the gateway into the agent's prompt.",
325
+ )
326
+ agent_init_function: Optional[AgentInitCleanupConfig] = Field(
327
+ default=None, description="Configuration for the agent's custom initialization function."
328
+ )
329
+ agent_cleanup_function: Optional[AgentInitCleanupConfig] = Field(
330
+ default=None, description="Configuration for the agent's custom cleanup function."
331
+ )
332
+ text_artifact_content_max_length: int = Field(
333
+ default=1000,
334
+ ge=100,
335
+ le=100000,
336
+ description="Maximum character length for text-based artifact content.",
337
+ )
338
+ max_llm_calls_per_task: int = Field(
339
+ default=20, description="Maximum number of LLM calls allowed for a single A2A task."
340
+ )
341
+ data_tools_config: DataToolsConfig = Field(
342
+ default_factory=DataToolsConfig,
343
+ description="Runtime configuration parameters for built-in data analysis tools.",
344
+ )
345
+ extract_content_from_artifact_config: ExtractContentConfig = Field(
346
+ default_factory=ExtractContentConfig,
347
+ description="Configuration for the LLM-powered artifact extraction tool.",
348
+ )
349
+ mcp_intelligent_processing: McpProcessingConfig = Field(
350
+ default_factory=McpProcessingConfig,
351
+ description="Configuration for intelligent processing of MCP tool responses.",
352
+ )
353
+
354
+
35
355
  class SamAgentApp(App):
36
356
  """
37
357
  Custom App class for SAM Agent Host that automatically generates
@@ -40,635 +360,30 @@ class SamAgentApp(App):
40
360
  It also defines the expected configuration structure via `app_schema`.
41
361
  """
42
362
 
43
- app_schema = {
44
- "config_parameters": [
45
- # --- A2A Config (Flattened) ---
46
- {
47
- "name": "namespace",
48
- "required": True,
49
- "type": "string",
50
- "description": "Absolute topic prefix for A2A communication (e.g., 'myorg/dev').",
51
- },
52
- {
53
- "name": "supports_streaming",
54
- "required": False,
55
- "type": "boolean",
56
- "default": False,
57
- "description": "Whether this host supports A2A streaming (tasks/sendSubscribe).",
58
- },
59
- # --- Core ADK Agent Definition ---
60
- {
61
- "name": "agent_name",
62
- "required": True,
63
- "type": "string",
64
- "description": "Unique name for this ADK agent instance.",
65
- },
66
- {
67
- "name": "model",
68
- "required": True,
69
- "type": "any",
70
- "description": "ADK model name (string) or BaseLlm config dict.",
71
- },
72
- {
73
- "name": "instruction",
74
- "required": False,
75
- "type": "any",
76
- "default": "",
77
- "description": "User-provided instructions for the ADK agent (string or invoke block).",
78
- },
79
- {
80
- "name": "global_instruction",
81
- "required": False,
82
- "type": "any",
83
- "default": "",
84
- "description": "User-provided global instructions for the agent tree (string or invoke block).",
85
- },
86
- {
87
- "name": "tools",
88
- "required": False,
89
- "type": "list",
90
- "default": [],
91
- "description": "List of tool configurations (python, mcp, built-in). Each tool can have 'required_scopes'.",
92
- "items": { # Schema for each item in the tools list
93
- "type": "object",
94
- "properties": {
95
- "tool_type": {
96
- "type": "string",
97
- "required": True,
98
- "enum": ["python", "mcp", "builtin", "builtin-group"],
99
- "description": "Type of the tool.",
100
- },
101
- "tool_name": {
102
- "type": "string",
103
- "required": False, # Required for mcp/builtin, optional for python
104
- "description": "Name of the tool (e.g., ADK built-in name, specific MCP tool name). Overwrite function_name for python tools.",
105
- },
106
- "tool_description": {
107
- "type": "string",
108
- "required": False, # Optional, Only for python
109
- "description": "Description of the tool to overwrite for python tools. Overwrite the python function description",
110
- },
111
- "component_module": { # For python tools
112
- "type": "string",
113
- "required": False,
114
- "description": "Python module for 'python' tool type.",
115
- },
116
- "function_name": { # For python tools
117
- "type": "string",
118
- "required": False,
119
- "description": "Function name within the module for 'python' tool type.",
120
- },
121
- "component_base_path": { # For python tools
122
- "type": "string",
123
- "required": False,
124
- "description": "Base path for 'python' tool module resolution.",
125
- },
126
- "connection_params": { # For mcp tools
127
- "type": "object",
128
- "required": False,
129
- "description": "Connection parameters for 'mcp' tool type.",
130
- },
131
- "environment_variables": { # For mcp tools (stdio)
132
- "type": "object",
133
- "required": False,
134
- "description": "Environment variables for 'mcp' tool type with stdio connection.",
135
- },
136
- "required_scopes": {
137
- "type": "list",
138
- "required": False,
139
- "default": [],
140
- "description": "List of scope strings required to use this specific tool.",
141
- "items": {"type": "string"},
142
- },
143
- "tool_config": {
144
- "type": "object",
145
- "required": False,
146
- "default": {},
147
- "description": "A dictionary holding specific configuration for this tool instance (e.g., API keys, model names for an image generation tool).",
148
- "additionalProperties": True,
149
- },
150
- },
151
- },
152
- },
153
- {
154
- "name": "data_tools_config",
155
- "required": False,
156
- "type": "object",
157
- "default": {},
158
- "description": "Runtime configuration parameters for built-in data analysis tools.",
159
- "properties": {
160
- "sqlite_memory_threshold_mb": {
161
- "type": "integer",
162
- "required": False,
163
- "default": 100,
164
- "description": "Size threshold (MB) for using in-memory vs. temp file SQLite DB for CSV input.",
165
- },
166
- "max_result_preview_rows": {
167
- "type": "integer",
168
- "required": False,
169
- "default": 50,
170
- "description": "Max rows to return in preview for SQL/JQ results.",
171
- },
172
- "max_result_preview_bytes": {
173
- "type": "integer",
174
- "required": False,
175
- "default": 4096,
176
- "description": "Max bytes to return in preview for SQL/JQ results (if row limit not hit first).",
177
- },
178
- },
179
- },
180
- {
181
- "name": "planner",
182
- "required": False,
183
- "type": "object",
184
- "default": None,
185
- "description": "Optional configuration for an ADK planner.",
186
- },
187
- {
188
- "name": "code_executor",
189
- "required": False,
190
- "type": "object",
191
- "default": None,
192
- "description": "Optional configuration for an ADK code executor.",
193
- },
194
- {
195
- "name": "inject_current_time",
196
- "required": False,
197
- "type": "boolean",
198
- "default": True,
199
- "description": "Whether to inject the current time into the agent's instruction.",
200
- },
201
- # --- ADK Services Configuration ---
202
- {
203
- "name": "session_service",
204
- "required": True,
205
- "type": "object",
206
- "description": "Configuration for ADK Session Service (e.g., { type: 'memory' }).",
207
- "default": {"type": "memory", "default_behavior": "PERSISTENT"},
208
- "properties": {
209
- "type": {
210
- "type": "string",
211
- "required": True,
212
- "description": "Service type (e.g., 'memory', 'vertex_rag').",
213
- },
214
- "default_behavior": {
215
- "type": "string",
216
- "required": False,
217
- "default": "PERSISTENT",
218
- "enum": ["PERSISTENT", "RUN_BASED"],
219
- "description": "Default behavior for session service: 'PERSISTENT' (default) or 'RUN_BASED' for how long to keep the session history.",
220
- },
221
- },
222
- },
223
- {
224
- "name": "artifact_service",
225
- "required": False,
226
- "type": "object",
227
- "default": {"type": "memory"},
228
- "description": "Configuration for ADK Artifact Service (defaults to memory).",
229
- "properties": {
230
- "type": {
231
- "type": "string",
232
- "required": True,
233
- "description": "Service type (e.g., 'memory', 'gcs', 'filesystem').",
234
- },
235
- "base_path": {
236
- "type": "string",
237
- "required": False, # Required only if type is filesystem
238
- "description": "Base directory path (required for type 'filesystem').",
239
- },
240
- "bucket_name": {
241
- "type": "string",
242
- "required": False, # Required only if type is gcs
243
- "description": "GCS bucket name (required for type 'gcs').",
244
- },
245
- "artifact_scope": {
246
- "type": "string",
247
- "required": False,
248
- "default": "namespace",
249
- "enum": ["namespace", "app"],
250
- "description": "Process-wide scope for all artifact services. 'namespace' (default): shared by all components in the namespace. 'app': isolated by agent/gateway name. This setting must be consistent for all components in the same process.",
251
- },
252
- "artifact_scope_value": {
253
- "type": "string",
254
- "required": False,
255
- "default": None,
256
- "description": "Custom identifier for artifact scope (required if artifact_scope is 'custom').",
257
- },
258
- },
259
- },
260
- {
261
- "name": "memory_service",
262
- "required": False,
263
- "type": "object",
264
- "default": {"type": "memory"},
265
- "description": "Configuration for ADK Memory Service (defaults to memory).",
266
- },
267
- # --- Tool Output Handling (Generalized) ---
268
- {
269
- "name": "tool_output_save_threshold_bytes",
270
- "required": False,
271
- "type": "integer",
272
- "default": 2048, # 2KB
273
- "description": "If any tool's processed output (e.g., extracted content from an artifact, MCP response) exceeds this size (bytes), its full content is saved as a new ADK artifact. This threshold should generally be less than or equal to tool_output_llm_return_max_bytes.",
274
- },
275
- {
276
- "name": "tool_output_llm_return_max_bytes",
277
- "required": False,
278
- "type": "integer",
279
- "default": 4096, # 4KB
280
- "description": "Maximum size (bytes) of any tool's (potentially summarized or original) output content returned directly to the LLM. If exceeded, the content will be truncated, and the full original output will be saved as an artifact if not already.",
281
- },
282
- # --- LLM-Powered Artifact Extraction Tool Config ---
283
- {
284
- "name": "extract_content_from_artifact_config",
285
- "required": False,
286
- "type": "object",
287
- "default": {},
288
- "description": "Configuration for the LLM-powered artifact extraction tool.",
289
- "properties": {
290
- "supported_binary_mime_types": {
291
- "type": "list",
292
- "required": False,
293
- "default": [],
294
- "items": {"type": "string"},
295
- "description": "List of binary MIME type patterns (e.g., 'image/png', 'image/*', 'video/mp4') that the tool should attempt to process using its internal LLM.",
296
- },
297
- "model": {
298
- "type": "any", # Union[str, Dict[str, Any]]
299
- "required": False,
300
- "default": None,
301
- "description": "Specifies the LLM for extraction. String (ADK LLMRegistry name) or dict (LiteLlm config). Defaults to agent's LLM.",
302
- },
303
- },
304
- },
305
- # --- MCP Intelligent Processing Config ---
306
- {
307
- "name": "mcp_intelligent_processing",
308
- "required": False,
309
- "type": "object",
310
- "default": {},
311
- "description": "Configuration for intelligent processing of MCP tool responses into typed artifacts.",
312
- "properties": {
313
- "enable_intelligent_processing": {
314
- "type": "boolean",
315
- "required": False,
316
- "default": True,
317
- "description": "Enable intelligent content-aware processing of MCP responses. When disabled, falls back to raw JSON saving.",
318
- },
319
- "enable_text_format_detection": {
320
- "type": "boolean",
321
- "required": False,
322
- "default": True,
323
- "description": "Enable detection and parsing of structured text formats (CSV, JSON, YAML) within text content.",
324
- },
325
- "enable_content_parsing": {
326
- "type": "boolean",
327
- "required": False,
328
- "default": True,
329
- "description": "Enable parsing and validation of detected content formats for enhanced metadata.",
330
- },
331
- "fallback_to_raw_on_error": {
332
- "type": "boolean",
333
- "required": False,
334
- "default": True,
335
- "description": "Fall back to raw JSON saving if intelligent processing fails.",
336
- },
337
- "save_raw_alongside_intelligent": {
338
- "type": "boolean",
339
- "required": False,
340
- "default": False,
341
- "description": "Save both intelligent artifacts and raw JSON response for debugging/comparison.",
342
- },
343
- "max_content_items": {
344
- "type": "integer",
345
- "required": False,
346
- "default": 50,
347
- "description": "Maximum number of content items to process from a single MCP response.",
348
- },
349
- "max_single_item_size_mb": {
350
- "type": "integer",
351
- "required": False,
352
- "default": 100,
353
- "description": "Maximum size in MB for a single content item before skipping intelligent processing.",
354
- },
355
- },
356
- },
357
- # --- MCP Tool Response Thresholds ---
358
- {
359
- "name": "mcp_tool_response_save_threshold_bytes",
360
- "required": False,
361
- "type": "integer",
362
- "default": 2048,
363
- "description": "Threshold in bytes above which MCP tool responses are saved as artifacts.",
364
- },
365
- {
366
- "name": "mcp_tool_llm_return_max_bytes",
367
- "required": False,
368
- "type": "integer",
369
- "default": 4096,
370
- "description": "Maximum size in bytes of MCP tool response content returned directly to the LLM.",
371
- },
372
- # --- Artifact Handling ---
373
- {
374
- "name": "artifact_handling_mode",
375
- "required": False,
376
- "type": "string",
377
- "default": "ignore",
378
- "description": "How to represent created artifacts in A2A messages: 'ignore' (default), 'embed' (include base64 data), 'reference' (include fetch URI).",
379
- },
380
- # --- Schema Inference Config ---
381
- {
382
- "name": "schema_max_keys",
383
- "required": False,
384
- "type": "integer",
385
- "default": DEFAULT_SCHEMA_MAX_KEYS,
386
- "description": "Maximum number of dictionary keys to inspect during schema inference.",
387
- },
388
- # --- Embed Resolution Config ---
389
- {
390
- "name": "enable_embed_resolution",
391
- "required": False,
392
- "type": "boolean",
393
- "default": True,
394
- "description": "Enable early-stage processing (state, math, etc.) of dynamic embeds and inject related instructions.",
395
- },
396
- {
397
- "name": "enable_auto_continuation",
398
- "required": False,
399
- "type": "boolean",
400
- "default": True,
401
- "description": "If true, automatically attempts to continue LLM generation if it is interrupted by a token limit.",
402
- },
403
- {
404
- "name": "stream_batching_threshold_bytes",
405
- "required": False,
406
- "type": "integer",
407
- "default": 0,
408
- "description": "Minimum size in bytes for accumulated text from LLM stream before sending a status update. If 0 or less, batching is disabled and updates are sent per chunk. Final LLM chunks are always sent regardless of this threshold.",
409
- },
410
- {
411
- "name": "max_message_size_bytes",
412
- "required": False,
413
- "type": "integer",
414
- "default": 10_000_000,
415
- "description": "Maximum allowed message size in bytes before rejecting publication to prevent broker disconnections. Default: 10MB",
416
- },
417
- {
418
- "name": "enable_artifact_content_instruction",
419
- "required": False,
420
- "type": "boolean",
421
- "default": True,
422
- "description": "Inject instructions about the 'artifact_content' embed type (resolved late-stage, typically by a gateway).",
423
- },
424
- # --- Agent Card Definition (Simplified) ---
425
- {
426
- "name": "agent_card",
427
- "required": True,
428
- "type": "object",
429
- "description": "Static definition of this agent's capabilities for discovery.",
430
- "properties": {
431
- "description": {
432
- "type": "string",
433
- "required": False,
434
- "default": "",
435
- "description": "Concise agent description for discovery.",
436
- },
437
- "defaultInputModes": {
438
- "type": "list",
439
- "required": False,
440
- "default": ["text"],
441
- "description": "Supported input content types.",
442
- },
443
- "defaultOutputModes": {
444
- "type": "list",
445
- "required": False,
446
- "default": ["text"],
447
- "description": "Supported output content types.",
448
- },
449
- "skills": {
450
- "type": "list",
451
- "required": False,
452
- "default": [],
453
- "description": "List of advertised agent skills (A2A AgentSkill structure).",
454
- },
455
- "documentationUrl": {
456
- "type": "string",
457
- "required": False,
458
- "default": None,
459
- "description": "Optional URL for agent documentation.",
460
- },
461
- "provider": {
462
- "type": "object",
463
- "required": False,
464
- "default": None,
465
- "description": "Optional provider information (A2A AgentProvider structure).",
466
- "properties": {
467
- "organization": {"type": "string", "required": True},
468
- "url": {"type": "string", "required": False},
469
- },
470
- },
471
- },
472
- },
473
- # --- Agent Discovery & Communication ---
474
- {
475
- "name": "agent_card_publishing",
476
- "required": True,
477
- "type": "object",
478
- "description": "Settings for publishing the agent card.",
479
- "properties": {
480
- "interval_seconds": {
481
- "type": "integer",
482
- "required": True,
483
- "description": "Publish interval (seconds). <= 0 disables periodic publish.",
484
- }
485
- },
486
- },
487
- {
488
- "name": "agent_discovery",
489
- "required": True,
490
- "type": "object",
491
- "description": "Settings for discovering other agents and injecting related instructions.",
492
- "properties": {
493
- "enabled": {
494
- "type": "boolean",
495
- "required": False,
496
- "default": True,
497
- "description": "Enable discovery and instruction injection.",
498
- }
499
- },
500
- },
501
- {
502
- "name": "inter_agent_communication",
503
- "required": True,
504
- "type": "object",
505
- "description": "Configuration for interacting with peer agents.",
506
- "properties": {
507
- "allow_list": {
508
- "type": "list",
509
- "required": False,
510
- "default": ["*"],
511
- "description": "Agent name patterns to allow delegation to.",
512
- },
513
- "deny_list": {
514
- "type": "list",
515
- "required": False,
516
- "default": [],
517
- "description": "Agent name patterns to deny delegation to.",
518
- },
519
- "request_timeout_seconds": {
520
- "type": "integer",
521
- "required": False,
522
- "default": DEFAULT_COMMUNICATION_TIMEOUT,
523
- "description": "Timeout for peer requests (seconds).",
524
- },
525
- },
526
- },
527
- {
528
- "name": "inject_system_purpose",
529
- "required": False,
530
- "type": "boolean",
531
- "default": False,
532
- "description": "If true, injects the system_purpose received from the gateway (via task metadata) into the agent's prompt.",
533
- },
534
- {
535
- "name": "inject_response_format",
536
- "required": False,
537
- "type": "boolean",
538
- "default": False,
539
- "description": "If true, injects the response_format received from the gateway (via task metadata) into the agent's prompt.",
540
- },
541
- {
542
- "name": "inject_user_profile",
543
- "required": False,
544
- "type": "boolean",
545
- "default": False,
546
- "description": "If true, injects the user_profile received from the gateway (via task metadata) into the agent's prompt.",
547
- },
548
- # --- Configurable Agent Initialization ---
549
- {
550
- "name": "agent_init_function",
551
- "required": False,
552
- "type": "object",
553
- "description": "Configuration for the agent's custom initialization function.",
554
- "properties": {
555
- "module": {
556
- "type": "string",
557
- "required": True,
558
- "description": "Python module path for the init function (e.g., 'my_plugin.initializers').",
559
- },
560
- "name": {
561
- "type": "string",
562
- "required": True,
563
- "description": "Name of the init function within the module.",
564
- },
565
- "base_path": {
566
- "type": "string",
567
- "required": False,
568
- "description": "Optional base path for module resolution if not in PYTHONPATH.",
569
- },
570
- "config": {
571
- "type": "object",
572
- "required": False,
573
- "default": {},
574
- "additionalProperties": True,
575
- "description": "Configuration dictionary for the init function, validated by its Pydantic model.",
576
- },
577
- },
578
- },
579
- # --- Configurable Agent Cleanup ---
580
- {
581
- "name": "agent_cleanup_function",
582
- "required": False,
583
- "type": "object",
584
- "description": "Configuration for the agent's custom cleanup function.",
585
- "properties": {
586
- "module": {
587
- "type": "string",
588
- "required": True,
589
- "description": "Python module path for the cleanup function.",
590
- },
591
- "name": {
592
- "type": "string",
593
- "required": True,
594
- "description": "Name of the cleanup function within the module.",
595
- },
596
- "base_path": {
597
- "type": "string",
598
- "required": False,
599
- "description": "Optional base path for module resolution.",
600
- },
601
- },
602
- },
603
- {
604
- "name": "text_artifact_content_max_length",
605
- "required": False,
606
- "type": "integer",
607
- "default": 1000,
608
- "minimum": 100,
609
- "maximum": 100000,
610
- "description": "Maximum character length for text-based artifact content (100-100000 characters). Binary artifacts are unaffected.",
611
- },
612
- {
613
- "name": "max_llm_calls_per_task",
614
- "required": False,
615
- "type": "integer",
616
- "default": 20,
617
- "description": "Maximum number of LLM calls allowed for a single A2A task. A value of 0 or less means unlimited.",
618
- },
619
- ]
620
- }
363
+ # The app_schema dictionary is now redundant for validation but can be kept for documentation
364
+ # or for frameworks that might inspect it. For now, we will remove it.
365
+ app_schema = {}
621
366
 
622
367
  def __init__(self, app_info: Dict[str, Any], **kwargs):
623
368
  log.debug("Initializing A2A_ADK_App...")
624
369
 
625
- app_config = app_info.get("app_config", {})
370
+ app_config_dict = app_info.get("app_config", {})
371
+
372
+ try:
373
+ # Validate the raw dict, cleaning None values to allow defaults to apply
374
+ app_config = SamAgentAppConfig.model_validate_and_clean(app_config_dict)
375
+ # Overwrite the raw dict with the validated object for downstream use
376
+ app_info["app_config"] = app_config
377
+ except ValidationError as e:
378
+ log.error("Agent configuration validation failed:\n%s", e)
379
+ raise ValueError(f"Invalid agent configuration: {e}") from e
380
+
381
+ # The rest of the method can now safely use .get() on the app_config object,
382
+ # ensuring full backward compatibility.
626
383
  namespace = app_config.get("namespace")
627
384
  agent_name = app_config.get("agent_name")
628
385
  broker_request_response = app_info.get("broker_request_response")
629
386
 
630
- if not namespace or not isinstance(namespace, str):
631
- raise ValueError(
632
- "Internal Error: Namespace missing or invalid after validation."
633
- )
634
- if not agent_name or not isinstance(agent_name, str):
635
- raise ValueError(
636
- "Internal Error: Agent name missing or invalid after validation."
637
- )
638
-
639
- artifact_mode = app_config.get("artifact_handling_mode", "ignore").lower()
640
- if artifact_mode not in ["ignore", "embed", "reference"]:
641
- log.warning(
642
- "Invalid 'artifact_handling_mode' value '%s' in app_config. Using 'ignore'. Allowed values: 'ignore', 'embed', 'reference'.",
643
- artifact_mode,
644
- )
645
- app_config["artifact_handling_mode"] = "ignore"
646
-
647
- schema_max_keys = app_config.get("schema_max_keys", DEFAULT_SCHEMA_MAX_KEYS)
648
- if not isinstance(schema_max_keys, int) or schema_max_keys < 0:
649
- log.warning(
650
- "Invalid 'schema_max_keys' value '%s' in app_config. Using default: %d.",
651
- schema_max_keys,
652
- DEFAULT_SCHEMA_MAX_KEYS,
653
- )
654
- app_config["schema_max_keys"] = DEFAULT_SCHEMA_MAX_KEYS
655
-
656
- artifact_service_config = app_config.get("artifact_service", {})
657
- if artifact_service_config.get("type") == "filesystem":
658
- artifact_scope = artifact_service_config.get("artifact_scope", "namespace")
659
- if artifact_scope == "custom" and not artifact_service_config.get(
660
- "artifact_scope_value"
661
- ):
662
- raise ValueError(
663
- "Configuration Error: 'artifact_scope_value' is required when 'artifact_scope' is 'custom'."
664
- )
665
- if artifact_scope != "custom" and artifact_service_config.get(
666
- "artifact_scope_value"
667
- ):
668
- log.warning(
669
- "Configuration Warning: 'artifact_scope_value' is ignored when 'artifact_scope' is not 'custom'."
670
- )
671
-
672
387
  log.info(
673
388
  "Configuring A2A_ADK_App for Agent: '%s' in Namespace: '%s'",
674
389
  agent_name,