holmesgpt 0.13.2__py3-none-any.whl → 0.18.4__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.
Files changed (188) hide show
  1. holmes/__init__.py +3 -5
  2. holmes/clients/robusta_client.py +20 -6
  3. holmes/common/env_vars.py +58 -3
  4. holmes/common/openshift.py +1 -1
  5. holmes/config.py +123 -148
  6. holmes/core/conversations.py +71 -15
  7. holmes/core/feedback.py +191 -0
  8. holmes/core/investigation.py +31 -39
  9. holmes/core/investigation_structured_output.py +3 -3
  10. holmes/core/issue.py +1 -1
  11. holmes/core/llm.py +508 -88
  12. holmes/core/models.py +108 -4
  13. holmes/core/openai_formatting.py +14 -1
  14. holmes/core/prompt.py +48 -3
  15. holmes/core/runbooks.py +1 -0
  16. holmes/core/safeguards.py +8 -6
  17. holmes/core/supabase_dal.py +295 -100
  18. holmes/core/tool_calling_llm.py +489 -428
  19. holmes/core/tools.py +325 -56
  20. holmes/core/tools_utils/token_counting.py +21 -0
  21. holmes/core/tools_utils/tool_context_window_limiter.py +40 -0
  22. holmes/core/tools_utils/tool_executor.py +0 -13
  23. holmes/core/tools_utils/toolset_utils.py +1 -0
  24. holmes/core/toolset_manager.py +191 -5
  25. holmes/core/tracing.py +19 -3
  26. holmes/core/transformers/__init__.py +23 -0
  27. holmes/core/transformers/base.py +63 -0
  28. holmes/core/transformers/llm_summarize.py +175 -0
  29. holmes/core/transformers/registry.py +123 -0
  30. holmes/core/transformers/transformer.py +32 -0
  31. holmes/core/truncation/compaction.py +94 -0
  32. holmes/core/truncation/dal_truncation_utils.py +23 -0
  33. holmes/core/truncation/input_context_window_limiter.py +219 -0
  34. holmes/interactive.py +228 -31
  35. holmes/main.py +23 -40
  36. holmes/plugins/interfaces.py +2 -1
  37. holmes/plugins/prompts/__init__.py +2 -1
  38. holmes/plugins/prompts/_fetch_logs.jinja2 +31 -6
  39. holmes/plugins/prompts/_general_instructions.jinja2 +1 -2
  40. holmes/plugins/prompts/_runbook_instructions.jinja2 +24 -12
  41. holmes/plugins/prompts/base_user_prompt.jinja2 +7 -0
  42. holmes/plugins/prompts/conversation_history_compaction.jinja2 +89 -0
  43. holmes/plugins/prompts/generic_ask.jinja2 +0 -4
  44. holmes/plugins/prompts/generic_ask_conversation.jinja2 +0 -1
  45. holmes/plugins/prompts/generic_ask_for_issue_conversation.jinja2 +0 -1
  46. holmes/plugins/prompts/generic_investigation.jinja2 +0 -1
  47. holmes/plugins/prompts/investigation_procedure.jinja2 +50 -1
  48. holmes/plugins/prompts/kubernetes_workload_ask.jinja2 +0 -1
  49. holmes/plugins/prompts/kubernetes_workload_chat.jinja2 +0 -1
  50. holmes/plugins/runbooks/__init__.py +145 -17
  51. holmes/plugins/runbooks/catalog.json +2 -0
  52. holmes/plugins/sources/github/__init__.py +4 -2
  53. holmes/plugins/sources/prometheus/models.py +1 -0
  54. holmes/plugins/toolsets/__init__.py +44 -27
  55. holmes/plugins/toolsets/aks-node-health.yaml +46 -0
  56. holmes/plugins/toolsets/aks.yaml +64 -0
  57. holmes/plugins/toolsets/atlas_mongodb/mongodb_atlas.py +38 -47
  58. holmes/plugins/toolsets/azure_sql/apis/alert_monitoring_api.py +3 -2
  59. holmes/plugins/toolsets/azure_sql/apis/azure_sql_api.py +2 -1
  60. holmes/plugins/toolsets/azure_sql/apis/connection_failure_api.py +3 -2
  61. holmes/plugins/toolsets/azure_sql/apis/connection_monitoring_api.py +3 -1
  62. holmes/plugins/toolsets/azure_sql/apis/storage_analysis_api.py +3 -1
  63. holmes/plugins/toolsets/azure_sql/azure_sql_toolset.py +12 -13
  64. holmes/plugins/toolsets/azure_sql/tools/analyze_connection_failures.py +15 -12
  65. holmes/plugins/toolsets/azure_sql/tools/analyze_database_connections.py +15 -12
  66. holmes/plugins/toolsets/azure_sql/tools/analyze_database_health_status.py +11 -11
  67. holmes/plugins/toolsets/azure_sql/tools/analyze_database_performance.py +11 -9
  68. holmes/plugins/toolsets/azure_sql/tools/analyze_database_storage.py +15 -12
  69. holmes/plugins/toolsets/azure_sql/tools/get_active_alerts.py +15 -15
  70. holmes/plugins/toolsets/azure_sql/tools/get_slow_queries.py +11 -8
  71. holmes/plugins/toolsets/azure_sql/tools/get_top_cpu_queries.py +11 -8
  72. holmes/plugins/toolsets/azure_sql/tools/get_top_data_io_queries.py +11 -8
  73. holmes/plugins/toolsets/azure_sql/tools/get_top_log_io_queries.py +11 -8
  74. holmes/plugins/toolsets/azure_sql/utils.py +0 -32
  75. holmes/plugins/toolsets/bash/argocd/__init__.py +3 -3
  76. holmes/plugins/toolsets/bash/aws/__init__.py +4 -4
  77. holmes/plugins/toolsets/bash/azure/__init__.py +4 -4
  78. holmes/plugins/toolsets/bash/bash_toolset.py +11 -15
  79. holmes/plugins/toolsets/bash/common/bash.py +23 -13
  80. holmes/plugins/toolsets/bash/common/bash_command.py +1 -1
  81. holmes/plugins/toolsets/bash/common/stringify.py +1 -1
  82. holmes/plugins/toolsets/bash/kubectl/__init__.py +2 -1
  83. holmes/plugins/toolsets/bash/kubectl/constants.py +0 -1
  84. holmes/plugins/toolsets/bash/kubectl/kubectl_get.py +3 -4
  85. holmes/plugins/toolsets/bash/parse_command.py +12 -13
  86. holmes/plugins/toolsets/cilium.yaml +284 -0
  87. holmes/plugins/toolsets/connectivity_check.py +124 -0
  88. holmes/plugins/toolsets/coralogix/api.py +132 -119
  89. holmes/plugins/toolsets/coralogix/coralogix.jinja2 +14 -0
  90. holmes/plugins/toolsets/coralogix/toolset_coralogix.py +219 -0
  91. holmes/plugins/toolsets/coralogix/utils.py +15 -79
  92. holmes/plugins/toolsets/datadog/datadog_api.py +525 -26
  93. holmes/plugins/toolsets/datadog/datadog_logs_instructions.jinja2 +55 -11
  94. holmes/plugins/toolsets/datadog/datadog_metrics_instructions.jinja2 +3 -3
  95. holmes/plugins/toolsets/datadog/datadog_models.py +59 -0
  96. holmes/plugins/toolsets/datadog/datadog_url_utils.py +213 -0
  97. holmes/plugins/toolsets/datadog/instructions_datadog_traces.jinja2 +165 -28
  98. holmes/plugins/toolsets/datadog/toolset_datadog_general.py +417 -241
  99. holmes/plugins/toolsets/datadog/toolset_datadog_logs.py +234 -214
  100. holmes/plugins/toolsets/datadog/toolset_datadog_metrics.py +167 -79
  101. holmes/plugins/toolsets/datadog/toolset_datadog_traces.py +374 -363
  102. holmes/plugins/toolsets/elasticsearch/__init__.py +6 -0
  103. holmes/plugins/toolsets/elasticsearch/elasticsearch.py +834 -0
  104. holmes/plugins/toolsets/elasticsearch/opensearch_ppl_query_docs.jinja2 +1616 -0
  105. holmes/plugins/toolsets/elasticsearch/opensearch_query_assist.py +78 -0
  106. holmes/plugins/toolsets/elasticsearch/opensearch_query_assist_instructions.jinja2 +223 -0
  107. holmes/plugins/toolsets/git.py +54 -50
  108. holmes/plugins/toolsets/grafana/base_grafana_toolset.py +16 -4
  109. holmes/plugins/toolsets/grafana/common.py +13 -29
  110. holmes/plugins/toolsets/grafana/grafana_tempo_api.py +455 -0
  111. holmes/plugins/toolsets/grafana/loki/instructions.jinja2 +25 -0
  112. holmes/plugins/toolsets/grafana/loki/toolset_grafana_loki.py +191 -0
  113. holmes/plugins/toolsets/grafana/loki_api.py +4 -0
  114. holmes/plugins/toolsets/grafana/toolset_grafana.py +293 -89
  115. holmes/plugins/toolsets/grafana/toolset_grafana_dashboard.jinja2 +49 -0
  116. holmes/plugins/toolsets/grafana/toolset_grafana_tempo.jinja2 +246 -11
  117. holmes/plugins/toolsets/grafana/toolset_grafana_tempo.py +820 -292
  118. holmes/plugins/toolsets/grafana/trace_parser.py +4 -3
  119. holmes/plugins/toolsets/internet/internet.py +15 -16
  120. holmes/plugins/toolsets/internet/notion.py +9 -11
  121. holmes/plugins/toolsets/investigator/core_investigation.py +44 -36
  122. holmes/plugins/toolsets/investigator/model.py +3 -1
  123. holmes/plugins/toolsets/json_filter_mixin.py +134 -0
  124. holmes/plugins/toolsets/kafka.py +36 -42
  125. holmes/plugins/toolsets/kubernetes.yaml +317 -113
  126. holmes/plugins/toolsets/kubernetes_logs.py +9 -9
  127. holmes/plugins/toolsets/kubernetes_logs.yaml +32 -0
  128. holmes/plugins/toolsets/logging_utils/logging_api.py +94 -8
  129. holmes/plugins/toolsets/mcp/toolset_mcp.py +218 -64
  130. holmes/plugins/toolsets/newrelic/new_relic_api.py +165 -0
  131. holmes/plugins/toolsets/newrelic/newrelic.jinja2 +65 -0
  132. holmes/plugins/toolsets/newrelic/newrelic.py +320 -0
  133. holmes/plugins/toolsets/openshift.yaml +283 -0
  134. holmes/plugins/toolsets/prometheus/prometheus.py +1202 -421
  135. holmes/plugins/toolsets/prometheus/prometheus_instructions.jinja2 +54 -5
  136. holmes/plugins/toolsets/prometheus/utils.py +28 -0
  137. holmes/plugins/toolsets/rabbitmq/api.py +23 -4
  138. holmes/plugins/toolsets/rabbitmq/toolset_rabbitmq.py +13 -14
  139. holmes/plugins/toolsets/robusta/robusta.py +239 -68
  140. holmes/plugins/toolsets/robusta/robusta_instructions.jinja2 +26 -9
  141. holmes/plugins/toolsets/runbook/runbook_fetcher.py +157 -27
  142. holmes/plugins/toolsets/service_discovery.py +1 -1
  143. holmes/plugins/toolsets/servicenow_tables/instructions.jinja2 +83 -0
  144. holmes/plugins/toolsets/servicenow_tables/servicenow_tables.py +426 -0
  145. holmes/plugins/toolsets/utils.py +88 -0
  146. holmes/utils/config_utils.py +91 -0
  147. holmes/utils/connection_utils.py +31 -0
  148. holmes/utils/console/result.py +10 -0
  149. holmes/utils/default_toolset_installation_guide.jinja2 +1 -22
  150. holmes/utils/env.py +7 -0
  151. holmes/utils/file_utils.py +2 -1
  152. holmes/utils/global_instructions.py +60 -11
  153. holmes/utils/holmes_status.py +6 -4
  154. holmes/utils/holmes_sync_toolsets.py +0 -2
  155. holmes/utils/krr_utils.py +188 -0
  156. holmes/utils/log.py +15 -0
  157. holmes/utils/markdown_utils.py +2 -3
  158. holmes/utils/memory_limit.py +58 -0
  159. holmes/utils/sentry_helper.py +64 -0
  160. holmes/utils/stream.py +69 -8
  161. holmes/utils/tags.py +4 -3
  162. holmes/version.py +37 -15
  163. holmesgpt-0.18.4.dist-info/LICENSE +178 -0
  164. {holmesgpt-0.13.2.dist-info → holmesgpt-0.18.4.dist-info}/METADATA +35 -31
  165. holmesgpt-0.18.4.dist-info/RECORD +258 -0
  166. holmes/core/performance_timing.py +0 -72
  167. holmes/plugins/toolsets/aws.yaml +0 -80
  168. holmes/plugins/toolsets/coralogix/toolset_coralogix_logs.py +0 -112
  169. holmes/plugins/toolsets/datadog/datadog_traces_formatter.py +0 -310
  170. holmes/plugins/toolsets/datadog/toolset_datadog_rds.py +0 -739
  171. holmes/plugins/toolsets/grafana/grafana_api.py +0 -42
  172. holmes/plugins/toolsets/grafana/tempo_api.py +0 -124
  173. holmes/plugins/toolsets/grafana/toolset_grafana_loki.py +0 -110
  174. holmes/plugins/toolsets/newrelic.py +0 -231
  175. holmes/plugins/toolsets/opensearch/opensearch.py +0 -257
  176. holmes/plugins/toolsets/opensearch/opensearch_logs.py +0 -161
  177. holmes/plugins/toolsets/opensearch/opensearch_traces.py +0 -218
  178. holmes/plugins/toolsets/opensearch/opensearch_traces_instructions.jinja2 +0 -12
  179. holmes/plugins/toolsets/opensearch/opensearch_utils.py +0 -166
  180. holmes/plugins/toolsets/servicenow/install.md +0 -37
  181. holmes/plugins/toolsets/servicenow/instructions.jinja2 +0 -3
  182. holmes/plugins/toolsets/servicenow/servicenow.py +0 -219
  183. holmes/utils/keygen_utils.py +0 -6
  184. holmesgpt-0.13.2.dist-info/LICENSE.txt +0 -21
  185. holmesgpt-0.13.2.dist-info/RECORD +0 -234
  186. /holmes/plugins/toolsets/{opensearch → newrelic}/__init__.py +0 -0
  187. {holmesgpt-0.13.2.dist-info → holmesgpt-0.18.4.dist-info}/WHEEL +0 -0
  188. {holmesgpt-0.13.2.dist-info → holmesgpt-0.18.4.dist-info}/entry_points.txt +0 -0
