holmesgpt 0.13.2__py3-none-any.whl → 0.16.2a0__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 (134) hide show
  1. holmes/__init__.py +1 -1
  2. holmes/clients/robusta_client.py +17 -4
  3. holmes/common/env_vars.py +40 -1
  4. holmes/config.py +114 -144
  5. holmes/core/conversations.py +53 -14
  6. holmes/core/feedback.py +191 -0
  7. holmes/core/investigation.py +18 -22
  8. holmes/core/llm.py +489 -88
  9. holmes/core/models.py +103 -1
  10. holmes/core/openai_formatting.py +13 -0
  11. holmes/core/prompt.py +1 -1
  12. holmes/core/safeguards.py +4 -4
  13. holmes/core/supabase_dal.py +293 -100
  14. holmes/core/tool_calling_llm.py +423 -323
  15. holmes/core/tools.py +311 -33
  16. holmes/core/tools_utils/token_counting.py +14 -0
  17. holmes/core/tools_utils/tool_context_window_limiter.py +57 -0
  18. holmes/core/tools_utils/tool_executor.py +13 -8
  19. holmes/core/toolset_manager.py +155 -4
  20. holmes/core/tracing.py +6 -1
  21. holmes/core/transformers/__init__.py +23 -0
  22. holmes/core/transformers/base.py +62 -0
  23. holmes/core/transformers/llm_summarize.py +174 -0
  24. holmes/core/transformers/registry.py +122 -0
  25. holmes/core/transformers/transformer.py +31 -0
  26. holmes/core/truncation/compaction.py +59 -0
  27. holmes/core/truncation/dal_truncation_utils.py +23 -0
  28. holmes/core/truncation/input_context_window_limiter.py +218 -0
  29. holmes/interactive.py +177 -24
  30. holmes/main.py +7 -4
  31. holmes/plugins/prompts/_fetch_logs.jinja2 +26 -1
  32. holmes/plugins/prompts/_general_instructions.jinja2 +1 -2
  33. holmes/plugins/prompts/_runbook_instructions.jinja2 +23 -12
  34. holmes/plugins/prompts/conversation_history_compaction.jinja2 +88 -0
  35. holmes/plugins/prompts/generic_ask.jinja2 +2 -4
  36. holmes/plugins/prompts/generic_ask_conversation.jinja2 +2 -1
  37. holmes/plugins/prompts/generic_ask_for_issue_conversation.jinja2 +2 -1
  38. holmes/plugins/prompts/generic_investigation.jinja2 +2 -1
  39. holmes/plugins/prompts/investigation_procedure.jinja2 +48 -0
  40. holmes/plugins/prompts/kubernetes_workload_ask.jinja2 +2 -1
  41. holmes/plugins/prompts/kubernetes_workload_chat.jinja2 +2 -1
  42. holmes/plugins/runbooks/__init__.py +117 -18
  43. holmes/plugins/runbooks/catalog.json +2 -0
  44. holmes/plugins/toolsets/__init__.py +21 -8
  45. holmes/plugins/toolsets/aks-node-health.yaml +46 -0
  46. holmes/plugins/toolsets/aks.yaml +64 -0
  47. holmes/plugins/toolsets/atlas_mongodb/mongodb_atlas.py +26 -36
  48. holmes/plugins/toolsets/azure_sql/azure_sql_toolset.py +0 -1
  49. holmes/plugins/toolsets/azure_sql/tools/analyze_connection_failures.py +10 -7
  50. holmes/plugins/toolsets/azure_sql/tools/analyze_database_connections.py +9 -6
  51. holmes/plugins/toolsets/azure_sql/tools/analyze_database_health_status.py +8 -6
  52. holmes/plugins/toolsets/azure_sql/tools/analyze_database_performance.py +8 -6
  53. holmes/plugins/toolsets/azure_sql/tools/analyze_database_storage.py +9 -6
  54. holmes/plugins/toolsets/azure_sql/tools/get_active_alerts.py +9 -7
  55. holmes/plugins/toolsets/azure_sql/tools/get_slow_queries.py +9 -6
  56. holmes/plugins/toolsets/azure_sql/tools/get_top_cpu_queries.py +9 -6
  57. holmes/plugins/toolsets/azure_sql/tools/get_top_data_io_queries.py +9 -6
  58. holmes/plugins/toolsets/azure_sql/tools/get_top_log_io_queries.py +9 -6
  59. holmes/plugins/toolsets/bash/bash_toolset.py +10 -13
  60. holmes/plugins/toolsets/bash/common/bash.py +7 -7
  61. holmes/plugins/toolsets/cilium.yaml +284 -0
  62. holmes/plugins/toolsets/coralogix/toolset_coralogix_logs.py +5 -3
  63. holmes/plugins/toolsets/datadog/datadog_api.py +490 -24
  64. holmes/plugins/toolsets/datadog/datadog_logs_instructions.jinja2 +21 -10
  65. holmes/plugins/toolsets/datadog/toolset_datadog_general.py +349 -216
  66. holmes/plugins/toolsets/datadog/toolset_datadog_logs.py +190 -19
  67. holmes/plugins/toolsets/datadog/toolset_datadog_metrics.py +101 -44
  68. holmes/plugins/toolsets/datadog/toolset_datadog_rds.py +13 -16
  69. holmes/plugins/toolsets/datadog/toolset_datadog_traces.py +25 -31
  70. holmes/plugins/toolsets/git.py +51 -46
  71. holmes/plugins/toolsets/grafana/common.py +15 -3
  72. holmes/plugins/toolsets/grafana/grafana_api.py +46 -24
  73. holmes/plugins/toolsets/grafana/grafana_tempo_api.py +454 -0
  74. holmes/plugins/toolsets/grafana/loki/instructions.jinja2 +9 -0
  75. holmes/plugins/toolsets/grafana/loki/toolset_grafana_loki.py +117 -0
  76. holmes/plugins/toolsets/grafana/toolset_grafana.py +211 -91
  77. holmes/plugins/toolsets/grafana/toolset_grafana_dashboard.jinja2 +27 -0
  78. holmes/plugins/toolsets/grafana/toolset_grafana_tempo.jinja2 +246 -11
  79. holmes/plugins/toolsets/grafana/toolset_grafana_tempo.py +653 -293
  80. holmes/plugins/toolsets/grafana/trace_parser.py +1 -1
  81. holmes/plugins/toolsets/internet/internet.py +6 -7
  82. holmes/plugins/toolsets/internet/notion.py +5 -6
  83. holmes/plugins/toolsets/investigator/core_investigation.py +42 -34
  84. holmes/plugins/toolsets/kafka.py +25 -36
  85. holmes/plugins/toolsets/kubernetes.yaml +58 -84
  86. holmes/plugins/toolsets/kubernetes_logs.py +6 -6
  87. holmes/plugins/toolsets/kubernetes_logs.yaml +32 -0
  88. holmes/plugins/toolsets/logging_utils/logging_api.py +80 -4
  89. holmes/plugins/toolsets/mcp/toolset_mcp.py +181 -55
  90. holmes/plugins/toolsets/newrelic/__init__.py +0 -0
  91. holmes/plugins/toolsets/newrelic/new_relic_api.py +125 -0
  92. holmes/plugins/toolsets/newrelic/newrelic.jinja2 +41 -0
  93. holmes/plugins/toolsets/newrelic/newrelic.py +163 -0
  94. holmes/plugins/toolsets/opensearch/opensearch.py +10 -17
  95. holmes/plugins/toolsets/opensearch/opensearch_logs.py +7 -7
  96. holmes/plugins/toolsets/opensearch/opensearch_ppl_query_docs.jinja2 +1616 -0
  97. holmes/plugins/toolsets/opensearch/opensearch_query_assist.py +78 -0
  98. holmes/plugins/toolsets/opensearch/opensearch_query_assist_instructions.jinja2 +223 -0
  99. holmes/plugins/toolsets/opensearch/opensearch_traces.py +13 -16
  100. holmes/plugins/toolsets/openshift.yaml +283 -0
  101. holmes/plugins/toolsets/prometheus/prometheus.py +915 -390
  102. holmes/plugins/toolsets/prometheus/prometheus_instructions.jinja2 +43 -2
  103. holmes/plugins/toolsets/prometheus/utils.py +28 -0
  104. holmes/plugins/toolsets/rabbitmq/toolset_rabbitmq.py +9 -10
  105. holmes/plugins/toolsets/robusta/robusta.py +236 -65
  106. holmes/plugins/toolsets/robusta/robusta_instructions.jinja2 +26 -9
  107. holmes/plugins/toolsets/runbook/runbook_fetcher.py +137 -26
  108. holmes/plugins/toolsets/service_discovery.py +1 -1
  109. holmes/plugins/toolsets/servicenow_tables/instructions.jinja2 +83 -0
  110. holmes/plugins/toolsets/servicenow_tables/servicenow_tables.py +426 -0
  111. holmes/plugins/toolsets/utils.py +88 -0
  112. holmes/utils/config_utils.py +91 -0
  113. holmes/utils/default_toolset_installation_guide.jinja2 +1 -22
  114. holmes/utils/env.py +7 -0
  115. holmes/utils/global_instructions.py +75 -10
  116. holmes/utils/holmes_status.py +2 -1
  117. holmes/utils/holmes_sync_toolsets.py +0 -2
  118. holmes/utils/krr_utils.py +188 -0
  119. holmes/utils/sentry_helper.py +41 -0
  120. holmes/utils/stream.py +61 -7
  121. holmes/version.py +34 -14
  122. holmesgpt-0.16.2a0.dist-info/LICENSE +178 -0
  123. {holmesgpt-0.13.2.dist-info → holmesgpt-0.16.2a0.dist-info}/METADATA +29 -27
  124. {holmesgpt-0.13.2.dist-info → holmesgpt-0.16.2a0.dist-info}/RECORD +126 -102
  125. holmes/core/performance_timing.py +0 -72
  126. holmes/plugins/toolsets/grafana/tempo_api.py +0 -124
  127. holmes/plugins/toolsets/grafana/toolset_grafana_loki.py +0 -110
  128. holmes/plugins/toolsets/newrelic.py +0 -231
  129. holmes/plugins/toolsets/servicenow/install.md +0 -37
  130. holmes/plugins/toolsets/servicenow/instructions.jinja2 +0 -3
  131. holmes/plugins/toolsets/servicenow/servicenow.py +0 -219
  132. holmesgpt-0.13.2.dist-info/LICENSE.txt +0 -21
  133. {holmesgpt-0.13.2.dist-info → holmesgpt-0.16.2a0.dist-info}/WHEEL +0 -0
  134. {holmesgpt-0.13.2.dist-info → holmesgpt-0.16.2a0.dist-info}/entry_points.txt +0 -0
