solace-agent-mesh 1.1.0__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 (139) hide show
  1. solace_agent_mesh/agent/adk/runner.py +18 -12
  2. solace_agent_mesh/agent/adk/services.py +3 -3
  3. solace_agent_mesh/agent/protocol/event_handlers.py +27 -21
  4. solace_agent_mesh/agent/sac/app.py +1 -1
  5. solace_agent_mesh/agent/sac/component.py +0 -1
  6. solace_agent_mesh/assets/docs/404.html +2 -2
  7. solace_agent_mesh/assets/docs/assets/js/{main.a75ecc0d.js → main.08d30374.js} +2 -2
  8. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +2 -2
  9. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +2 -2
  10. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +2 -2
  11. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +2 -2
  12. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +2 -2
  13. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +2 -2
  14. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +2 -2
  15. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +2 -2
  16. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +2 -2
  17. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +2 -2
  18. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +2 -2
  19. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +2 -2
  20. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +2 -2
  21. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +2 -2
  22. solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +2 -2
  23. solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html +2 -2
  24. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +2 -2
  25. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +2 -2
  26. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +2 -2
  27. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +2 -2
  28. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +2 -2
  29. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +2 -2
  30. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +2 -2
  31. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +2 -2
  32. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +2 -2
  33. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +2 -2
  34. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +2 -2
  35. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +2 -2
  36. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +2 -2
  37. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +2 -2
  38. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +2 -2
  39. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +2 -2
  40. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +2 -2
  41. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +2 -2
  42. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +2 -2
  43. solace_agent_mesh/assets/docs/lunr-index-1757433031159.json +1 -0
  44. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  45. solace_agent_mesh/assets/docs/search-doc-1757433031159.json +1 -0
  46. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  47. solace_agent_mesh/cli/__init__.py +1 -1
  48. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
  49. solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
  50. solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
  51. solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
  52. solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
  53. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
  54. solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
  55. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
  56. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
  57. solace_agent_mesh/cli/commands/run_cmd.py +5 -3
  58. solace_agent_mesh/cli/utils.py +68 -12
  59. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-vY5eu2lI.js +1 -0
  60. solace_agent_mesh/client/webui/frontend/static/assets/client-BeBkzgWW.js +25 -0
  61. solace_agent_mesh/client/webui/frontend/static/assets/main-Bjys1KQs.js +339 -0
  62. solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
  63. solace_agent_mesh/client/webui/frontend/static/assets/vendor-CE0AeXyK.js +395 -0
  64. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
  65. solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
  66. solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
  67. solace_agent_mesh/config_portal/backend/common.py +2 -2
  68. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
  69. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
  70. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  71. solace_agent_mesh/evaluation/message_organizer.py +35 -56
  72. solace_agent_mesh/evaluation/run.py +26 -5
  73. solace_agent_mesh/evaluation/subscriber.py +35 -10
  74. solace_agent_mesh/evaluation/summary_builder.py +27 -34
  75. solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
  76. solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
  77. solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
  78. solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
  79. solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
  80. solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
  81. solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
  82. solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
  83. solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
  84. solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
  85. solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
  86. solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
  87. solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
  88. solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
  89. solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
  90. solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
  91. solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
  92. solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
  93. solace_agent_mesh/gateway/http_sse/app.py +31 -1
  94. solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
  95. solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
  96. solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
  97. solace_agent_mesh/gateway/http_sse/component.py +224 -62
  98. solace_agent_mesh/gateway/http_sse/dependencies.py +142 -39
  99. solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
  100. solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
  101. solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
  102. solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
  103. solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
  104. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
  105. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
  106. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
  107. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
  108. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
  109. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
  110. solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
  111. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
  112. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
  113. solace_agent_mesh/gateway/http_sse/main.py +289 -85
  114. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +121 -54
  115. solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
  116. solace_agent_mesh/gateway/http_sse/routers/tasks.py +83 -2
  117. solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
  118. solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
  119. solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
  120. solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
  121. solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
  122. solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
  123. solace_agent_mesh/templates/shared_config.yaml +4 -5
  124. solace_agent_mesh/templates/webui.yaml +8 -10
  125. {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/METADATA +5 -3
  126. {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/RECORD +130 -91
  127. solace_agent_mesh/assets/docs/lunr-index-1756992446316.json +0 -1
  128. solace_agent_mesh/assets/docs/search-doc-1756992446316.json +0 -1
  129. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
  130. solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
  131. solace_agent_mesh/client/webui/frontend/static/assets/main-C0jZjYa8.js +0 -699
  132. solace_agent_mesh/client/webui/frontend/static/assets/main-CCeG324-.css +0 -1
  133. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
  134. solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -85
  135. solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
  136. /solace_agent_mesh/assets/docs/assets/js/{main.a75ecc0d.js.LICENSE.txt → main.08d30374.js.LICENSE.txt} +0 -0
  137. {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/WHEEL +0 -0
  138. {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/entry_points.txt +0 -0
  139. {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -1 +1 @@
1
- window.__remixManifest={"entry":{"module":"/assets/entry.client-mvZjNKiz.js","imports":["/assets/index-DzNKzXrc.js","/assets/components-Rk0n-9cK.js"],"css":[]},"routes":{"root":{"id":"root","path":"","hasAction":false,"hasLoader":false,"hasClientAction":false,"hasClientLoader":false,"hasErrorBoundary":false,"module":"/assets/root-BWvk5-gF.js","imports":["/assets/index-DzNKzXrc.js","/assets/components-Rk0n-9cK.js"],"css":["/assets/root-DxRwaWiE.css"]},"routes/_index":{"id":"routes/_index","parentId":"root","index":true,"hasAction":false,"hasLoader":false,"hasClientAction":false,"hasClientLoader":false,"hasErrorBoundary":false,"module":"/assets/_index-Bym6YkMd.js","imports":["/assets/index-DzNKzXrc.js"],"css":[]}},"url":"/assets/manifest-d845808d.js","version":"d845808d"};
1
+ window.__remixManifest={"entry":{"module":"/assets/entry.client-mvZjNKiz.js","imports":["/assets/index-DzNKzXrc.js","/assets/components-Rk0n-9cK.js"],"css":[]},"routes":{"root":{"id":"root","path":"","hasAction":false,"hasLoader":false,"hasClientAction":false,"hasClientLoader":false,"hasErrorBoundary":false,"module":"/assets/root-BWvk5-gF.js","imports":["/assets/index-DzNKzXrc.js","/assets/components-Rk0n-9cK.js"],"css":["/assets/root-DxRwaWiE.css"]},"routes/_index":{"id":"routes/_index","parentId":"root","index":true,"hasAction":false,"hasLoader":false,"hasClientAction":false,"hasClientLoader":false,"hasErrorBoundary":false,"module":"/assets/_index-bFMKlzKf.js","imports":["/assets/index-DzNKzXrc.js"],"css":[]}},"url":"/assets/manifest-89db7c30.js","version":"89db7c30"};
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/assets/root-DxRwaWiE.css"/><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous"/><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&amp;display=swap"/></head><body><p>Loading...</p><link rel="modulepreload" href="/assets/manifest-d845808d.js"/><link rel="modulepreload" href="/assets/entry.client-mvZjNKiz.js"/><link rel="modulepreload" href="/assets/index-DzNKzXrc.js"/><link rel="modulepreload" href="/assets/components-Rk0n-9cK.js"/><link rel="modulepreload" href="/assets/root-BWvk5-gF.js"/><script>window.__remixContext = {"basename":"/","future":{"v3_fetcherPersist":false,"v3_relativeSplatPath":false,"v3_throwAbortReason":false,"v3_routeConfig":false,"v3_singleFetch":false,"v3_lazyRouteDiscovery":false,"unstable_optimizeDeps":false},"isSpaMode":true,"state":{"loaderData":{"root":null,"routes/_index":null},"actionData":null,"errors":null}};</script><script type="module" async="">import "/assets/manifest-d845808d.js";
2
+ <html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/assets/root-DxRwaWiE.css"/><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous"/><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&amp;display=swap"/></head><body><p>Loading...</p><link rel="modulepreload" href="/assets/manifest-89db7c30.js"/><link rel="modulepreload" href="/assets/entry.client-mvZjNKiz.js"/><link rel="modulepreload" href="/assets/index-DzNKzXrc.js"/><link rel="modulepreload" href="/assets/components-Rk0n-9cK.js"/><link rel="modulepreload" href="/assets/root-BWvk5-gF.js"/><script>window.__remixContext = {"basename":"/","future":{"v3_fetcherPersist":false,"v3_relativeSplatPath":false,"v3_throwAbortReason":false,"v3_routeConfig":false,"v3_singleFetch":false,"v3_lazyRouteDiscovery":false,"unstable_optimizeDeps":false},"isSpaMode":true,"state":{"loaderData":{"root":null,"routes/_index":null},"actionData":null,"errors":null}};</script><script type="module" async="">import "/assets/manifest-89db7c30.js";
3
3
  import * as route0 from "/assets/root-BWvk5-gF.js";
4
4
 
5
5
  window.__remixRouteModules = {"root":route0};
@@ -106,16 +106,22 @@ class TaskIdExtractor:
106
106
  Extract task ID using multiple strategies in order of preference.
107
107
  Returns (parent_task_id, sub_task_id) tuple.
108
108
  """
109
+ if not isinstance(message.payload, dict):
110
+ return None, None
111
+
109
112
  strategies = [
110
- self._extract_from_payload_metadata,
111
- self._extract_from_payload_params,
112
- self._extract_from_payload_result,
113
+ self._extract_from_subtask_delegation,
114
+ self._extract_from_toplevel_id,
115
+ self._extract_from_result_object,
113
116
  self._extract_from_topic,
114
117
  ]
115
118
 
116
119
  for strategy in strategies:
117
120
  try:
118
- task_id, sub_task_id = strategy(message)
121
+ if strategy.__name__ == "_extract_from_topic":
122
+ task_id, sub_task_id = strategy(message)
123
+ else:
124
+ task_id, sub_task_id = strategy(message.payload)
119
125
  if task_id:
120
126
  return task_id, sub_task_id
121
127
  except Exception as e:
@@ -124,67 +130,40 @@ class TaskIdExtractor:
124
130
 
125
131
  return None, None
126
132
 
127
- def _extract_from_payload_metadata(
128
- self, message: TaskMessage
133
+ def _extract_from_subtask_delegation(
134
+ self, payload: dict
129
135
  ) -> Tuple[Optional[str], Optional[str]]:
130
- """Strategy 1: Extract from payload metadata (parent-child relationship)."""
131
- payload = message.payload
132
-
133
- if not isinstance(payload, dict):
134
- return None, None
135
-
136
+ """Strategy 1: Check for sub-task delegation (agent-to-agent calls)."""
136
137
  params = payload.get("params", {})
137
- if not isinstance(params, dict):
138
- return None, None
139
-
140
- metadata = params.get("metadata", {})
141
- if not isinstance(metadata, dict):
142
- return None, None
143
-
144
- parent_task_id = metadata.get("parentTaskId")
145
- sub_task_id = params.get("id")
146
-
147
- if parent_task_id and sub_task_id:
148
- return parent_task_id, sub_task_id
149
-
138
+ if isinstance(params, dict):
139
+ message_param = params.get("message", {})
140
+ if isinstance(message_param, dict):
141
+ metadata = message_param.get("metadata", {})
142
+ if isinstance(metadata, dict):
143
+ parent_task_id = metadata.get("parentTaskId")
144
+ sub_task_id = payload.get("id")
145
+ if parent_task_id and sub_task_id:
146
+ return parent_task_id, sub_task_id
150
147
  return None, None
151
148
 
152
- def _extract_from_payload_params(
153
- self, message: TaskMessage
149
+ def _extract_from_toplevel_id(
150
+ self, payload: dict
154
151
  ) -> Tuple[Optional[str], Optional[str]]:
155
- """Strategy 2: Extract from payload params (direct task ID)."""
156
- payload = message.payload
157
-
158
- if not isinstance(payload, dict):
159
- return None, None
160
-
161
- params = payload.get("params", {})
162
- if not isinstance(params, dict):
163
- return None, None
164
-
165
- task_id = params.get("id")
166
- if task_id and isinstance(task_id, str) and task_id.startswith("task-"):
152
+ """Strategy 2: Get the primary task ID from the top-level 'id' field."""
153
+ task_id = payload.get("id")
154
+ if task_id and isinstance(task_id, str):
167
155
  return task_id, None
168
-
169
156
  return None, None
170
157
 
171
- def _extract_from_payload_result(
172
- self, message: TaskMessage
158
+ def _extract_from_result_object(
159
+ self, payload: dict
173
160
  ) -> Tuple[Optional[str], Optional[str]]:
174
- """Strategy 3: Extract from payload result."""
175
- payload = message.payload
176
-
177
- if not isinstance(payload, dict):
178
- return None, None
179
-
161
+ """Strategy 3: Fallback for status updates which also have taskId nested."""
180
162
  result = payload.get("result", {})
181
- if not isinstance(result, dict):
182
- return None, None
183
-
184
- task_id = result.get("id")
185
- if task_id and isinstance(task_id, str) and task_id.startswith("task-"):
186
- return task_id, None
187
-
163
+ if isinstance(result, dict):
164
+ task_id = result.get("taskId")
165
+ if task_id and isinstance(task_id, str):
166
+ return task_id, None
188
167
  return None, None
189
168
 
190
169
  def _extract_from_topic(
@@ -197,7 +176,7 @@ class TaskIdExtractor:
197
176
 
198
177
  # Extract the last part of the topic path
199
178
  task_id = topic.split("/")[-1]
200
- if task_id.startswith("task-"):
179
+ if task_id.startswith("gdk-task-"):
201
180
  return task_id, None
202
181
 
203
182
  return None, None
@@ -33,7 +33,7 @@ class EvaluationConfig:
33
33
  """Centralized configuration with validation and defaults."""
34
34
 
35
35
  # Constants
36
- DEFAULT_STARTUP_WAIT_TIME = 20
36
+ DEFAULT_STARTUP_WAIT_TIME = 60
37
37
  DEFAULT_TEST_TIMEOUT = 60
38
38
 
39
39
  def __init__(self, config_data: Dict[str, Any]):
@@ -108,13 +108,34 @@ class ProcessManager:
108
108
  command, stdout=sys.stdout, stderr=sys.stderr, cwd=project_root
109
109
  )
110
110
 
111
- print(
112
- f"Waiting for server to start... ({self.config.DEFAULT_STARTUP_WAIT_TIME} seconds)"
113
- )
114
- time.sleep(self.config.DEFAULT_STARTUP_WAIT_TIME)
111
+ print("Waiting for server to become healthy...")
112
+ self._wait_for_server_ready()
115
113
 
116
114
  return self.process, self.namespace
117
115
 
116
+ def _wait_for_server_ready(self):
117
+ """Poll the health endpoint until the server is ready."""
118
+ start_time = time.time()
119
+ health_url = f"{self.config.API_BASE_URL.replace('/api/v2', '')}/health"
120
+
121
+ while time.time() - start_time < self.config.DEFAULT_STARTUP_WAIT_TIME:
122
+ try:
123
+ response = requests.get(health_url)
124
+ if response.status_code == 200:
125
+ print("Server is healthy.")
126
+ time.sleep(1) # Wait an extra second as requested
127
+ return
128
+ except requests.ConnectionError:
129
+ # Server is not yet available, wait and retry
130
+ time.sleep(1)
131
+ except Exception as e:
132
+ print(f"An unexpected error occurred during health check: {e}")
133
+ time.sleep(1)
134
+
135
+ raise RuntimeError(
136
+ f"Server did not become healthy within {self.config.DEFAULT_STARTUP_WAIT_TIME} seconds."
137
+ )
138
+
118
139
  def stop_services(self, subscriber: Optional[Subscriber] = None):
119
140
  """Clean up running processes."""
120
141
  if subscriber:
@@ -120,9 +120,14 @@ class SubscriptionConfig:
120
120
  "/gateway/response/",
121
121
  ]
122
122
  )
123
+ blocked_topic_infixes: List[str] = field(
124
+ default_factory=lambda: [
125
+ "/discovery/"
126
+ ]
127
+ )
123
128
  message_timeout: int = 1000
124
129
  filter_non_final_status: bool = True
125
- remove_config_keys: bool = True
130
+ remove_config_keys: bool = False
126
131
 
127
132
  def __post_init__(self):
128
133
  """Validate subscription configuration."""
@@ -142,7 +147,10 @@ class SubscriptionConfig:
142
147
 
143
148
  def is_topic_allowed(self, topic: str) -> bool:
144
149
  """Check if a topic is allowed based on configured infixes."""
145
- return any(infix in topic for infix in self.allowed_topic_infixes)
150
+ # return any(infix in topic for infix in self.allowed_topic_infixes)
151
+ if any(infix in topic for infix in self.blocked_topic_infixes):
152
+ return False
153
+ return True
146
154
 
147
155
 
148
156
  @dataclass
@@ -300,20 +308,37 @@ class MessageProcessor:
300
308
  if not self.config.filter_non_final_status:
301
309
  return False
302
310
 
303
- if "/gateway/status/" not in topic:
304
- return False
305
-
306
311
  try:
307
- if isinstance(payload, dict):
308
- result = payload.get("result", {})
309
- if isinstance(result, dict):
310
- # Filter out non-final status messages
311
- return not result.get("final", True)
312
+ # Filter only for llm_invocation
313
+ if self._find_part_type(payload, "llm_invocation"):
314
+ return True
315
+
316
+ # Filter only for llm_response
317
+ if self._find_part_type(payload, "llm_response"):
318
+ return True
319
+
320
+ # Filter out agent progress update messages
321
+ if self._find_part_type(payload, "agent_progress_update"):
322
+ return True
312
323
  except Exception:
313
324
  pass
314
325
 
315
326
  return False
316
327
 
328
+ def _find_part_type(self, data: Any, type_to_find: str) -> bool:
329
+ """Recursively search for a part with a specific type."""
330
+ if isinstance(data, dict):
331
+ if data.get("type") == type_to_find:
332
+ return True
333
+ for key, value in data.items():
334
+ if self._find_part_type(value, type_to_find):
335
+ return True
336
+ elif isinstance(data, list):
337
+ for item in data:
338
+ if self._find_part_type(item, type_to_find):
339
+ return True
340
+ return False
341
+
317
342
  def _determine_message_type(self, topic: str) -> str:
318
343
  """Determine the type of message based on topic."""
319
344
  if "/agent/request/" in topic:
@@ -57,7 +57,7 @@ class RunSummary:
57
57
  query: str = ""
58
58
  target_agent: str = ""
59
59
  namespace: str = ""
60
- session_id: str = ""
60
+ context_id: str = ""
61
61
  final_status: str = ""
62
62
  final_message: str = ""
63
63
  time_metrics: TimeMetrics = field(default_factory=TimeMetrics)
@@ -74,7 +74,7 @@ class RunSummary:
74
74
  "query": self.query,
75
75
  "target_agent": self.target_agent,
76
76
  "namespace": self.namespace,
77
- "session_id": self.session_id,
77
+ "context_id": self.context_id,
78
78
  "final_status": self.final_status,
79
79
  "final_message": self.final_message,
80
80
  "start_time": self.time_metrics.start_time,
@@ -105,9 +105,6 @@ class RunSummary:
105
105
  "artifact_name": art.artifact_name,
106
106
  "directory": art.directory,
107
107
  "versions": art.versions,
108
- "created_by_tool": art.created_by_tool,
109
- "created_by_call_id": art.created_by_call_id,
110
- "creation_timestamp": art.creation_timestamp,
111
108
  }
112
109
  for art in self.output_artifacts
113
110
  ],
@@ -311,12 +308,13 @@ class MessageProcessor:
311
308
  return None, None
312
309
 
313
310
  @staticmethod
314
- def extract_session_id(first_message: Dict[str, Any]) -> Optional[str]:
315
- """Extract session ID from the first message."""
311
+ def extract_context_id(first_message: Dict[str, Any]) -> Optional[str]:
312
+ """Extract context ID from the first message."""
316
313
  try:
317
314
  payload = first_message.get("payload", {})
318
315
  params = payload.get("params", {})
319
- return params.get("sessionId")
316
+ message = params.get("message", {})
317
+ return message.get("contextId")
320
318
  except KeyError:
321
319
  return None
322
320
 
@@ -357,27 +355,22 @@ class MessageProcessor:
357
355
  result = payload.get("result", {})
358
356
  status = result.get("status", {})
359
357
  message_data = status.get("message", {})
360
- metadata = message_data.get("metadata", {})
361
- data = metadata.get("data", {})
362
- content = data.get("content", {})
363
- parts = content.get("parts", [])
358
+ parts = message_data.get("parts", [])
364
359
 
365
360
  for part in parts:
366
- function_call = part.get("function_call", {})
367
- if not function_call:
368
- continue
369
-
370
- call_id = function_call.get("id")
371
- if call_id and call_id not in processed_tool_calls:
372
- tool_call = ToolCall(
373
- call_id=call_id,
374
- agent=result.get("metadata", {}).get("agent_name", ""),
375
- tool_name=function_call.get("name", ""),
376
- arguments=function_call.get("args", {}),
377
- timestamp=status.get("timestamp", ""),
378
- )
379
- tool_calls.append(tool_call)
380
- processed_tool_calls.add(call_id)
361
+ data = part.get("data", {})
362
+ if data.get("type") == "tool_invocation_start":
363
+ call_id = data.get("function_call_id")
364
+ if call_id and call_id not in processed_tool_calls:
365
+ tool_call = ToolCall(
366
+ call_id=call_id,
367
+ agent=result.get("metadata", {}).get("agent_name", ""),
368
+ tool_name=data.get("tool_name", ""),
369
+ arguments=data.get("tool_args", {}),
370
+ timestamp=status.get("timestamp", ""),
371
+ )
372
+ tool_calls.append(tool_call)
373
+ processed_tool_calls.add(call_id)
381
374
 
382
375
  except (KeyError, IndexError):
383
376
  continue
@@ -392,11 +385,11 @@ class ArtifactService:
392
385
  self.base_path = base_path
393
386
  self.user_identity = user_identity
394
387
 
395
- def get_artifact_info(self, namespace: str, session_id: str) -> List[ArtifactInfo]:
388
+ def get_artifact_info(self, namespace: str, context_id: str) -> List[ArtifactInfo]:
396
389
  """Retrieve information about artifacts from the session directory."""
397
390
  artifact_info = []
398
391
  session_dir = os.path.join(
399
- self.base_path, namespace, self.user_identity, session_id
392
+ self.base_path, namespace, self.user_identity, context_id
400
393
  )
401
394
 
402
395
  if not os.path.isdir(session_dir):
@@ -652,9 +645,9 @@ class SummaryBuilder:
652
645
  "Could not find target agent and namespace in the first message."
653
646
  )
654
647
 
655
- session_id = self.message_processor.extract_session_id(first_message)
656
- if session_id:
657
- summary.session_id = session_id
648
+ context_id = self.message_processor.extract_context_id(first_message)
649
+ if context_id:
650
+ summary.context_id = context_id
658
651
 
659
652
  # Extract final status information
660
653
  final_status, final_message = self.message_processor.extract_final_status_info(
@@ -699,7 +692,7 @@ class SummaryBuilder:
699
692
 
700
693
  def _add_artifact_information(self, summary: RunSummary, test_case: Dict[str, Any]):
701
694
  """Add artifact information if configuration is available."""
702
- if not summary.namespace or not summary.session_id:
695
+ if not summary.namespace or not summary.context_id:
703
696
  return
704
697
 
705
698
  try:
@@ -710,7 +703,7 @@ class SummaryBuilder:
710
703
 
711
704
  # Get and categorize artifacts
712
705
  all_artifacts = self.artifact_service.get_artifact_info(
713
- summary.namespace, summary.session_id
706
+ summary.namespace, summary.context_id
714
707
  )
715
708
 
716
709
  input_artifacts, output_artifacts = (