@@ -1,17 +1,22 @@
1
1
  import logging
2
- from typing import Any, Dict, Tuple
3
2
  from datetime import datetime, timezone
3
+ from typing import Any, Dict, Tuple
4
4
 
5
- from holmes.core.tools import StructuredToolResult, ToolParameter, ToolResultStatus
6
- from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
7
- BaseAzureSQLTool,
8
- BaseAzureSQLToolset,
9
- AzureSQLDatabaseConfig,
5
+ from holmes.core.tools import (
6
+ StructuredToolResult,
7
+ StructuredToolResultStatus,
8
+ ToolInvokeContext,
9
+ ToolParameter,
10
10
  )
11
+ from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
11
12
  from holmes.plugins.toolsets.azure_sql.apis.storage_analysis_api import (
12
13
  StorageAnalysisAPI,
13
14
  )
14
- from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
15
+ from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
16
+ AzureSQLDatabaseConfig,
17
+ BaseAzureSQLTool,
18
+ BaseAzureSQLToolset,
19
+ )
15
20
  from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
16
21
 
17
22
 
@@ -249,9 +254,7 @@ class AnalyzeDatabaseStorage(BaseAzureSQLTool):
249
254
 
250
255
  return "\n".join(report_sections)
251
256
 
252
- def _invoke(
253
- self, params: dict, user_approved: bool = False
254
- ) -> StructuredToolResult:
257
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
255
258
  try:
256
259
  hours_back = params.get("hours_back", 24)
257
260
  top_tables = params.get("top_tables", 20)
@@ -307,7 +310,7 @@ class AnalyzeDatabaseStorage(BaseAzureSQLTool):
307
310
  )
308
311
 
309
312
  return StructuredToolResult(
310
- status=ToolResultStatus.SUCCESS,
313
+ status=StructuredToolResultStatus.SUCCESS,
311
314
  data=report_text,
312
315
  params=params,
313
316
  )
@@ -315,7 +318,7 @@ class AnalyzeDatabaseStorage(BaseAzureSQLTool):
315
318
  error_msg = f"Failed to generate storage report: {str(e)}"
316
319
  logging.error(error_msg)
317
320
  return StructuredToolResult(
318
- status=ToolResultStatus.ERROR,
321
+ status=StructuredToolResultStatus.ERROR,
319
322
  error=error_msg,
320
323
  params=params,
321
324
  )
@@ -1,19 +1,21 @@
1
1
  import logging
2
- from typing import Dict
3
2
  from datetime import datetime, timezone
3
+ from typing import Dict, Tuple
4
4
 
5
- from holmes.core.tools import StructuredToolResult, ToolResultStatus
6
- from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
7
- BaseAzureSQLTool,
8
- BaseAzureSQLToolset,
9
- AzureSQLDatabaseConfig,
5
+ from holmes.core.tools import (
6
+ StructuredToolResult,
7
+ StructuredToolResultStatus,
8
+ ToolInvokeContext,
10
9
  )