@@ -7,7 +7,10 @@ import yaml # type: ignore
7
7
  from pydantic import ValidationError
8
8
 
9
9
  import holmes.utils.env as env_utils
10
- from holmes.common.env_vars import USE_LEGACY_KUBERNETES_LOGS
10
+ from holmes.common.env_vars import (
11
+ USE_LEGACY_KUBERNETES_LOGS,
12
+ DISABLE_PROMETHEUS_TOOLSET,
13
+ )
11
14
  from holmes.core.supabase_dal import SupabaseDal
12
15
  from holmes.core.tools import Toolset, ToolsetType, ToolsetYamlFromConfig, YAMLToolset
13
16
  from holmes.plugins.toolsets.atlas_mongodb.mongodb_atlas import MongoDBAtlasToolset
@@ -31,22 +34,26 @@ from holmes.plugins.toolsets.datadog.toolset_datadog_general import (
31
34
  )
32
35
  from holmes.plugins.toolsets.git import GitToolset
33
36
  from holmes.plugins.toolsets.grafana.toolset_grafana import GrafanaToolset
34
- from holmes.plugins.toolsets.grafana.toolset_grafana_loki import GrafanaLokiToolset
37
+ from holmes.plugins.toolsets.grafana.loki.toolset_grafana_loki import GrafanaLokiToolset
35
38
  from holmes.plugins.toolsets.grafana.toolset_grafana_tempo import GrafanaTempoToolset