11
- from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
12
10
  from holmes.plugins.toolsets.azure_sql.apis.alert_monitoring_api import (
13
11
  AlertMonitoringAPI,
14
12
  )
15
- from typing import Tuple
16
-
13
+ from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
14
+ from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
15
+ AzureSQLDatabaseConfig,
16
+ BaseAzureSQLTool,
17
+ BaseAzureSQLToolset,
18
+ )
17
19
  from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
18
20
 
19
21
 
@@ -147,9 +149,7 @@ class GetActiveAlerts(BaseAzureSQLTool):
147
149
 
148
150
  return "\n".join(report_sections)
149
151
 
150
- def _invoke(
151
- self, params: dict, user_approved: bool = False
152
- ) -> StructuredToolResult:
152
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
153
153
  try:
154
154
  db_config = self.toolset.database_config()
155
155
  api_client = self.toolset.api_client()
@@ -170,7 +170,7 @@ class GetActiveAlerts(BaseAzureSQLTool):
170
170
  # Check for errors
171
171
  if "error" in alerts_data:
172
172
  return StructuredToolResult(
173
- status=ToolResultStatus.ERROR,
173
+ status=StructuredToolResultStatus.ERROR,
174
174
  error=alerts_data["error"],
175
175
  params=params,
176
176
  )
@@ -179,7 +179,7 @@ class GetActiveAlerts(BaseAzureSQLTool):
179
179
  report_text = self._build_alerts_report(db_config, alerts_data, "active")
180
180
 
181
181
  return StructuredToolResult(
182
- status=ToolResultStatus.SUCCESS,
182
+ status=StructuredToolResultStatus.SUCCESS,
183
183
  data=report_text,
184
184
  params=params,
185
185
  )
@@ -187,7 +187,7 @@ class GetActiveAlerts(BaseAzureSQLTool):
187
187
  error_msg = f"Failed to retrieve active alerts: {str(e)}"
188
188
  logging.error(error_msg)
189
189
  return StructuredToolResult(
190
- status=ToolResultStatus.ERROR,
190
+ status=StructuredToolResultStatus.ERROR,
191
191
  error=error_msg,
192
192
  params=params,
193
193
  )
@@ -1,13 +1,18 @@
1
1
  import logging
2
2
  from typing import Dict, List, Tuple
3
3
 
4
- from holmes.core.tools import StructuredToolResult, ToolParameter, ToolResultStatus
4
+ from holmes.core.tools import (
5
+ StructuredToolResult,
6
+ StructuredToolResultStatus,
7
+ ToolInvokeContext,
8
+ ToolParameter,
9
+ )
10
+ from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
5
11
  from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
12
+ AzureSQLDatabaseConfig,
6
13
  BaseAzureSQLTool,
7
14
  BaseAzureSQLToolset,
8
- AzureSQLDatabaseConfig,
9
15
  )
10
- from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
11
16
  from holmes.plugins.toolsets.azure_sql.utils import format_timing
12
17
  from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
13
18
 
@@ -99,9 +104,7 @@ class GetSlowQueries(BaseAzureSQLTool):
99
104
 
100
105
  return "\n".join(report_sections)
101
106
 
102
- def _invoke(
103
- self, params: dict, user_approved: bool = False
104
- ) -> StructuredToolResult:
107
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
105
108
  try:
106
109
  top_count = params.get("top_count", 15)
107
110
  hours_back = params.get("hours_back", 2)
@@ -125,7 +128,7 @@ class GetSlowQueries(BaseAzureSQLTool):
125
128
  )
126
129
 
127
130
  return StructuredToolResult(
128
- status=ToolResultStatus.SUCCESS,
131
+ status=StructuredToolResultStatus.SUCCESS,
129
132
  data=report_text,
130
133
  params=params,
131
134
  )
@@ -133,7 +136,7 @@ class GetSlowQueries(BaseAzureSQLTool):
133
136
  error_msg = f"Failed to get slow queries: {str(e)}"
134
137
  logging.error(error_msg)
135
138
  return StructuredToolResult(
136
- status=ToolResultStatus.ERROR,
139
+ status=StructuredToolResultStatus.ERROR,
137
140
  error=error_msg,
138
141
  params=params,
139
142
  )
@@ -1,13 +1,18 @@
1
1
  import logging
2
2
  from typing import Dict, List, Tuple
3
3
 
4
- from holmes.core.tools import StructuredToolResult, ToolParameter, ToolResultStatus
4
+ from holmes.core.tools import (
5
+ StructuredToolResult,
6
+ StructuredToolResultStatus,
7
+ ToolInvokeContext,
8
+ ToolParameter,
9
+ )
10
+ from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
5
11
  from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
12
+ AzureSQLDatabaseConfig,
6
13
  BaseAzureSQLTool,
7
14
  BaseAzureSQLToolset,
8
- AzureSQLDatabaseConfig,
9
15
  )
10
- from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
11
16
  from holmes.plugins.toolsets.azure_sql.utils import format_timing
12
17
  from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
13
18
 
@@ -97,9 +102,7 @@ class GetTopCPUQueries(BaseAzureSQLTool):
97
102
 
98
103
  return "\n".join(report_sections)
99
104
 
100
- def _invoke(
101
- self, params: dict, user_approved: bool = False
102
- ) -> StructuredToolResult:
105
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
103
106
  try:
104
107
  top_count = params.get("top_count", 15)
105
108
  hours_back = params.get("hours_back", 2)
@@ -123,7 +126,7 @@ class GetTopCPUQueries(BaseAzureSQLTool):
123
126
  )
124
127
 
125
128
  return StructuredToolResult(
126
- status=ToolResultStatus.SUCCESS,
129
+ status=StructuredToolResultStatus.SUCCESS,
127
130
  data=report_text,
128
131
  params=params,
129
132
  )
@@ -131,7 +134,7 @@ class GetTopCPUQueries(BaseAzureSQLTool):
131
134
  error_msg = f"Failed to get top CPU queries: {str(e)}"
132
135
  logging.error(error_msg)
133
136
  return StructuredToolResult(
134
- status=ToolResultStatus.ERROR,
137
+ status=StructuredToolResultStatus.ERROR,
135
138
  error=error_msg,
136
139
  params=params,
137
140
  )
@@ -1,13 +1,18 @@
1
1
  import logging
2
2
  from typing import Dict, List, Tuple
3
3
 
4
- from holmes.core.tools import StructuredToolResult, ToolParameter, ToolResultStatus
4
+ from holmes.core.tools import (
5
+ StructuredToolResult,
6
+ StructuredToolResultStatus,
7
+ ToolInvokeContext,
8
+ ToolParameter,
9
+ )
10
+ from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
5
11
  from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
12
+ AzureSQLDatabaseConfig,
6
13
  BaseAzureSQLTool,
7
14
  BaseAzureSQLToolset,
8
- AzureSQLDatabaseConfig,
9
15
  )
10
- from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
11
16
  from holmes.plugins.toolsets.azure_sql.utils import format_timing
12
17
  from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
13
18
 
@@ -115,9 +120,7 @@ class GetTopDataIOQueries(BaseAzureSQLTool):
115
120
 
116
121
  return "\n".join(report_sections)
117
122
 
118
- def _invoke(
119
- self, params: dict, user_approved: bool = False
120
- ) -> StructuredToolResult:
123
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
121
124
  try:
122
125
  top_count = params.get("top_count", 15)
123
126
  hours_back = params.get("hours_back", 2)
@@ -141,7 +144,7 @@ class GetTopDataIOQueries(BaseAzureSQLTool):
141
144
  )
142
145
 
143
146
  return StructuredToolResult(
144
- status=ToolResultStatus.SUCCESS,
147
+ status=StructuredToolResultStatus.SUCCESS,
145
148
  data=report_text,
146
149
  params=params,
147
150
  )
@@ -149,7 +152,7 @@ class GetTopDataIOQueries(BaseAzureSQLTool):
149
152
  error_msg = f"Failed to get top data I/O queries: {str(e)}"
150
153
  logging.error(error_msg)
151
154
  return StructuredToolResult(
152
- status=ToolResultStatus.ERROR,
155
+ status=StructuredToolResultStatus.ERROR,
153
156
  error=error_msg,
154
157
  params=params,
155
158
  )
@@ -1,13 +1,18 @@
1
1
  import logging
2
2
  from typing import Dict, List, Tuple
3
3
 
4
- from holmes.core.tools import StructuredToolResult, ToolParameter, ToolResultStatus
4
+ from holmes.core.tools import (
5
+ StructuredToolResult,
6
+ StructuredToolResultStatus,
7
+ ToolInvokeContext,
8
+ ToolParameter,
9
+ )
10
+ from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
5
11
  from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
12
+ AzureSQLDatabaseConfig,
6
13
  BaseAzureSQLTool,
7
14
  BaseAzureSQLToolset,
8
- AzureSQLDatabaseConfig,
9
15
  )
10
- from holmes.plugins.toolsets.azure_sql.apis.azure_sql_api import AzureSQLAPIClient
11
16
  from holmes.plugins.toolsets.azure_sql.utils import format_timing
12
17
  from holmes.plugins.toolsets.utils import toolset_name_for_one_liner
13
18
 