36
39
  from holmes.plugins.toolsets.internet.internet import InternetToolset
37
40
  from holmes.plugins.toolsets.internet.notion import NotionToolset
38
41
  from holmes.plugins.toolsets.kafka import KafkaToolset
39
42
  from holmes.plugins.toolsets.kubernetes_logs import KubernetesLogsToolset
40
43
  from holmes.plugins.toolsets.mcp.toolset_mcp import RemoteMCPToolset
41
- from holmes.plugins.toolsets.newrelic import NewRelicToolset
44
+ from holmes.plugins.toolsets.newrelic.newrelic import NewRelicToolset
42
45
  from holmes.plugins.toolsets.opensearch.opensearch import OpenSearchToolset
43
46
  from holmes.plugins.toolsets.opensearch.opensearch_logs import OpenSearchLogsToolset
47
+ from holmes.plugins.toolsets.opensearch.opensearch_query_assist import (
48
+ OpenSearchQueryAssistToolset,
49
+ )
44
50
  from holmes.plugins.toolsets.opensearch.opensearch_traces import OpenSearchTracesToolset
45
- from holmes.plugins.toolsets.prometheus.prometheus import PrometheusToolset
46
51
  from holmes.plugins.toolsets.rabbitmq.toolset_rabbitmq import RabbitMQToolset
47
52
  from holmes.plugins.toolsets.robusta.robusta import RobustaToolset
48
53
  from holmes.plugins.toolsets.runbook.runbook_fetcher import RunbookToolset
49
- from holmes.plugins.toolsets.servicenow.servicenow import ServiceNowToolset
54
+ from holmes.plugins.toolsets.servicenow_tables.servicenow_tables import (
55
+ ServiceNowTablesToolset,
56
+ )
50
57
  from holmes.plugins.toolsets.investigator.core_investigation import (
51
58
  CoreInvestigationToolset,
52
59
  )
@@ -89,18 +96,24 @@ def load_python_toolsets(dal: Optional[SupabaseDal]) -> List[Toolset]:
89
96
  DatadogMetricsToolset(),
90
97
  DatadogTracesToolset(),
91
98
  DatadogRDSToolset(),
92
- PrometheusToolset(),
93
99
  OpenSearchLogsToolset(),
94
100
  OpenSearchTracesToolset(),
101
+ OpenSearchQueryAssistToolset(),
95
102
  CoralogixLogsToolset(),
96
103
  RabbitMQToolset(),
97
104
  GitToolset(),
98
105
  BashExecutorToolset(),
99
106
  MongoDBAtlasToolset(),
100
- RunbookToolset(),
107
+ RunbookToolset(dal=dal),
101
108
  AzureSQLToolset(),
102
- ServiceNowToolset(),
109
+ ServiceNowTablesToolset(),
103
110
  ]
111
+
112
+ if not DISABLE_PROMETHEUS_TOOLSET:
113
+ from holmes.plugins.toolsets.prometheus.prometheus import PrometheusToolset
114
+
115
+ toolsets.append(PrometheusToolset())
116
+
104
117
  if not USE_LEGACY_KUBERNETES_LOGS:
105
118
  toolsets.append(KubernetesLogsToolset())
106
119
 
@@ -7,17 +7,49 @@ toolsets:
7
7
  - command: "az account show"
8
8
  - command: "az aks --help"
9
9
  - command: "kubectl version --client"
10
+
11
+ # Note: Tools in this toolset use transformers with llm_summarize
12
+ # to automatically summarize large outputs from Azure CLI and kubectl commands
13
+ # when a fast model is configured, focusing on health issues and troubleshooting.
10
14
  tools:
11
15
  - name: "check_node_status"
12
16
  description: "Checks the status of all nodes in the AKS cluster."
13
17
  user_description: "get the status of all nodes in the AKS cluster"
14
18
  command: |
15
19
  kubectl get nodes
20
+ transformers:
21
+ - name: llm_summarize
22
+ config:
23
+ input_threshold: 800
24
+ prompt: |
25
+ Summarize this node status output focusing on:
26
+ - Any nodes that are NotReady or in error states
27
+ - Node health patterns and issues requiring attention
28
+ - Group healthy nodes together with aggregate counts
29
+ - Highlight nodes with concerning conditions or ages
30
+ - When possible, mention exact node names for follow-up investigation
31
+ - Be concise: aim for ≤ 50% of the original length; avoid repeating defaults/healthy/unchanged details
32
+ - Prefer aggregates and counts; list only outliers and actionable items
33
+ - Keep grep-friendly: include exact field names/values that matter
16
34
  - name: "describe_node"
17
35
  description: "Describes a specific node in the AKS cluster to inspect its conditions."
18
36
  user_description: "describe node {{ NODE_NAME }} in the AKS cluster"
19
37
  command: |
20
38
  kubectl describe node {{ NODE_NAME }}
39
+ transformers:
40
+ - name: llm_summarize
41
+ config:
42
+ input_threshold: 1200
43
+ prompt: |
44
+ Summarize this node description focusing on:
45
+ - Node conditions and health status (Ready, MemoryPressure, DiskPressure, etc.)
46
+ - Resource capacity vs allocatable vs current usage
47
+ - Any taints, labels, or annotations indicating issues
48
+ - Recent events that show problems or state changes
49
+ - System information relevant to troubleshooting
50
+ - When possible, highlight specific condition reasons for investigation
51
+ - Strive for ≤ 50% of the original size; keep results compact and grep-friendly (one line per aggregate)
52
+ - Prioritize aggregates and actionable outliers over comprehensive details
21
53
  - name: "get_node_events"
22
54
  description: "Fetches recent events for a specific node to surface warnings and errors."
23
55
  user_description: "get events for node {{ NODE_NAME }}"
@@ -33,6 +65,20 @@ toolsets:
33
65
  user_description: "review Azure Activity Log for resource group {{ RESOURCE_GROUP_NAME }}"
34
66
  command: |
35
67
  az monitor activity-log list --resource-group {{ RESOURCE_GROUP_NAME }}
68
+ transformers:
69
+ - name: llm_summarize
70
+ config:
71
+ input_threshold: 1500
72
+ prompt: |
73
+ Summarize this Azure Activity Log focusing on:
74
+ - Recent administrative actions or configuration changes
75
+ - Any failed operations or errors that could impact node health
76
+ - Resource scaling, updates, or maintenance activities
77
+ - Network security group, load balancer, or VM-related changes
78
+ - Group similar activities and highlight time patterns
79
+ - When possible, mention specific operation names and correlation IDs
80
+ - Be concise and avoid expansion: target ≤ 50% of input size; prefer counts + outliers over full listings
81
+ - Include grep-ready keys/values; avoid repeating entire objects or unchanged defaults
36
82
  - name: "check_top_resource_consuming_pods"
37
83
  description: "Checks for the top resource-consuming pods on a specific node."
38
84
  user_description: "get the top resource-consuming pods on node {{ NODE_NAME }}"
@@ -7,6 +7,10 @@ toolsets:
7
7
  - command: "az account show"
8
8
  - command: "az aks --help"
9
9
  - command: "kubectl version --client"
10
+
11
+ # Note: Tools in this toolset use transformers with llm_summarize
12
+ # to automatically summarize large JSON outputs from Azure CLI commands
13
+ # when a fast model is configured, focusing on key configuration and status information.
10
14
  tools:
11
15
  - name: "cloud_provider"
12
16
  description: "Fetches the cloud provider of the kubernetes cluster, determined by the providerID of the nodes"
@@ -18,16 +22,61 @@ toolsets:
18
22
  user_description: "get AKS cluster {{ CLUSTER_NAME }} under resource group {{ RESOURCE_GROUP_NAME }} in subscription {{ SUBSCRIPTION_ID }}"
19
23
  command: |
20
24
  az aks show --resource-group {{ RESOURCE_GROUP_NAME }} --name {{ CLUSTER_NAME }} --subscription {{ SUBSCRIPTION_ID }}
25
+ transformers:
26
+ - name: llm_summarize
27
+ config:
28
+ input_threshold: 1500
29
+ prompt: |
30
+ Summarize this AKS cluster configuration focusing on:
31
+ - Cluster status, health state, and version information
32
+ - Node pool configuration and scaling settings
33
+ - Network configuration (subnet, load balancer, network policy)
34
+ - Add-ons and features enabled (monitoring, auto-scaling, etc.)
35
+ - Security settings (RBAC, managed identity, private cluster)
36
+ - Any warnings or deprecated configurations
37
+ - When possible, highlight settings that might impact performance or security
38
+ - Be concise: aim for ≤ 50% of the original length; avoid repeating defaults/healthy/unchanged details
39
+ - Prefer aggregates and counts; list only outliers and actionable items
40
+ - Keep grep-friendly: include exact field names/values that matter
21
41
  - name: "aks_list_clusters_by_rg"
22
42
  description: "Lists all AKS clusters under a specific resource group. Only run this tool when you need to get all clusters in a resource group, rather than a specific one."
23
43
  user_description: "list AKS clusters in resource group {{ RESOURCE_GROUP_NAME }} under subscription {{ SUBSCRIPTION_ID }}"
24
44
  command: |
25
45
  az aks list --resource-group {{ RESOURCE_GROUP_NAME }} --subscription {{ SUBSCRIPTION_ID }}
46
+ transformers:
47
+ - name: llm_summarize
48
+ config:
49
+ input_threshold: 1000
50
+ prompt: |
51
+ Summarize this AKS clusters list focusing on:
52
+ - Cluster names, locations, and current status
53
+ - Kubernetes versions and any version skew issues
54
+ - Node pool counts and VM SKUs
55
+ - Key configuration differences between clusters
56
+ - Any clusters in error or unusual states
57
+ - When possible, group clusters by similar configurations
58
+ - Be concise and avoid expansion: target ≤ 50% of input size; prefer counts + outliers over full listings
59
+ - Include grep-ready keys/values; avoid repeating entire objects or unchanged defaults
26
60
  - name: "aks_list_node_pools"
27
61
  description: "Lists node pools in an AKS cluster"