@@ -107,9 +112,7 @@ class GetTopLogIOQueries(BaseAzureSQLTool):
107
112
 
108
113
  return "\n".join(report_sections)
109
114
 
110
- def _invoke(
111
- self, params: dict, user_approved: bool = False
112
- ) -> StructuredToolResult:
115
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
113
116
  try:
114
117
  top_count = params.get("top_count", 15)
115
118
  hours_back = params.get("hours_back", 2)
@@ -133,7 +136,7 @@ class GetTopLogIOQueries(BaseAzureSQLTool):
133
136
  )
134
137
 
135
138
  return StructuredToolResult(
136
- status=ToolResultStatus.SUCCESS,
139
+ status=StructuredToolResultStatus.SUCCESS,
137
140
  data=report_text,
138
141
  params=params,
139
142
  )
@@ -141,7 +144,7 @@ class GetTopLogIOQueries(BaseAzureSQLTool):
141
144
  error_msg = f"Failed to get top log I/O queries: {str(e)}"
142
145
  logging.error(error_msg)
143
146
  return StructuredToolResult(
144
- status=ToolResultStatus.ERROR,
147
+ status=StructuredToolResultStatus.ERROR,
145
148
  error=error_msg,
146
149
  params=params,
147
150
  )
@@ -20,38 +20,6 @@ def format_timing(microseconds: float) -> str:
20
20
  return f"{microseconds:.0f} μs"
21
21
 
22
22
 
23
- def format_size_bytes(bytes_value: float) -> str:
24
- """Format byte values with appropriate units.
25
-
26
- Args:
27
- bytes_value: Size value in bytes
28
-
29
- Returns:
30
- Formatted string with appropriate units (GB, MB, KB, or B)
31
- """
32
- if bytes_value >= 1_073_741_824: # >= 1 GB
33
- return f"{bytes_value / 1_073_741_824:.2f} GB"
34
- elif bytes_value >= 1_048_576: # >= 1 MB
35
- return f"{bytes_value / 1_048_576:.2f} MB"
36
- elif bytes_value >= 1_024: # >= 1 KB
37
- return f"{bytes_value / 1_024:.2f} KB"
38
- else: # < 1 KB
39
- return f"{bytes_value:.0f} B"
40
-
41
-
42
- def format_percentage(value: float, decimal_places: int = 2) -> str:
43
- """Format percentage values.
44
-
45
- Args:
46
- value: Percentage value (0-100)
47
- decimal_places: Number of decimal places to show
48
-
49
- Returns:
50
- Formatted percentage string
51
- """
52
- return f"{value:.{decimal_places}f}%"
53
-
54
-
55
23
  def safe_divide(numerator: float, denominator: float, default: float = 0.0) -> float:
56
24
  """Safely divide two numbers, handling division by zero.
57
25
 
@@ -1,13 +1,13 @@
1
1
  import argparse
2
2
  from typing import Any, Optional
3
3
 
4
- from holmes.plugins.toolsets.bash.common.bash_command import BashCommand
5
- from holmes.plugins.toolsets.bash.common.config import BashExecutorConfig
6
- from holmes.plugins.toolsets.bash.common.stringify import escape_shell_args
7
4
  from holmes.plugins.toolsets.bash.argocd.constants import (
8
5
  ALLOWED_ARGOCD_COMMANDS,
9
6
  DENIED_ARGOCD_COMMANDS,
10
7
  )
8
+ from holmes.plugins.toolsets.bash.common.bash_command import BashCommand
9
+ from holmes.plugins.toolsets.bash.common.config import BashExecutorConfig
10
+ from holmes.plugins.toolsets.bash.common.stringify import escape_shell_args
11
11
  from holmes.plugins.toolsets.bash.common.validators import (
12
12
  validate_command_and_operations,
13
13
  )
@@ -1,16 +1,16 @@
1
1
  import argparse
2
2
  from typing import Any, Optional
3
3
 
4
+ from holmes.plugins.toolsets.bash.aws.constants import (
5
+ ALLOWED_AWS_COMMANDS,
6
+ DENIED_AWS_COMMANDS,
7
+ )
4
8
  from holmes.plugins.toolsets.bash.common.bash_command import BashCommand
5
9
  from holmes.plugins.toolsets.bash.common.config import BashExecutorConfig
6
10
  from holmes.plugins.toolsets.bash.common.stringify import escape_shell_args
7
11
  from holmes.plugins.toolsets.bash.common.validators import (
8
12
  validate_command_and_operations,
9
13
  )
10
- from holmes.plugins.toolsets.bash.aws.constants import (
11
- ALLOWED_AWS_COMMANDS,
12
- DENIED_AWS_COMMANDS,
13
- )
14
14
 
15
15
 
16
16
  class AWSCommand(BashCommand):
@@ -1,16 +1,16 @@
1
1
  import argparse
2
2
  from typing import Any, Optional
3
3
 
4
+ from holmes.plugins.toolsets.bash.azure.constants import (
5
+ ALLOWED_AZURE_COMMANDS,
6
+ DENIED_AZURE_COMMANDS,
7
+ )
4
8
  from holmes.plugins.toolsets.bash.common.bash_command import BashCommand
5
9
  from holmes.plugins.toolsets.bash.common.config import BashExecutorConfig
6
10
  from holmes.plugins.toolsets.bash.common.stringify import escape_shell_args
7
11
  from holmes.plugins.toolsets.bash.common.validators import (
8
12
  validate_command_and_operations,
9
13
  )
10
- from holmes.plugins.toolsets.bash.azure.constants import (
11
- ALLOWED_AZURE_COMMANDS,
12
- DENIED_AZURE_COMMANDS,
13
- )
14
14
 
15
15
 
16
16
  class AzureCommand(BashCommand):
@@ -4,20 +4,20 @@ import os
4
4
  import random
5
5
  import re
6
6
  import string
7
- from typing import Dict, Any, Optional
7
+ from typing import Any, Dict, Optional
8
8
 
9
9
  import sentry_sdk
10
10
 
11
-
12
11
  from holmes.common.env_vars import (
13
12
  BASH_TOOL_UNSAFE_ALLOW_ALL,
14
13
  )
15
14
  from holmes.core.tools import (
16
15
  CallablePrerequisite,
17
16
  StructuredToolResult,
17
+ StructuredToolResultStatus,
18
18
  Tool,
19
+ ToolInvokeContext,
19
20
  ToolParameter,
20
- ToolResultStatus,
21
21
  Toolset,
22
22
  ToolsetTag,
23
23
  )
@@ -82,9 +82,7 @@ class KubectlRunImageCommand(BaseBashTool):
82
82
  command_str = get_param_or_raise(params, "command")
83
83
  return f"kubectl run {pod_name} --image={image} --namespace={namespace} --rm --attach --restart=Never -i -- {command_str}"
84
84
 
85
- def _invoke(
86
- self, params: dict, user_approved: bool = False
87
- ) -> StructuredToolResult:
85
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
88
86
  timeout = params.get("timeout", 60)
89
87
 
90
88
  image = get_param_or_raise(params, "image")
@@ -94,7 +92,7 @@ class KubectlRunImageCommand(BaseBashTool):
94
92
 
95
93
  if namespace and not re.match(SAFE_NAMESPACE_PATTERN, namespace):
96
94
  return StructuredToolResult(
97
- status=ToolResultStatus.ERROR,
95
+ status=StructuredToolResultStatus.ERROR,
98
96
  error=f"Error: The namespace is invalid. Valid namespaces must match the following regexp: {SAFE_NAMESPACE_PATTERN}",
99
97
  params=params,
100
98
  )
@@ -118,7 +116,7 @@ class KubectlRunImageCommand(BaseBashTool):
118
116
  }
119
117
  )
120
118
  return StructuredToolResult(
121
- status=ToolResultStatus.ERROR,
119
+ status=StructuredToolResultStatus.ERROR,
122
120
  error=str(e),
123
121
  params=params,
124
122
  )
@@ -164,22 +162,20 @@ class RunBashCommand(BaseBashTool):
164
162
  toolset=toolset,
165
163
  )
166
164
 
167
- def _invoke(
168
- self, params: dict, user_approved: bool = False
169
- ) -> StructuredToolResult:
165
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
170
166
  command_str = params.get("command")
171
167
  timeout = params.get("timeout", 60)
172
168
 
173
169
  if not command_str:
174
170
  return StructuredToolResult(
175
- status=ToolResultStatus.ERROR,
171
+ status=StructuredToolResultStatus.ERROR,
176
172
  error="The 'command' parameter is required and was not provided.",
177
173
  params=params,
178
174
  )
179
175
 
180
176
  if not isinstance(command_str, str):
181
177
  return StructuredToolResult(
182
- status=ToolResultStatus.ERROR,
178
+ status=StructuredToolResultStatus.ERROR,
183
179
  error=f"The 'command' parameter must be a string, got {type(command_str).__name__}.",
184
180
  params=params,
185
181
  )
@@ -187,7 +183,7 @@ class RunBashCommand(BaseBashTool):
187
183
  command_to_execute = command_str
188
184
 
189
185
  # Only run the safety check if user has NOT approved the command
190
- if not user_approved:
186
+ if not context.user_approved:
191
187
  try:
192
188
  command_to_execute = make_command_safe(command_str, self.toolset.config)
193
189
 
@@ -202,7 +198,7 @@ class RunBashCommand(BaseBashTool):
202
198
  logging.info(f"Refusing LLM tool call {command_str}")
203
199
 
204
200
  return StructuredToolResult(
205
- status=ToolResultStatus.APPROVAL_REQUIRED,
201
+ status=StructuredToolResultStatus.APPROVAL_REQUIRED,
206
202
  error=f"Refusing to execute bash command. {str(e)}",
207
203
  params=params,
208
204
  invocation=command_str,
@@ -1,11 +1,14 @@
1
1
  import subprocess
2
- from holmes.core.tools import StructuredToolResult, ToolResultStatus
2
+
3
+ from holmes.core.tools import StructuredToolResult, StructuredToolResultStatus
4
+ from holmes.utils.memory_limit import check_oom_and_append_hint, get_ulimit_prefix
3
5
 
4
6
 
5
7
  def execute_bash_command(cmd: str, timeout: int, params: dict) -> StructuredToolResult:
6
8
  try:
9
+ protected_cmd = get_ulimit_prefix() + cmd
7
10
  process = subprocess.run(
8
- cmd,
11
+ protected_cmd,
9
12
  shell=True,
10
13
  executable="/bin/bash",
11
14
  stdout=subprocess.PIPE,
@@ -16,16 +19,23 @@ def execute_bash_command(cmd: str, timeout: int, params: dict) -> StructuredTool
16
19
  )
17
20
 
18
21
  stdout = process.stdout.strip() if process.stdout else ""
19
- result_data = f"{cmd}\n" f"{stdout}"
22
+ stdout = check_oom_and_append_hint(stdout, process.returncode)
23
+ result_data = f"{cmd}\n{stdout}"
20
24
 
21
- status = ToolResultStatus.ERROR
22
- if process.returncode == 0 and stdout:
23
- status = ToolResultStatus.SUCCESS
24
- elif not stdout:
25
- status = ToolResultStatus.NO_DATA
25
+ if process.returncode == 0:
26
+ status = (
27
+ StructuredToolResultStatus.SUCCESS
28
+ if stdout
29
+ else StructuredToolResultStatus.NO_DATA
30
+ )
31
+ error = None
32
+ else:
33
+ status = StructuredToolResultStatus.ERROR
34
+ error = f'Error: Command "{cmd}" returned non-zero exit status {process.returncode}'
26
35
 
27
36
  return StructuredToolResult(
28
37
  status=status,
38
+ error=error,
29
39
  data=result_data,
30
40
  params=params,
31
41
  invocation=cmd,
@@ -33,20 +43,20 @@ def execute_bash_command(cmd: str, timeout: int, params: dict) -> StructuredTool
33
43
  )
34
44
  except subprocess.TimeoutExpired:
35
45
  return StructuredToolResult(
36
- status=ToolResultStatus.ERROR,
46
+ status=StructuredToolResultStatus.ERROR,
37
47
  error=f"Error: Command '{cmd}' timed out after {timeout} seconds.",
38
48
  params=params,
39
49
  )
40
50
  except FileNotFoundError:
41
- # This might occur if /bin/bash is not found, or if shell=False and command is not found
51
+ # This might occur if /bin/bash is not found, or command is not found
42
52
  return StructuredToolResult(
43
- status=ToolResultStatus.ERROR,
44
- error="Error: Bash executable or command not found. Ensure bash is installed and the command is valid.",
53
+ status=StructuredToolResultStatus.ERROR,
54
+ error="Error: Bash executable or command not found.",
45
55
  params=params,
46
56
  )
47
57
  except Exception as e:
48
58
  return StructuredToolResult(
49
- status=ToolResultStatus.ERROR,
59
+ status=StructuredToolResultStatus.ERROR,
50
60
  error=f"Error executing command '{cmd}': {str(e)}",
51
61
  params=params,
52
62
  )
@@ -1,5 +1,5 @@
1
- from abc import ABC, abstractmethod
2
1
  import argparse
2
+ from abc import ABC, abstractmethod
3
3
  from typing import Any, Optional
4
4
 
5
5
  from holmes.plugins.toolsets.bash.common.config import BashExecutorConfig
@@ -1,5 +1,5 @@
1
- import shlex
2
1
  import re
2
+ import shlex
3
3
 
4
4
  SAFE_SHELL_CHARS = frozenset(".-_=/,:")
5
5
 
@@ -1,4 +1,5 @@
1
1
  from typing import Any, Optional
2
+
2
3
  from holmes.plugins.toolsets.bash.common.bash_command import BashCommand
3
4
  from holmes.plugins.toolsets.bash.common.config import BashExecutorConfig
4
5
  from holmes.plugins.toolsets.bash.kubectl.constants import (
@@ -9,9 +10,9 @@ from holmes.plugins.toolsets.bash.kubectl.constants import (
9
10
  )
10
11
  from holmes.plugins.toolsets.bash.kubectl.kubectl_describe import KubectlDescribeCommand
11
12
  from holmes.plugins.toolsets.bash.kubectl.kubectl_events import KubectlEventsCommand
13
+ from holmes.plugins.toolsets.bash.kubectl.kubectl_get import KubectlGetCommand
12
14
  from holmes.plugins.toolsets.bash.kubectl.kubectl_logs import KubectlLogsCommand
13
15
  from holmes.plugins.toolsets.bash.kubectl.kubectl_top import KubectlTopCommand
14
- from holmes.plugins.toolsets.bash.kubectl.kubectl_get import KubectlGetCommand
15
16
 
16
17
 
17
18
  class KubectlCommand(BashCommand):
@@ -1,6 +1,5 @@
1
1
  import re
2
2
 
3
-
4
3
  SAFE_NAME_PATTERN = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9\-_.]*$")
5
4
  SAFE_NAMESPACE_PATTERN = re.compile(r"^[a-z0-9][a-z0-9\-]*$")
6
5
  SAFE_SELECTOR_PATTERN = re.compile(r"^[a-zA-Z0-9\-_.=,!()]+$")
@@ -1,6 +1,8 @@
1
+ import argparse
1
2
  from typing import Any, Optional
2
3
 
3
- import argparse
4
+ from holmes.plugins.toolsets.bash.common.bash_command import BashCommand
5
+ from holmes.plugins.toolsets.bash.common.config import BashExecutorConfig
4
6
  from holmes.plugins.toolsets.bash.common.stringify import escape_shell_args
5
7
  from holmes.plugins.toolsets.bash.common.validators import (
6
8
  whitelist_validator,
@@ -9,9 +11,6 @@ from holmes.plugins.toolsets.bash.kubectl.constants import (
9
11
  VALID_RESOURCE_TYPES,
10
12
  )
11
13
 
12
- from holmes.plugins.toolsets.bash.common.bash_command import BashCommand
13
- from holmes.plugins.toolsets.bash.common.config import BashExecutorConfig
14
-
15
14
 
16
15
  class KubectlGetCommand(BashCommand):
17
16
  def __init__(self):