28
62
  user_description: "list node pools for AKS cluster {{ CLUSTER_NAME }} under resource group {{ RESOURCE_GROUP_NAME }}"
29
63
  command: |
30
64
  az aks nodepool list --resource-group {{ RESOURCE_GROUP_NAME }} --cluster-name {{ CLUSTER_NAME }} --subscription {{ SUBSCRIPTION_ID }}
65
+ transformers:
66
+ - name: llm_summarize
67
+ config:
68
+ input_threshold: 1200
69
+ prompt: |
70
+ Summarize this AKS node pools list focusing on:
71
+ - Node pool names, VM sizes, and current node counts
72
+ - Scaling configuration (min/max nodes, auto-scaling enabled)
73
+ - Node pool status and provisioning state
74
+ - OS types, Kubernetes versions, and any upgrade patterns
75
+ - Taints, labels, and specialized configurations
76
+ - Any node pools in error states or with scaling issues
77
+ - When possible, identify resource allocation patterns
78
+ - Strive for ≤ 50% of the original size; keep results compact and grep-friendly (one line per aggregate)
79
+ - Prioritize aggregates and actionable outliers over comprehensive details
31
80
  - name: "aks_show_node_pool"
32
81
  description: "Shows details of a specific node pool in an AKS cluster"
33
82
  user_description: "get node pool {{ NODE_POOL_NAME }} in AKS cluster {{ CLUSTER_NAME }} under resource group {{ RESOURCE_GROUP_NAME }}"
@@ -84,3 +133,18 @@ toolsets:
84
133
  user_description: "list NSG rules for NSG {{ NSG_NAME }} in resource group {{ RESOURCE_GROUP_NAME }} under subscription {{ SUBSCRIPTION_ID }}"
85
134
  command: |
86
135
  az network nsg rule list --resource-group {{ RESOURCE_GROUP_NAME }} --nsg-name {{ NSG_NAME }} --subscription {{ SUBSCRIPTION_ID }} --include-default -o table
136
+ transformers:
137
+ - name: llm_summarize
138
+ config:
139
+ input_threshold: 1000
140
+ prompt: |
141
+ Summarize these NSG rules focusing on:
142
+ - Allow vs deny rules and their priority order
143
+ - Inbound vs outbound traffic rules
144
+ - Port ranges and protocols affected
145
+ - Source and destination configurations
146
+ - Any overly permissive or potentially insecure rules
147
+ - Default rules vs custom rules
148
+ - When possible, highlight rules that might impact AKS connectivity
149
+ - Be concise: aim for ≤ 50% of the original text; prioritize aggregates and actionable outliers
150
+ - Include grep-ready keys/values; avoid repeating entire rules or unchanged defaults
@@ -4,13 +4,14 @@ from typing import Any, Dict, Tuple, List
4
4
  from holmes.core.tools import (
5
5
  CallablePrerequisite,
6
6
  Tool,
7
+ ToolInvokeContext,
7
8
  ToolParameter,
8
9
  Toolset,
9
10
  ToolsetTag,
10
11
  )
11
12
 
12
13
  from pydantic import BaseModel, PrivateAttr
13
- from holmes.core.tools import StructuredToolResult, ToolResultStatus
14
+ from holmes.core.tools import StructuredToolResult, StructuredToolResultStatus
14
15
  from requests.auth import HTTPDigestAuth # type: ignore
15
16
  import gzip
16
17
  import io
@@ -41,7 +42,6 @@ class MongoDBAtlasToolset(Toolset):
41
42
  def __init__(self):
42
43
  super().__init__(
43
44
  prerequisites=[CallablePrerequisite(callable=self.prerequisites_callable)],
44
- experimental=True,
45
45
  tools=[
46
46
  ReturnProjectAlerts(toolset=self),
47
47
  ReturnProjectProcesses(toolset=self),
@@ -66,8 +66,8 @@ class MongoDBAtlasToolset(Toolset):
66
66
  {"Accept": "application/vnd.atlas.2025-03-12+json"}
67
67
  )
68
68
  self._session.auth = HTTPDigestAuth(
69
- self.config.get("public_key"),
70
- self.config.get("private_key"),
69
+ self.config.get("public_key"), # type: ignore
70
+ self.config.get("private_key"), # type: ignore
71
71
  )
72
72
  return True, ""
73
73
  except Exception:
@@ -90,15 +90,15 @@ class MongoDBAtlasBaseTool(Tool):
90
90
  if response.ok:
91
91
  res = response.json()
92
92
  return StructuredToolResult(
93
- status=ToolResultStatus.SUCCESS
93
+ status=StructuredToolResultStatus.SUCCESS
94
94
  if res.get(field, [])
95
- else ToolResultStatus.NO_DATA,
95
+ else StructuredToolResultStatus.NO_DATA,
96
96
  data=res,
97
97
  params=params,
98
98
  )
99
99
  else:
100
100
  return StructuredToolResult(
101
- status=ToolResultStatus.ERROR,
101
+ status=StructuredToolResultStatus.ERROR,
102
102
  error=f"Failed {self.name}.\n{response.text}",
103
103
  return_code=response.status_code,
104
104
  params=params,
@@ -118,9 +118,7 @@ class ReturnProjectAlerts(MongoDBAtlasBaseTool):
118
118
  project_id = self.toolset.config.get("project_id", "")
119
119
  return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Project Alerts ({project_id})"
120
120
 
121
- def _invoke(
122
- self, params: dict, user_approved: bool = False
123
- ) -> StructuredToolResult:
121
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
124
122
  try:
125
123
  url = "https://cloud.mongodb.com/api/atlas/v2/groups/{project_id}/alerts".format(
126
124
  project_id=self.toolset.config.get("project_id")
@@ -130,7 +128,7 @@ class ReturnProjectAlerts(MongoDBAtlasBaseTool):
130
128
  except Exception as e:
131
129
  logging.exception(self.get_parameterized_one_liner(params))
132
130
  return StructuredToolResult(
133
- status=ToolResultStatus.ERROR,
131
+ status=StructuredToolResultStatus.ERROR,
134
132
  data=f"Exception {self.name}: {str(e)}",
135
133
  params=params,
136
134
  )
@@ -145,9 +143,7 @@ class ReturnProjectProcesses(MongoDBAtlasBaseTool):
145
143
  project_id = self.toolset.config.get("project_id", "")
146
144
  return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Project Processes ({project_id})"
147
145
 
148
- def _invoke(
149
- self, params: dict, user_approved: bool = False
150
- ) -> StructuredToolResult:
146
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
151
147
  try:
152
148
  url = "https://cloud.mongodb.com/api/atlas/v2/groups/{project_id}/processes".format(
153
149
  project_id=self.toolset.config.get("project_id")
@@ -157,7 +153,7 @@ class ReturnProjectProcesses(MongoDBAtlasBaseTool):
157
153
  except Exception as e:
158
154
  logging.exception(self.get_parameterized_one_liner(params))
159
155
  return StructuredToolResult(
160
- status=ToolResultStatus.ERROR,
156
+ status=StructuredToolResultStatus.ERROR,
161
157
  error=f"Exception {self.name}: {str(e)}",
162
158
  params=params,
163
159
  )
@@ -180,9 +176,7 @@ class ReturnProjectSlowQueries(MongoDBAtlasBaseTool):
180
176
  process_id = params.get("process_id", "")
181
177
  return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Slow Queries ({process_id})"
182
178
 
183
- def _invoke(
184
- self, params: dict, user_approved: bool = False
185
- ) -> StructuredToolResult:
179
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
186
180
  try:
187
181
  url = self.url.format(
188
182
  project_id=self.toolset.config.get("project_id"),
@@ -193,7 +187,7 @@ class ReturnProjectSlowQueries(MongoDBAtlasBaseTool):
193
187
  except Exception as e:
194
188
  logging.exception(self.get_parameterized_one_liner(params))
195
189
  return StructuredToolResult(
196
- status=ToolResultStatus.ERROR,
190
+ status=StructuredToolResultStatus.ERROR,
197
191
  error=f"Exception {self.name}: {str(e)}",
198
192
  params=params,
199
193
  )
@@ -209,9 +203,7 @@ class ReturnEventsFromProject(MongoDBAtlasBaseTool):
209
203
  project_id = self.toolset.config.get("project_id", "")
210
204
  return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Project Events ({project_id})"
211
205
 
212
- def _invoke(
213
- self, params: dict, user_approved: bool = False
214
- ) -> StructuredToolResult:
206
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
215
207
  params.update({"itemsPerPage": 500})
216
208
  try:
217
209
  now_utc = datetime.now(timezone.utc)
@@ -230,14 +222,14 @@ class ReturnEventsFromProject(MongoDBAtlasBaseTool):
230
222
  )
231
223
  data = f"last 4 hours eventTypeName and # of occurrences list: {events_counter} \n to get more information about a given eventTypeName call atlas_return_events_type_from_project"
232
224
  status = (
233
- ToolResultStatus.SUCCESS
225
+ StructuredToolResultStatus.SUCCESS
234
226
  if events_counter
235
- else ToolResultStatus.NO_DATA
227
+ else StructuredToolResultStatus.NO_DATA
236
228
  )
237
229
  return StructuredToolResult(status=status, data=data, params=params)
238
230
  else:
239
231
  return StructuredToolResult(
240
- status=ToolResultStatus.ERROR,
232
+ status=StructuredToolResultStatus.ERROR,
241
233
  error=f"Failed {self.name}. \n{response.text}",
242
234
  return_code=response.status_code,
243
235
  params=params,
@@ -245,7 +237,7 @@ class ReturnEventsFromProject(MongoDBAtlasBaseTool):
245
237
  except Exception as e:
246
238
  logging.exception(self.get_parameterized_one_liner(params))
247
239
  return StructuredToolResult(
248
- status=ToolResultStatus.ERROR,
240
+ status=StructuredToolResultStatus.ERROR,
249
241
  error=f"Exception {self.name}: {str(e)}",
250
242
  params=params,
251
243
  )
@@ -268,9 +260,7 @@ class ReturnLogsForProcessInProject(MongoDBAtlasBaseTool):
268
260
  hostname = params.get("hostName", "")
269
261
  return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Host Logs ({hostname})"
270
262
 
271
- def _invoke(
272
- self, params: dict, user_approved: bool = False
273
- ) -> StructuredToolResult:
263
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
274
264
  one_hour_ago = datetime.now(timezone.utc) - timedelta(hours=1)
275
265
  try:
276
266
  url = self.url.format(
@@ -287,11 +277,13 @@ class ReturnLogsForProcessInProject(MongoDBAtlasBaseTool):
287
277
  with gzip.GzipFile(fileobj=io.BytesIO(response.content)) as gz:
288
278
  text_data = gz.read().decode("utf-8")
289
279
  return StructuredToolResult(
290
- status=ToolResultStatus.SUCCESS, data=text_data, params=params
280
+ status=StructuredToolResultStatus.SUCCESS,
281
+ data=text_data,
282
+ params=params,
291
283
  )
292
284
  else:
293
285
  return StructuredToolResult(
294
- status=ToolResultStatus.ERROR,
286
+ status=StructuredToolResultStatus.ERROR,
295
287
  error=f"Failed {self.name}. \n{response.text}",
296
288
  return_code=response.status_code,
297
289
  params=params,
@@ -299,7 +291,7 @@ class ReturnLogsForProcessInProject(MongoDBAtlasBaseTool):
299
291
  except Exception as e:
300
292
  logging.exception(self.get_parameterized_one_liner(params))
301
293
  return StructuredToolResult(
302
- status=ToolResultStatus.ERROR,
294
+ status=StructuredToolResultStatus.ERROR,
303
295
  error=f"Exception {self.name}: {str(e)}",
304
296
  params=params,
305
297
  )
@@ -322,9 +314,7 @@ class ReturnEventTypeFromProject(MongoDBAtlasBaseTool):
322
314
  event_type = params.get("eventType", "")
323
315
  return f"{toolset_name_for_one_liner(self.toolset.name)}: Get Event Details ({event_type})"
324
316
 
325
- def _invoke(
326
- self, params: dict, user_approved: bool = False
327
- ) -> StructuredToolResult:
317
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
328
318
  try:
329
319
  url = self.url.format(projectId=self.toolset.config.get("project_id"))
330
320
 
@@ -340,7 +330,7 @@ class ReturnEventTypeFromProject(MongoDBAtlasBaseTool):
340
330
  except Exception as e:
341
331
  logging.exception(self.get_parameterized_one_liner(params))
342
332
  return StructuredToolResult(
343
- status=ToolResultStatus.ERROR,
333
+ status=StructuredToolResultStatus.ERROR,
344
334
  error=f"Exception {self.name}: {str(e)}",
345
335
  params=params,
346
336
  )
@@ -60,7 +60,6 @@ class AzureSQLToolset(BaseAzureSQLToolset):
60
60
  docs_url="https://kagi.com/proxy/png-clipart-microsoft-sql-server-microsoft-azure-sql-database-microsoft-text-logo-thumbnail.png?c=4Sg1bvcUGOrhnDzXgoBBa0G0j27ykgskX4a8cLrZp_quzqlpVGVG02OqQtezTxy7lB6ydmTKgbVAn_F7BxofxK6LKKUZSpjJ1huIAsXPVaXyakO4sWXFiX0Wz_8WjkA0AIlO_oFfW31AKaj5RcvGcr3siy0n5kW-GcqdpeBWsmm_huxUT6RycULFCDFBwuUzHvVl5TW3cYqlMxT8ecPZfg%3D%3D",
61
61
  icon_url="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Azure_SQL_Database_logo.svg/1200px-Azure_SQL_Database_logo.svg.png",
62
62
  tags=[ToolsetTag.CORE],
63
- experimental=True,
64
63
  tools=[
65
64
  AnalyzeDatabaseHealthStatus(self),
66
65
  AnalyzeDatabasePerformance(self),
@@ -2,7 +2,12 @@ import logging
2
2
  from typing import Dict, Tuple
3
3
  from datetime import datetime, timezone
4
4
 
5
- from holmes.core.tools import StructuredToolResult, ToolParameter, ToolResultStatus
5
+ from holmes.core.tools import (
6
+ StructuredToolResult,
7
+ ToolInvokeContext,
8
+ ToolParameter,
9
+ StructuredToolResultStatus,
10
+ )
6
11
  from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
7
12
  BaseAzureSQLTool,
8
13
  BaseAzureSQLToolset,
@@ -213,9 +218,7 @@ class AnalyzeConnectionFailures(BaseAzureSQLTool):
213
218
 
214
219
  return "\n".join(report_sections)
215
220
 
216
- def _invoke(
217
- self, params: dict, user_approved: bool = False
218
- ) -> StructuredToolResult:
221
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
219
222
  try:
220
223
  # Get configuration
221
224
  db_config = self.toolset.database_config()
@@ -242,7 +245,7 @@ class AnalyzeConnectionFailures(BaseAzureSQLTool):
242
245
  # Check for errors
243
246
  if "error" in analysis_data:
244
247
  return StructuredToolResult(
245
- status=ToolResultStatus.ERROR,
248
+ status=StructuredToolResultStatus.ERROR,
246
249
  error=analysis_data["error"],
247
250
  params=params,
248
251
  )
@@ -253,7 +256,7 @@ class AnalyzeConnectionFailures(BaseAzureSQLTool):
253
256
  )
254
257
 
255
258
  return StructuredToolResult(
256
- status=ToolResultStatus.SUCCESS,
259
+ status=StructuredToolResultStatus.SUCCESS,
257
260
  data=report_text,
258
261
  params=params,
259
262
  )
@@ -263,7 +266,7 @@ class AnalyzeConnectionFailures(BaseAzureSQLTool):
263
266
  f"Error in analyze_connection_failures: {str(e)}", exc_info=True
264
267
  )
265
268
  return StructuredToolResult(
266
- status=ToolResultStatus.ERROR,
269
+ status=StructuredToolResultStatus.ERROR,
267
270
  error=f"Failed to analyze connection failures: {str(e)}",
268
271
  params=params,
269
272
  )
@@ -2,7 +2,12 @@ import logging
2
2
  from typing import Any, Dict, Tuple
3
3
  from datetime import datetime, timezone
4
4
 
5
- from holmes.core.tools import StructuredToolResult, ToolParameter, ToolResultStatus
5
+ from holmes.core.tools import (
6
+ StructuredToolResult,
7
+ ToolInvokeContext,
8
+ ToolParameter,
9
+ StructuredToolResultStatus,
10
+ )
6
11
  from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
7
12
  BaseAzureSQLTool,
8
13
  BaseAzureSQLToolset,
@@ -151,9 +156,7 @@ class AnalyzeDatabaseConnections(BaseAzureSQLTool):
151
156
 
152
157
  return "\n".join(report_sections)
153
158
 
154
- def _invoke(
155
- self, params: dict, user_approved: bool = False
156
- ) -> StructuredToolResult:
159
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
157
160
  try:
158
161
  hours_back = params.get("hours_back", 2)
159
162
 
@@ -200,7 +203,7 @@ class AnalyzeDatabaseConnections(BaseAzureSQLTool):
200
203
  )
201
204
 
202
205
  return StructuredToolResult(
203
- status=ToolResultStatus.SUCCESS,
206
+ status=StructuredToolResultStatus.SUCCESS,
204
207
  data=report_text,
205
208
  params=params,
206
209
  )
@@ -208,7 +211,7 @@ class AnalyzeDatabaseConnections(BaseAzureSQLTool):
208
211
  error_msg = f"Failed to generate connection report: {str(e)}"
209
212
  logging.error(error_msg)
210
213
  return StructuredToolResult(
211
- status=ToolResultStatus.ERROR,
214
+ status=StructuredToolResultStatus.ERROR,
212
215
  error=error_msg,
213
216
  params=params,
214
217
  )
@@ -2,7 +2,11 @@ import logging
2
2
  from typing import Dict
3
3
  from datetime import datetime, timezone
4
4
 
5
- from holmes.core.tools import StructuredToolResult, ToolResultStatus
5
+ from holmes.core.tools import (
6
+ StructuredToolResult,
7
+ StructuredToolResultStatus,
8
+ ToolInvokeContext,
9
+ )
6
10
  from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
7
11
  BaseAzureSQLTool,
8
12
  BaseAzureSQLToolset,
@@ -131,9 +135,7 @@ class AnalyzeDatabaseHealthStatus(BaseAzureSQLTool):
131
135
 
132
136
  return "\n".join(report_sections)
133
137
 
134
- def _invoke(
135
- self, params: dict, user_approved: bool = False
136
- ) -> StructuredToolResult:
138
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
137
139
  try:
138
140
  db_config = self.toolset.database_config()
139
141
  client = self.toolset.api_client()
@@ -145,7 +147,7 @@ class AnalyzeDatabaseHealthStatus(BaseAzureSQLTool):
145
147
  report_text = self._build_health_report(health_data, db_config)
146
148
 
147
149
  return StructuredToolResult(
148
- status=ToolResultStatus.SUCCESS,
150
+ status=StructuredToolResultStatus.SUCCESS,
149
151
  data=report_text,
150
152
  params=params,
151
153
  )
@@ -153,7 +155,7 @@ class AnalyzeDatabaseHealthStatus(BaseAzureSQLTool):
153
155
  error_msg = f"Failed to generate health report: {str(e)}"
154
156
  logging.error(error_msg)
155
157
  return StructuredToolResult(
156
- status=ToolResultStatus.ERROR,
158
+ status=StructuredToolResultStatus.ERROR,
157
159
  error=error_msg,
158
160
  params=params,
159
161
  )
@@ -2,7 +2,11 @@ import logging
2
2
  from typing import Any, Dict, List, Tuple, cast
3
3
  from datetime import datetime, timezone
4
4
 
5
- from holmes.core.tools import StructuredToolResult, ToolResultStatus
5
+ from holmes.core.tools import (
6
+ StructuredToolResult,
7
+ StructuredToolResultStatus,
8
+ ToolInvokeContext,
9
+ )
6
10
  from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
7
11
  BaseAzureSQLTool,
8
12
  BaseAzureSQLToolset,
@@ -192,9 +196,7 @@ class AnalyzeDatabasePerformance(BaseAzureSQLTool):
192
196
 
193
197
  return "\n".join(report_sections)
194
198
 
195
- def _invoke(
196
- self, params: dict, user_approved: bool = False
197
- ) -> StructuredToolResult:
199
+ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolResult:
198
200
  try:
199
201
  db_config = self.toolset.database_config()
200
202
  client = self.toolset.api_client()
@@ -206,7 +208,7 @@ class AnalyzeDatabasePerformance(BaseAzureSQLTool):
206
208
  report_text = self._build_performance_report(performance_data, db_config)
207
209
 
208
210
  return StructuredToolResult(
209
- status=ToolResultStatus.SUCCESS,
211
+ status=StructuredToolResultStatus.SUCCESS,
210
212
  data=report_text,
211
213
  params=params,
212
214
  )
@@ -214,7 +216,7 @@ class AnalyzeDatabasePerformance(BaseAzureSQLTool):
214
216
  error_msg = f"Failed to generate performance report: {str(e)}"
215
217
  logging.error(error_msg)
216
218
  return StructuredToolResult(
217
- status=ToolResultStatus.ERROR,
219
+ status=StructuredToolResultStatus.ERROR,
218
220
  error=error_msg,
219
221
  params=params,
220
222
  )
@@ -2,7 +2,12 @@ import logging
2
2
  from typing import Any, Dict, Tuple
3
3
  from datetime import datetime, timezone
4
4
 
5
- from holmes.core.tools import StructuredToolResult, ToolParameter, ToolResultStatus
5
+ from holmes.core.tools import (
6
+ StructuredToolResult,
7
+ ToolInvokeContext,
8
+ ToolParameter,
9
+ StructuredToolResultStatus,
10
+ )
6
11
  from holmes.plugins.toolsets.azure_sql.azure_base_toolset import (
7
12
  BaseAzureSQLTool,
8
13
  BaseAzureSQLToolset,
@@ -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
  )