holmesgpt 0.12.0a0__py3-none-any.whl → 0.12.1__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 holmesgpt might be problematic. Click here for more details.
- holmes/__init__.py +6 -74
- holmes/clients/robusta_client.py +1 -1
- holmes/common/env_vars.py +1 -0
- holmes/common/openshift.py +15 -0
- holmes/config.py +0 -27
- holmes/core/llm.py +5 -8
- holmes/core/supabase_dal.py +4 -0
- holmes/core/tool_calling_llm.py +12 -3
- holmes/core/tools.py +2 -1
- holmes/core/toolset_manager.py +1 -1
- holmes/core/tracing.py +5 -4
- holmes/interactive.py +46 -16
- holmes/main.py +6 -2
- holmes/plugins/toolsets/prometheus/prometheus.py +21 -2
- holmes/utils/console/logging.py +3 -0
- holmes/version.py +178 -0
- {holmesgpt-0.12.0a0.dist-info → holmesgpt-0.12.1.dist-info}/METADATA +3 -2
- {holmesgpt-0.12.0a0.dist-info → holmesgpt-0.12.1.dist-info}/RECORD +21 -19
- {holmesgpt-0.12.0a0.dist-info → holmesgpt-0.12.1.dist-info}/LICENSE.txt +0 -0
- {holmesgpt-0.12.0a0.dist-info → holmesgpt-0.12.1.dist-info}/WHEEL +0 -0
- {holmesgpt-0.12.0a0.dist-info → holmesgpt-0.12.1.dist-info}/entry_points.txt +0 -0
holmes/__init__.py
CHANGED
|
@@ -1,76 +1,8 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import os
|
|
3
|
-
import subprocess
|
|
4
|
-
import sys
|
|
5
|
-
from cachetools import cached # type: ignore
|
|
6
|
-
|
|
7
|
-
# For relative imports to work in Python 3.6 - see https://stackoverflow.com/a/49375740
|
|
8
|
-
this_path = os.path.dirname(os.path.realpath(__file__))
|
|
9
|
-
sys.path.append(this_path)
|
|
10
|
-
|
|
11
1
|
# This is patched by github actions during release
|
|
12
|
-
__version__ = "0.12.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def is_official_release() -> bool:
|
|
16
|
-
return not __version__.startswith("0.0.0")
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@cached(cache=dict())
|
|
20
|
-
def get_version() -> str:
|
|
21
|
-
# the version string was patched by a release - return __version__ which will be correct
|
|
22
|
-
if is_official_release():
|
|
23
|
-
return __version__
|
|
24
|
-
|
|
25
|
-
# we are running from an unreleased dev version
|
|
26
|
-
try:
|
|
27
|
-
# Get the latest git tag
|
|
28
|
-
tag = (
|
|
29
|
-
subprocess.check_output(
|
|
30
|
-
["git", "describe", "--tags"], stderr=subprocess.STDOUT, cwd=this_path
|
|
31
|
-
)
|
|
32
|
-
.decode()
|
|
33
|
-
.strip()
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
# Get the current branch name
|
|
37
|
-
branch = (
|
|
38
|
-
subprocess.check_output(
|
|
39
|
-
["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
|
40
|
-
stderr=subprocess.STDOUT,
|
|
41
|
-
cwd=this_path,
|
|
42
|
-
)
|
|
43
|
-
.decode()
|
|
44
|
-
.strip()
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
# Check if there are uncommitted changes
|
|
48
|
-
status = (
|
|
49
|
-
subprocess.check_output(
|
|
50
|
-
["git", "status", "--porcelain"],
|
|
51
|
-
stderr=subprocess.STDOUT,
|
|
52
|
-
cwd=this_path,
|
|
53
|
-
)
|
|
54
|
-
.decode()
|
|
55
|
-
.strip()
|
|
56
|
-
)
|
|
57
|
-
dirty = "-dirty" if status else ""
|
|
58
|
-
|
|
59
|
-
return f"{tag}-{branch}{dirty}"
|
|
60
|
-
|
|
61
|
-
except Exception:
|
|
62
|
-
pass
|
|
63
|
-
|
|
64
|
-
# we are running without git history, but we still might have git archival data (e.g. if we were pip installed)
|
|
65
|
-
archival_file_path = os.path.join(this_path, ".git_archival.json")
|
|
66
|
-
if os.path.exists(archival_file_path):
|
|
67
|
-
try:
|
|
68
|
-
with open(archival_file_path, "r") as f:
|
|
69
|
-
archival_data = json.load(f)
|
|
70
|
-
return f"dev-{archival_data['refs']}-{archival_data['hash-short']}"
|
|
71
|
-
except Exception:
|
|
72
|
-
pass
|
|
73
|
-
|
|
74
|
-
return "dev-version"
|
|
2
|
+
__version__ = "0.12.1"
|
|
75
3
|
|
|
76
|
-
|
|
4
|
+
# Re-export version functions from version module for backward compatibility
|
|
5
|
+
from .version import (
|
|
6
|
+
get_version as get_version,
|
|
7
|
+
is_official_release as is_official_release,
|
|
8
|
+
)
|
holmes/clients/robusta_client.py
CHANGED
holmes/common/env_vars.py
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
# NOTE: This one will be mounted if openshift is enabled in values.yaml
|
|
5
|
+
TOKEN_LOCATION = os.environ.get(
|
|
6
|
+
"TOKEN_LOCATION", "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def load_openshift_token() -> Optional[str]:
|
|
11
|
+
try:
|
|
12
|
+
with open(TOKEN_LOCATION, "r") as file:
|
|
13
|
+
return file.read()
|
|
14
|
+
except FileNotFoundError:
|
|
15
|
+
return None
|
holmes/config.py
CHANGED
|
@@ -9,8 +9,6 @@ from typing import Any, List, Optional, Union
|
|
|
9
9
|
import yaml # type: ignore
|
|
10
10
|
from pydantic import BaseModel, ConfigDict, FilePath, SecretStr
|
|
11
11
|
|
|
12
|
-
from holmes import get_version # type: ignore
|
|
13
|
-
from holmes.clients.robusta_client import HolmesInfo, fetch_holmes_info
|
|
14
12
|
from holmes.common.env_vars import ROBUSTA_AI, ROBUSTA_API_ENDPOINT, ROBUSTA_CONFIG_PATH
|
|
15
13
|
from holmes.core.llm import LLM, DefaultLLM
|
|
16
14
|
from holmes.core.runbooks import RunbookManager
|
|
@@ -116,26 +114,8 @@ class Config(RobustaBaseConfig):
|
|
|
116
114
|
|
|
117
115
|
_server_tool_executor: Optional[ToolExecutor] = None
|
|
118
116
|
|
|
119
|
-
_version: Optional[str] = None
|
|
120
|
-
_holmes_info: Optional[HolmesInfo] = None
|
|
121
|
-
|
|
122
117
|
_toolset_manager: Optional[ToolsetManager] = None
|
|
123
118
|
|
|
124
|
-
@property
|
|
125
|
-
def is_latest_version(self) -> bool:
|
|
126
|
-
if (
|
|
127
|
-
not self._holmes_info
|
|
128
|
-
or not self._holmes_info.latest_version
|
|
129
|
-
or not self._version
|
|
130
|
-
):
|
|
131
|
-
# We couldn't resolve version, assume we are running the latest version
|
|
132
|
-
return True
|
|
133
|
-
if self._version.startswith("dev-"):
|
|
134
|
-
# dev versions are considered to be the latest version
|
|
135
|
-
return True
|
|
136
|
-
|
|
137
|
-
return self._version.startswith(self._holmes_info.latest_version)
|
|
138
|
-
|
|
139
119
|
@property
|
|
140
120
|
def toolset_manager(self) -> ToolsetManager:
|
|
141
121
|
if not self._toolset_manager:
|
|
@@ -147,8 +127,6 @@ class Config(RobustaBaseConfig):
|
|
|
147
127
|
return self._toolset_manager
|
|
148
128
|
|
|
149
129
|
def model_post_init(self, __context: Any) -> None:
|
|
150
|
-
self._version = get_version()
|
|
151
|
-
self._holmes_info = fetch_holmes_info()
|
|
152
130
|
self._model_list = parse_models_file(MODEL_LIST_FILE_LOCATION)
|
|
153
131
|
if self._should_load_robusta_ai():
|
|
154
132
|
logging.info("Loading Robusta AI model")
|
|
@@ -179,11 +157,6 @@ class Config(RobustaBaseConfig):
|
|
|
179
157
|
if self._model_list:
|
|
180
158
|
logging.info(f"loaded models: {list(self._model_list.keys())}")
|
|
181
159
|
|
|
182
|
-
if not self.is_latest_version and self._holmes_info:
|
|
183
|
-
logging.warning(
|
|
184
|
-
f"You are running version {self._version} of holmes, but the latest version is {self._holmes_info.latest_version}. Please update.",
|
|
185
|
-
)
|
|
186
|
-
|
|
187
160
|
@classmethod
|
|
188
161
|
def load_from_file(cls, config_file: Optional[Path], **kwargs) -> "Config":
|
|
189
162
|
"""
|
holmes/core/llm.py
CHANGED
|
@@ -140,14 +140,11 @@ class DefaultLLM(LLM):
|
|
|
140
140
|
https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json
|
|
141
141
|
"""
|
|
142
142
|
model_name = self.model
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
model_name = model_name[
|
|
149
|
-
len("vertex_ai/") :
|
|
150
|
-
] # Strip the 'vertex_ai/' prefix
|
|
143
|
+
prefixes = ["openai/", "bedrock/", "vertex_ai/", "anthropic/"]
|
|
144
|
+
|
|
145
|
+
for prefix in prefixes:
|
|
146
|
+
if model_name.startswith(prefix):
|
|
147
|
+
return model_name[len(prefix) :]
|
|
151
148
|
|
|
152
149
|
return model_name
|
|
153
150
|
|
holmes/core/supabase_dal.py
CHANGED
|
@@ -182,6 +182,10 @@ class SupabaseDal:
|
|
|
182
182
|
res = self.client.auth.sign_in_with_password(
|
|
183
183
|
{"email": self.email, "password": self.password}
|
|
184
184
|
)
|
|
185
|
+
if not res.session:
|
|
186
|
+
raise ValueError("Authentication failed: no session returned")
|
|
187
|
+
if not res.user:
|
|
188
|
+
raise ValueError("Authentication failed: no user returned")
|
|
185
189
|
self.client.auth.set_session(
|
|
186
190
|
res.session.access_token, res.session.refresh_token
|
|
187
191
|
)
|
holmes/core/tool_calling_llm.py
CHANGED
|
@@ -39,7 +39,7 @@ from holmes.utils.global_instructions import (
|
|
|
39
39
|
)
|
|
40
40
|
from holmes.utils.tags import format_tags_in_string, parse_messages_tags
|
|
41
41
|
from holmes.core.tools_utils.tool_executor import ToolExecutor
|
|
42
|
-
from holmes.core.tracing import DummySpan
|
|
42
|
+
from holmes.core.tracing import DummySpan
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
def format_tool_result_data(tool_result: StructuredToolResult) -> str:
|
|
@@ -249,6 +249,7 @@ class ToolCallingLLM:
|
|
|
249
249
|
user_prompt: Optional[str] = None,
|
|
250
250
|
sections: Optional[InputSectionsDataType] = None,
|
|
251
251
|
trace_span=DummySpan(),
|
|
252
|
+
tool_number_offset: int = 0,
|
|
252
253
|
) -> LLMResult:
|
|
253
254
|
perf_timing = PerformanceTiming("tool_calling_llm.call")
|
|
254
255
|
tool_calls = [] # type: ignore
|
|
@@ -367,7 +368,7 @@ class ToolCallingLLM:
|
|
|
367
368
|
tool_to_call=t,
|
|
368
369
|
previous_tool_calls=tool_calls,
|
|
369
370
|
trace_span=trace_span,
|
|
370
|
-
tool_number=tool_index,
|
|
371
|
+
tool_number=tool_number_offset + tool_index,
|
|
371
372
|
)
|
|
372
373
|
)
|
|
373
374
|
|
|
@@ -383,6 +384,8 @@ class ToolCallingLLM:
|
|
|
383
384
|
if tools_to_call:
|
|
384
385
|
logging.info("")
|
|
385
386
|
|
|
387
|
+
raise Exception(f"Too many LLM calls - exceeded max_steps: {i}/{max_steps}")
|
|
388
|
+
|
|
386
389
|
def _invoke_tool(
|
|
387
390
|
self,
|
|
388
391
|
tool_to_call: ChatCompletionMessageToolCall,
|
|
@@ -419,7 +422,7 @@ class ToolCallingLLM:
|
|
|
419
422
|
tool_response = None
|
|
420
423
|
|
|
421
424
|
# Create tool span if tracing is enabled
|
|
422
|
-
tool_span = trace_span.start_span(name=tool_name, type=
|
|
425
|
+
tool_span = trace_span.start_span(name=tool_name, type="tool")
|
|
423
426
|
|
|
424
427
|
try:
|
|
425
428
|
tool_response = prevent_overly_repeated_tool_call(
|
|
@@ -448,6 +451,8 @@ class ToolCallingLLM:
|
|
|
448
451
|
metadata={
|
|
449
452
|
"status": tool_response.status.value,
|
|
450
453
|
"error": tool_response.error,
|
|
454
|
+
"description": tool.get_parameterized_one_liner(tool_params),
|
|
455
|
+
"structured_tool_result": tool_response,
|
|
451
456
|
},
|
|
452
457
|
)
|
|
453
458
|
|
|
@@ -720,6 +725,10 @@ class ToolCallingLLM:
|
|
|
720
725
|
"tool_calling_result", streaming_result_dict
|
|
721
726
|
)
|
|
722
727
|
|
|
728
|
+
raise Exception(
|
|
729
|
+
f"Too many LLM calls - exceeded max_steps: {i}/{self.max_steps}"
|
|
730
|
+
)
|
|
731
|
+
|
|
723
732
|
|
|
724
733
|
# TODO: consider getting rid of this entirely and moving templating into the cmds in holmes_cli.py
|
|
725
734
|
class IssueInvestigator(ToolCallingLLM):
|
holmes/core/tools.py
CHANGED
|
@@ -154,8 +154,9 @@ class Tool(ABC, BaseModel):
|
|
|
154
154
|
if hasattr(result, "get_stringified_data")
|
|
155
155
|
else str(result)
|
|
156
156
|
)
|
|
157
|
+
show_hint = f"/show {tool_number}" if tool_number else "/show"
|
|
157
158
|
logging.info(
|
|
158
|
-
f" [dim]Finished {tool_number_str}in {elapsed:.2f}s, output length: {len(output_str):,} characters -
|
|
159
|
+
f" [dim]Finished {tool_number_str}in {elapsed:.2f}s, output length: {len(output_str):,} characters - {show_hint} to view contents[/dim]"
|
|
159
160
|
)
|
|
160
161
|
return result
|
|
161
162
|
|
holmes/core/toolset_manager.py
CHANGED
|
@@ -290,7 +290,7 @@ class ToolsetManager:
|
|
|
290
290
|
[toolset for toolset in all_toolsets_with_status if toolset.enabled]
|
|
291
291
|
)
|
|
292
292
|
logging.info(
|
|
293
|
-
f"Using {num_available_toolsets} datasources (toolsets). To refresh:
|
|
293
|
+
f"Using {num_available_toolsets} datasources (toolsets). To refresh: use flag `--refresh-toolsets`"
|
|
294
294
|
)
|
|
295
295
|
return all_toolsets_with_status
|
|
296
296
|
|
holmes/core/tracing.py
CHANGED
|
@@ -32,12 +32,13 @@ class SpanType(Enum):
|
|
|
32
32
|
TOOL = "tool"
|
|
33
33
|
TASK = "task"
|
|
34
34
|
SCORE = "score"
|
|
35
|
+
EVAL = "eval"
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
class DummySpan:
|
|
38
39
|
"""A no-op span implementation for when tracing is disabled."""
|
|
39
40
|
|
|
40
|
-
def start_span(self, name: str, span_type
|
|
41
|
+
def start_span(self, name: str, span_type=None, **kwargs):
|
|
41
42
|
return DummySpan()
|
|
42
43
|
|
|
43
44
|
def log(self, *args, **kwargs):
|
|
@@ -121,17 +122,17 @@ class BraintrustTracer:
|
|
|
121
122
|
# Add span type to kwargs if provided
|
|
122
123
|
kwargs = {}
|
|
123
124
|
if span_type:
|
|
124
|
-
kwargs["type"] =
|
|
125
|
+
kwargs["type"] = span_type.value
|
|
125
126
|
|
|
126
127
|
# Use current Braintrust context (experiment or parent span)
|
|
127
128
|
current_span = braintrust.current_span()
|
|
128
129
|
if not _is_noop_span(current_span):
|
|
129
|
-
return current_span.start_span(name=name, **kwargs)
|
|
130
|
+
return current_span.start_span(name=name, **kwargs) # type: ignore
|
|
130
131
|
|
|
131
132
|
# Fallback to current experiment
|
|
132
133
|
current_experiment = braintrust.current_experiment()
|
|
133
134
|
if current_experiment:
|
|
134
|
-
return current_experiment.start_span(name=name, **kwargs)
|
|
135
|
+
return current_experiment.start_span(name=name, **kwargs) # type: ignore
|
|
135
136
|
|
|
136
137
|
return DummySpan()
|
|
137
138
|
|
holmes/interactive.py
CHANGED
|
@@ -6,15 +6,15 @@ import threading
|
|
|
6
6
|
from collections import defaultdict
|
|
7
7
|
from enum import Enum
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import
|
|
9
|
+
from typing import DefaultDict, List, Optional
|
|
10
10
|
|
|
11
11
|
import typer
|
|
12
12
|
from prompt_toolkit import PromptSession
|
|
13
13
|
from prompt_toolkit.application import Application
|
|
14
14
|
from prompt_toolkit.completion import Completer, Completion, merge_completers
|
|
15
15
|
from prompt_toolkit.completion.filesystem import ExecutableCompleter, PathCompleter
|
|
16
|
-
from prompt_toolkit.history import InMemoryHistory, FileHistory
|
|
17
16
|
from prompt_toolkit.document import Document
|
|
17
|
+
from prompt_toolkit.history import FileHistory, InMemoryHistory
|
|
18
18
|
from prompt_toolkit.key_binding import KeyBindings
|
|
19
19
|
from prompt_toolkit.layout import Layout
|
|
20
20
|
from prompt_toolkit.layout.containers import HSplit, Window
|
|
@@ -22,27 +22,26 @@ from prompt_toolkit.layout.controls import FormattedTextControl
|
|
|
22
22
|
from prompt_toolkit.shortcuts.prompt import CompleteStyle
|
|
23
23
|
from prompt_toolkit.styles import Style
|
|
24
24
|
from prompt_toolkit.widgets import TextArea
|
|
25
|
-
|
|
26
25
|
from rich.console import Console
|
|
27
26
|
from rich.markdown import Markdown, Panel
|
|
28
27
|
|
|
29
28
|
from holmes.core.prompt import build_initial_ask_messages
|
|
30
29
|
from holmes.core.tool_calling_llm import ToolCallingLLM, ToolCallResult
|
|
31
30
|
from holmes.core.tools import pretty_print_toolset_status
|
|
32
|
-
from holmes.
|
|
31
|
+
from holmes.version import check_version_async
|
|
32
|
+
from holmes.core.tracing import DummyTracer
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
class SlashCommands(Enum):
|
|
36
36
|
EXIT = ("/exit", "Exit interactive mode")
|
|
37
37
|
HELP = ("/help", "Show help message with all commands")
|
|
38
|
-
|
|
38
|
+
CLEAR = ("/clear", "Clear screen and reset conversation context")
|
|
39
39
|
TOOLS_CONFIG = ("/tools", "Show available toolsets and their status")
|
|
40
40
|
TOGGLE_TOOL_OUTPUT = (
|
|
41
41
|
"/auto",
|
|
42
42
|
"Toggle auto-display of tool outputs after responses",
|
|
43
43
|
)
|
|
44
44
|
LAST_OUTPUT = ("/last", "Show all tool outputs from last response")
|
|
45
|
-
CLEAR = ("/clear", "Clear the terminal screen")
|
|
46
45
|
RUN = ("/run", "Run a bash command and optionally share with LLM")
|
|
47
46
|
SHELL = (
|
|
48
47
|
"/shell",
|
|
@@ -722,9 +721,9 @@ def run_interactive_loop(
|
|
|
722
721
|
show_tool_output: bool,
|
|
723
722
|
tracer=None,
|
|
724
723
|
) -> None:
|
|
725
|
-
# Initialize tracer - use
|
|
724
|
+
# Initialize tracer - use DummyTracer if no tracer provided
|
|
726
725
|
if tracer is None:
|
|
727
|
-
tracer =
|
|
726
|
+
tracer = DummyTracer()
|
|
728
727
|
|
|
729
728
|
style = Style.from_dict(
|
|
730
729
|
{
|
|
@@ -753,6 +752,23 @@ def run_interactive_loop(
|
|
|
753
752
|
# Create custom key bindings for Ctrl+C behavior
|
|
754
753
|
bindings = KeyBindings()
|
|
755
754
|
status_message = ""
|
|
755
|
+
version_message = ""
|
|
756
|
+
|
|
757
|
+
def clear_version_message():
|
|
758
|
+
nonlocal version_message
|
|
759
|
+
version_message = ""
|
|
760
|
+
session.app.invalidate()
|
|
761
|
+
|
|
762
|
+
def on_version_check_complete(result):
|
|
763
|
+
"""Callback when background version check completes"""
|
|
764
|
+
nonlocal version_message
|
|
765
|
+
if not result.is_latest and result.update_message:
|
|
766
|
+
version_message = result.update_message
|
|
767
|
+
session.app.invalidate()
|
|
768
|
+
|
|
769
|
+
# Auto-clear after 10 seconds
|
|
770
|
+
timer = threading.Timer(10, clear_version_message)
|
|
771
|
+
timer.start()
|
|
756
772
|
|
|
757
773
|
@bindings.add("c-c")
|
|
758
774
|
def _(event):
|
|
@@ -776,9 +792,19 @@ def run_interactive_loop(
|
|
|
776
792
|
raise KeyboardInterrupt()
|
|
777
793
|
|
|
778
794
|
def get_bottom_toolbar():
|
|
795
|
+
messages = []
|
|
796
|
+
|
|
797
|
+
# Ctrl-c status message (red background)
|
|
779
798
|
if status_message:
|
|
780
|
-
|
|
781
|
-
|
|
799
|
+
messages.append(("bg:#ff0000 fg:#000000", status_message))
|
|
800
|
+
|
|
801
|
+
# Version message (yellow background)
|
|
802
|
+
if version_message:
|
|
803
|
+
if messages:
|
|
804
|
+
messages.append(("", " | "))
|
|
805
|
+
messages.append(("bg:#ffff00 fg:#000000", version_message))
|
|
806
|
+
|
|
807
|
+
return messages if messages else None
|
|
782
808
|
|
|
783
809
|
session = PromptSession(
|
|
784
810
|
completer=command_completer,
|
|
@@ -789,6 +815,9 @@ def run_interactive_loop(
|
|
|
789
815
|
bottom_toolbar=get_bottom_toolbar,
|
|
790
816
|
) # type: ignore
|
|
791
817
|
|
|
818
|
+
# Start background version check
|
|
819
|
+
check_version_async(on_version_check_complete)
|
|
820
|
+
|
|
792
821
|
input_prompt = [("class:prompt", "User: ")]
|
|
793
822
|
|
|
794
823
|
console.print(WELCOME_BANNER)
|
|
@@ -833,9 +862,10 @@ def run_interactive_loop(
|
|
|
833
862
|
for cmd, description in SLASH_COMMANDS_REFERENCE.items():
|
|
834
863
|
console.print(f" [bold]{cmd}[/bold] - {description}")
|
|
835
864
|
continue
|
|
836
|
-
elif command == SlashCommands.
|
|
865
|
+
elif command == SlashCommands.CLEAR.command:
|
|
866
|
+
console.clear()
|
|
837
867
|
console.print(
|
|
838
|
-
f"[bold {STATUS_COLOR}]
|
|
868
|
+
f"[bold {STATUS_COLOR}]Screen cleared and context reset. You can now ask a new question.[/bold {STATUS_COLOR}]"
|
|
839
869
|
)
|
|
840
870
|
messages = None
|
|
841
871
|
last_response = None
|
|
@@ -854,9 +884,6 @@ def run_interactive_loop(
|
|
|
854
884
|
elif command == SlashCommands.LAST_OUTPUT.command:
|
|
855
885
|
handle_last_command(last_response, console, all_tool_calls_history)
|
|
856
886
|
continue
|
|
857
|
-
elif command == SlashCommands.CLEAR.command:
|
|
858
|
-
console.clear()
|
|
859
|
-
continue
|
|
860
887
|
elif command == SlashCommands.CONTEXT.command:
|
|
861
888
|
handle_context_command(messages, ai, console)
|
|
862
889
|
continue
|
|
@@ -902,7 +929,10 @@ def run_interactive_loop(
|
|
|
902
929
|
metadata={"type": "user_question"},
|
|
903
930
|
)
|
|
904
931
|
response = ai.call(
|
|
905
|
-
messages,
|
|
932
|
+
messages,
|
|
933
|
+
post_processing_prompt,
|
|
934
|
+
trace_span=trace_span,
|
|
935
|
+
tool_number_offset=len(all_tool_calls_history),
|
|
906
936
|
)
|
|
907
937
|
trace_span.log(
|
|
908
938
|
output=response.result,
|
holmes/main.py
CHANGED
|
@@ -219,16 +219,20 @@ def ask(
|
|
|
219
219
|
Ask any question and answer using available tools
|
|
220
220
|
"""
|
|
221
221
|
console = init_logging(verbose) # type: ignore
|
|
222
|
-
|
|
223
222
|
# Detect and read piped input
|
|
224
223
|
piped_data = None
|
|
225
|
-
|
|
224
|
+
|
|
225
|
+
# when attaching a pycharm debugger sys.stdin.isatty() returns false and sys.stdin.read() is stuck
|
|
226
|
+
running_from_pycharm = os.environ.get("PYCHARM_HOSTED", False)
|
|
227
|
+
|
|
228
|
+
if not sys.stdin.isatty() and not running_from_pycharm:
|
|
226
229
|
piped_data = sys.stdin.read().strip()
|
|
227
230
|
if interactive:
|
|
228
231
|
console.print(
|
|
229
232
|
"[bold yellow]Interactive mode disabled when reading piped input[/bold yellow]"
|
|
230
233
|
)
|
|
231
234
|
interactive = False
|
|
235
|
+
|
|
232
236
|
config = Config.load_from_file(
|
|
233
237
|
config_file,
|
|
234
238
|
api_key=api_key,
|
|
@@ -9,7 +9,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union
|
|
|
9
9
|
from urllib.parse import urljoin
|
|
10
10
|
|
|
11
11
|
import requests # type: ignore
|
|
12
|
-
from pydantic import BaseModel, field_validator
|
|
12
|
+
from pydantic import BaseModel, field_validator, Field, model_validator
|
|
13
13
|
from requests import RequestException
|
|
14
14
|
|
|
15
15
|
from holmes.core.tools import (
|
|
@@ -29,6 +29,8 @@ from holmes.plugins.toolsets.utils import (
|
|
|
29
29
|
standard_start_datetime_tool_param_description,
|
|
30
30
|
)
|
|
31
31
|
from holmes.utils.cache import TTLCache
|
|
32
|
+
from holmes.common.env_vars import IS_OPENSHIFT
|
|
33
|
+
from holmes.common.openshift import load_openshift_token
|
|
32
34
|
|
|
33
35
|
PROMETHEUS_RULES_CACHE_KEY = "cached_prometheus_rules"
|
|
34
36
|
DEFAULT_TIME_SPAN_SECONDS = 3600
|
|
@@ -45,7 +47,7 @@ class PrometheusConfig(BaseModel):
|
|
|
45
47
|
fetch_labels_with_labels_api: bool = False
|
|
46
48
|
fetch_metadata_with_series_api: bool = False
|
|
47
49
|
tool_calls_return_data: bool = True
|
|
48
|
-
headers: Dict =
|
|
50
|
+
headers: Dict = Field(default_factory=dict)
|
|
49
51
|
rules_cache_duration_seconds: Union[int, None] = 1800 # 30 minutes
|
|
50
52
|
additional_labels: Optional[Dict[str, str]] = None
|
|
51
53
|
|
|
@@ -55,6 +57,23 @@ class PrometheusConfig(BaseModel):
|
|
|
55
57
|
return v + "/"
|
|
56
58
|
return v
|
|
57
59
|
|
|
60
|
+
@model_validator(mode="after")
|
|
61
|
+
def validate_prom_config(self):
|
|
62
|
+
# If openshift is enabled, and the user didn't configure auth headers, we will try to load the token from the service account.
|
|
63
|
+
if IS_OPENSHIFT:
|
|
64
|
+
if self.healthcheck == "-/healthy":
|
|
65
|
+
self.healthcheck = "api/v1/query?query=up"
|
|
66
|
+
|
|
67
|
+
if self.headers.get("Authorization"):
|
|
68
|
+
return self
|
|
69
|
+
|
|
70
|
+
openshift_token = load_openshift_token()
|
|
71
|
+
if openshift_token:
|
|
72
|
+
logging.info("Using openshift token for prometheus toolset auth")
|
|
73
|
+
self.headers["Authorization"] = f"Bearer {openshift_token}"
|
|
74
|
+
|
|
75
|
+
return self
|
|
76
|
+
|
|
58
77
|
|
|
59
78
|
class BasePrometheusTool(Tool):
|
|
60
79
|
toolset: "PrometheusToolset"
|
holmes/utils/console/logging.py
CHANGED
|
@@ -46,6 +46,7 @@ def init_logging(verbose_flags: Optional[List[bool]] = None):
|
|
|
46
46
|
|
|
47
47
|
if verbosity == Verbosity.VERY_VERBOSE:
|
|
48
48
|
logging.basicConfig(
|
|
49
|
+
force=True,
|
|
49
50
|
level=logging.DEBUG,
|
|
50
51
|
format="%(message)s",
|
|
51
52
|
handlers=[
|
|
@@ -60,6 +61,7 @@ def init_logging(verbose_flags: Optional[List[bool]] = None):
|
|
|
60
61
|
)
|
|
61
62
|
elif verbosity == Verbosity.VERBOSE:
|
|
62
63
|
logging.basicConfig(
|
|
64
|
+
force=True,
|
|
63
65
|
level=logging.INFO,
|
|
64
66
|
format="%(message)s",
|
|
65
67
|
handlers=[
|
|
@@ -76,6 +78,7 @@ def init_logging(verbose_flags: Optional[List[bool]] = None):
|
|
|
76
78
|
suppress_noisy_logs()
|
|
77
79
|
else:
|
|
78
80
|
logging.basicConfig(
|
|
81
|
+
force=True,
|
|
79
82
|
level=logging.INFO,
|
|
80
83
|
format="%(message)s",
|
|
81
84
|
handlers=[
|
holmes/version.py
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Centralized version management for Holmes.
|
|
3
|
+
Handles current version detection, latest version fetching, and comparison logic.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
import threading
|
|
11
|
+
from typing import Optional, NamedTuple
|
|
12
|
+
from functools import cache
|
|
13
|
+
import requests # type: ignore
|
|
14
|
+
from pydantic import BaseModel, ConfigDict
|
|
15
|
+
from holmes.common.env_vars import ROBUSTA_API_ENDPOINT
|
|
16
|
+
|
|
17
|
+
# For relative imports to work in Python 3.6 - see https://stackoverflow.com/a/49375740
|
|
18
|
+
this_path = os.path.dirname(os.path.realpath(__file__))
|
|
19
|
+
sys.path.append(this_path)
|
|
20
|
+
|
|
21
|
+
# Version checking API constants
|
|
22
|
+
HOLMES_GET_INFO_URL = f"{ROBUSTA_API_ENDPOINT}/api/holmes/get_info"
|
|
23
|
+
TIMEOUT = 0.5
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class HolmesInfo(BaseModel):
|
|
27
|
+
model_config = ConfigDict(extra="ignore")
|
|
28
|
+
latest_version: Optional[str] = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class VersionCheckResult(NamedTuple):
|
|
32
|
+
"""Result of version check with all relevant info"""
|
|
33
|
+
|
|
34
|
+
is_latest: bool
|
|
35
|
+
current_version: str
|
|
36
|
+
latest_version: Optional[str] = None
|
|
37
|
+
update_message: Optional[str] = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def is_official_release() -> bool:
|
|
41
|
+
"""Check if this is an official release (version was patched by CI/CD)"""
|
|
42
|
+
from holmes import __version__
|
|
43
|
+
|
|
44
|
+
return not __version__.startswith("0.0.0")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@cache
|
|
48
|
+
def get_version() -> str:
|
|
49
|
+
"""
|
|
50
|
+
Get the current version of Holmes.
|
|
51
|
+
Returns the official version if patched by CI/CD, otherwise builds from git.
|
|
52
|
+
"""
|
|
53
|
+
from holmes import __version__
|
|
54
|
+
|
|
55
|
+
# the version string was patched by a release - return __version__ which will be correct
|
|
56
|
+
if is_official_release():
|
|
57
|
+
return __version__
|
|
58
|
+
|
|
59
|
+
# we are running from an unreleased dev version
|
|
60
|
+
try:
|
|
61
|
+
# Get the latest git tag
|
|
62
|
+
tag = (
|
|
63
|
+
subprocess.check_output(
|
|
64
|
+
["git", "describe", "--tags"], stderr=subprocess.STDOUT, cwd=this_path
|
|
65
|
+
)
|
|
66
|
+
.decode()
|
|
67
|
+
.strip()
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Get the current branch name
|
|
71
|
+
branch = (
|
|
72
|
+
subprocess.check_output(
|
|
73
|
+
["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
|
74
|
+
stderr=subprocess.STDOUT,
|
|
75
|
+
cwd=this_path,
|
|
76
|
+
)
|
|
77
|
+
.decode()
|
|
78
|
+
.strip()
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Check if there are uncommitted changes
|
|
82
|
+
status = (
|
|
83
|
+
subprocess.check_output(
|
|
84
|
+
["git", "status", "--porcelain"],
|
|
85
|
+
stderr=subprocess.STDOUT,
|
|
86
|
+
cwd=this_path,
|
|
87
|
+
)
|
|
88
|
+
.decode()
|
|
89
|
+
.strip()
|
|
90
|
+
)
|
|
91
|
+
dirty = "-dirty" if status else ""
|
|
92
|
+
|
|
93
|
+
return f"{tag}-{branch}{dirty}"
|
|
94
|
+
|
|
95
|
+
except Exception:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
# we are running without git history, but we still might have git archival data (e.g. if we were pip installed)
|
|
99
|
+
archival_file_path = os.path.join(this_path, ".git_archival.json")
|
|
100
|
+
if os.path.exists(archival_file_path):
|
|
101
|
+
try:
|
|
102
|
+
with open(archival_file_path, "r") as f:
|
|
103
|
+
archival_data = json.load(f)
|
|
104
|
+
return f"dev-{archival_data['refs']}-{archival_data['hash-short']}"
|
|
105
|
+
except Exception:
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
return "dev-version"
|
|
109
|
+
|
|
110
|
+
return "unknown-version"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@cache
|
|
114
|
+
def fetch_holmes_info() -> Optional[HolmesInfo]:
|
|
115
|
+
"""Fetch latest version information from Robusta API"""
|
|
116
|
+
try:
|
|
117
|
+
response = requests.get(HOLMES_GET_INFO_URL, timeout=TIMEOUT)
|
|
118
|
+
response.raise_for_status()
|
|
119
|
+
result = response.json()
|
|
120
|
+
return HolmesInfo(**result)
|
|
121
|
+
except Exception:
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def check_version() -> VersionCheckResult:
|
|
126
|
+
"""
|
|
127
|
+
Centralized version checking logic.
|
|
128
|
+
Returns complete version check result with message.
|
|
129
|
+
"""
|
|
130
|
+
current_version = get_version()
|
|
131
|
+
holmes_info = fetch_holmes_info()
|
|
132
|
+
|
|
133
|
+
# Default to latest if we can't determine
|
|
134
|
+
if not holmes_info or not holmes_info.latest_version or not current_version:
|
|
135
|
+
return VersionCheckResult(
|
|
136
|
+
is_latest=True, current_version=current_version or "unknown"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Dev versions are considered latest
|
|
140
|
+
if current_version.startswith("dev-"):
|
|
141
|
+
return VersionCheckResult(
|
|
142
|
+
is_latest=True,
|
|
143
|
+
current_version=current_version,
|
|
144
|
+
latest_version=holmes_info.latest_version,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Check if current version starts with latest version
|
|
148
|
+
is_latest = current_version.startswith(holmes_info.latest_version)
|
|
149
|
+
|
|
150
|
+
update_message = None
|
|
151
|
+
if not is_latest:
|
|
152
|
+
update_message = f"Update available: v{holmes_info.latest_version} (current: {current_version})"
|
|
153
|
+
|
|
154
|
+
return VersionCheckResult(
|
|
155
|
+
is_latest=is_latest,
|
|
156
|
+
current_version=current_version,
|
|
157
|
+
latest_version=holmes_info.latest_version,
|
|
158
|
+
update_message=update_message,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def check_version_async(callback):
|
|
163
|
+
"""
|
|
164
|
+
Async version check for background use.
|
|
165
|
+
Calls callback with VersionCheckResult when complete.
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
def _check():
|
|
169
|
+
try:
|
|
170
|
+
result = check_version()
|
|
171
|
+
callback(result)
|
|
172
|
+
except Exception:
|
|
173
|
+
# Silent failure - call callback with "latest" result
|
|
174
|
+
callback(VersionCheckResult(is_latest=True, current_version="unknown"))
|
|
175
|
+
|
|
176
|
+
thread = threading.Thread(target=_check, daemon=True)
|
|
177
|
+
thread.start()
|
|
178
|
+
return thread
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: holmesgpt
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.1
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Natan Yellin
|
|
6
6
|
Author-email: natan@robusta.dev
|
|
@@ -28,7 +28,7 @@ Requires-Dist: google-api-python-client (>=2.156.0,<3.0.0)
|
|
|
28
28
|
Requires-Dist: humanize (>=4.9.0,<5.0.0)
|
|
29
29
|
Requires-Dist: jinja2 (>=3.1.2,<4.0.0)
|
|
30
30
|
Requires-Dist: kubernetes (>=32.0.1,<33.0.0)
|
|
31
|
-
Requires-Dist: litellm (==1.
|
|
31
|
+
Requires-Dist: litellm (==1.74.7)
|
|
32
32
|
Requires-Dist: markdown (>=3.6,<4.0)
|
|
33
33
|
Requires-Dist: markdownify (>=1.1.0,<2.0.0)
|
|
34
34
|
Requires-Dist: mcp (==v1.9.0)
|
|
@@ -40,6 +40,7 @@ Requires-Dist: pydantic (>=2.7,<3.0)
|
|
|
40
40
|
Requires-Dist: pydantic-settings (>=2.1.0,<3.0.0)
|
|
41
41
|
Requires-Dist: pydash (>=8.0.1,<9.0.0)
|
|
42
42
|
Requires-Dist: pyodbc (>=5.0.1,<6.0.0)
|
|
43
|
+
Requires-Dist: pytest-shared-session-scope (>=0.4.0,<0.5.0)
|
|
43
44
|
Requires-Dist: python-benedict (>=0.33.1,<0.34.0)
|
|
44
45
|
Requires-Dist: python_multipart (>=0.0.18,<0.0.19)
|
|
45
46
|
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
holmes/.git_archival.json,sha256=PbwdO7rNhEJ4ALiO12DPPb81xNAIsVxCA0m8OrVoqsk,182
|
|
2
|
-
holmes/__init__.py,sha256=
|
|
3
|
-
holmes/clients/robusta_client.py,sha256=
|
|
4
|
-
holmes/common/env_vars.py,sha256=
|
|
5
|
-
holmes/
|
|
2
|
+
holmes/__init__.py,sha256=XpZCSjCRuY95_DFurWgff6-iC_hubbC2uvMgUSid0Zg,257
|
|
3
|
+
holmes/clients/robusta_client.py,sha256=u1ZvPBE7VaNVrPdtiTLDjI3Xrx6TWTnOWeIlky_aCHg,672
|
|
4
|
+
holmes/common/env_vars.py,sha256=6Pi3v9cumKKCnEoeJT5fGgmzzerM5oV0izHnM-nPsBA,1963
|
|
5
|
+
holmes/common/openshift.py,sha256=akbQ0GpnmuzXOqTcotpTDQSDKIROypS9mgPOprUgkCw,407
|
|
6
|
+
holmes/config.py,sha256=WblVSBedeDeG_xl-SkPGkxTUgdw4vXz2mOJg08oQQpU,20266
|
|
6
7
|
holmes/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
8
|
holmes/core/conversations.py,sha256=LXT3T-5hwl4xHXBhO4XyOKm6k9w58anQ3dw4F2aptqs,20769
|
|
8
9
|
holmes/core/investigation.py,sha256=nSVkCfeliZjQT2PrgNPD3o1EwKe9je0Pq3F2bDNQiCU,5646
|
|
9
10
|
holmes/core/investigation_structured_output.py,sha256=f9MDfhaI5OfaZ4J_UKqMFhWncoODuo6CBNMNWbdIkvE,9991
|
|
10
11
|
holmes/core/issue.py,sha256=dbctGv8KHAXC1SeOMkEP-BudJ50u7kA8jLN5FN_d808,2426
|
|
11
|
-
holmes/core/llm.py,sha256=
|
|
12
|
+
holmes/core/llm.py,sha256=P81ZlwDSzK4B1uIMAtJuchQdHUfh088KDz0Yvr-jHk4,10761
|
|
12
13
|
holmes/core/models.py,sha256=Bfo-HxC4SjW1Y60fjwn8AAq2zyrTfM61x6OsWartmU8,5693
|
|
13
14
|
holmes/core/openai_formatting.py,sha256=T5GguKhYiJbHx7mFTyJZZReV-s9LBX443BD_nJQZR2s,1677
|
|
14
15
|
holmes/core/performance_timing.py,sha256=MTbTiiX2jjPmW7PuNA2eYON40eWsHPryR1ap_KlwZ_E,2217
|
|
@@ -16,16 +17,16 @@ holmes/core/prompt.py,sha256=pc2qoCw0xeJDjGwG0DHOtEUvKsnUAtR6API10ThdlkU,1244
|
|
|
16
17
|
holmes/core/resource_instruction.py,sha256=rduue_t8iQi1jbWc3-k3jX867W1Fvc6Tah5uOJk35Mc,483
|
|
17
18
|
holmes/core/runbooks.py,sha256=Oj5ICmiGgaq57t4erPzQDvHQ0rMGj1nhiiYhl8peH3Q,939
|
|
18
19
|
holmes/core/safeguards.py,sha256=SAw-J9y3uAehJVZJYsFs4C62jzLV4p_C07F2jUuJHug,4895
|
|
19
|
-
holmes/core/supabase_dal.py,sha256=
|
|
20
|
-
holmes/core/tool_calling_llm.py,sha256=
|
|
21
|
-
holmes/core/tools.py,sha256=
|
|
20
|
+
holmes/core/supabase_dal.py,sha256=76QjQcQKlZb8Mr9RCfXq5OJOfkVgm1m6dn-Gtux_J24,20231
|
|
21
|
+
holmes/core/tool_calling_llm.py,sha256=SakvJ2nGgZquFMFkT66Iv0Kg3FnvsLxYTc3JnEGc6LA,34930
|
|
22
|
+
holmes/core/tools.py,sha256=RU9d1onms_1M3-knZQN9HTOrJCB15xhfn5_kRG22Fr4,20280
|
|
22
23
|
holmes/core/tools_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
24
|
holmes/core/tools_utils/tool_executor.py,sha256=ZGrzn8c8RelQa_t6ZR9siWBBzOCQ1fgKhug4JDqqgUM,2100
|
|
24
25
|
holmes/core/tools_utils/toolset_utils.py,sha256=1r7nlET4e7CjzMl9MUc_pYOTtRU7YSL8AKp6fQF3_3o,2217
|
|
25
|
-
holmes/core/toolset_manager.py,sha256=
|
|
26
|
-
holmes/core/tracing.py,sha256=
|
|
27
|
-
holmes/interactive.py,sha256=
|
|
28
|
-
holmes/main.py,sha256=
|
|
26
|
+
holmes/core/toolset_manager.py,sha256=xc9-tv5jt5f-8qgDCGD4tn_mYcDHvX65UxIcnZfUGME,18171
|
|
27
|
+
holmes/core/tracing.py,sha256=PTWjonUIfZLINeLzZgPmKRYdwYwINZopLXnco-cwpgU,7088
|
|
28
|
+
holmes/interactive.py,sha256=g4CLH8lr2e5n_VSRfU5v-wzy0g0Vn7uIRXuQJ9GvG_8,36355
|
|
29
|
+
holmes/main.py,sha256=DbDMrI3BDtcMT7E1n3tll3-U8xW4ZuAllBjbHhyR0Uw,34888
|
|
29
30
|
holmes/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
31
|
holmes/plugins/destinations/__init__.py,sha256=vMYwTfA5nQ05us5Rzbaoe0R5C8Navo6ENVZhojtACTk,98
|
|
31
32
|
holmes/plugins/destinations/slack/__init__.py,sha256=HVoDdTbdJJ1amXt12ZSMVcn3E04rcOrqk6BgNwvMbWY,56
|
|
@@ -151,7 +152,7 @@ holmes/plugins/toolsets/opensearch/opensearch_logs.py,sha256=TbBzLv7we91pTGqmsM1
|
|
|
151
152
|
holmes/plugins/toolsets/opensearch/opensearch_traces.py,sha256=gXV2yXrAn0Tu3r5GMiSdsLAKx9myUrHWD0U-OYBXN0g,8497
|
|
152
153
|
holmes/plugins/toolsets/opensearch/opensearch_traces_instructions.jinja2,sha256=Xn8AW4XCMYV1VkBbF8nNB9fUpKQ1Vbm88iFczj-LQXo,1035
|
|
153
154
|
holmes/plugins/toolsets/opensearch/opensearch_utils.py,sha256=mh9Wp22tOdJYmA9IaFS7tD3aEENljyeuPOsF-lEe5C0,5097
|
|
154
|
-
holmes/plugins/toolsets/prometheus/prometheus.py,sha256=
|
|
155
|
+
holmes/plugins/toolsets/prometheus/prometheus.py,sha256=H8YWHj1Q2C8SqabNYQdyoTGe0kZlEarELDQcSVmSkE0,31795
|
|
155
156
|
holmes/plugins/toolsets/prometheus/prometheus_instructions.jinja2,sha256=hIR8Uo9QNVgsUdY94NVNKwpQvJiuGpkECGw8Eu-oVuY,2856
|
|
156
157
|
holmes/plugins/toolsets/rabbitmq/api.py,sha256=-BtqF7hQWtl_OamnQ521vYHhR8E2n2wcPNYxfI9r4kQ,14307
|
|
157
158
|
holmes/plugins/toolsets/rabbitmq/rabbitmq_instructions.jinja2,sha256=qetmtJUMkx9LIihr2fSJ2EV9h2J-b-ZdUAvMtopXZYY,3105
|
|
@@ -172,7 +173,7 @@ holmes/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
172
173
|
holmes/utils/cache.py,sha256=aPc7zTdpBQ3JQR7ET4wvIwzXhx2PpPKiBBSTgbVNXlY,2219
|
|
173
174
|
holmes/utils/cert_utils.py,sha256=5YAUOY3LjFqqFpYHnHLvSc70LCxEWf0spw1vZwLLvOw,1193
|
|
174
175
|
holmes/utils/console/consts.py,sha256=klHl0_iXcw_mqtv-YUWBzx3oxi0maaHok_Eq_7ZZdb8,257
|
|
175
|
-
holmes/utils/console/logging.py,sha256=
|
|
176
|
+
holmes/utils/console/logging.py,sha256=jnNWqHIJRb6mCOXN24YSi1w_oMxUcOkkXsZb42daFU0,3072
|
|
176
177
|
holmes/utils/console/result.py,sha256=-n9QtaJtgagIYXu9XYF6foQ6poiCUcYZbK0CWbK9cJw,1334
|
|
177
178
|
holmes/utils/default_toolset_installation_guide.jinja2,sha256=HEf7tX75HE3H4-YeLbJfa0WbiLEsI71usKrXHCO_sHo,992
|
|
178
179
|
holmes/utils/definitions.py,sha256=WKVDFh1wfuo0UCV_1jXFjgP0gjGM3-U-UdxdVxmXaKM,287
|
|
@@ -185,8 +186,9 @@ holmes/utils/markdown_utils.py,sha256=_yDc_IRB5zkj9THUlZ6nzir44VfirTjPccC_DrFrBk
|
|
|
185
186
|
holmes/utils/pydantic_utils.py,sha256=g0e0jLTa8Je8JKrhEP4N5sMxj0_hhPOqFZr0Vpd67sg,1649
|
|
186
187
|
holmes/utils/robusta.py,sha256=4FZKv5DhDnvINuMlbyFRWCYdR4p7Pj4tyYIUkq1vHUU,363
|
|
187
188
|
holmes/utils/tags.py,sha256=SU4EZMBtLlIb7OlHsSpguFaypczRzOcuHYxDSanV3sQ,3364
|
|
188
|
-
|
|
189
|
-
holmesgpt-0.12.
|
|
190
|
-
holmesgpt-0.12.
|
|
191
|
-
holmesgpt-0.12.
|
|
192
|
-
holmesgpt-0.12.
|
|
189
|
+
holmes/version.py,sha256=g_ytiKxYSKlQqYwYDMYBjDWprAc9ZyS2sLrfPb3XDkg,5217
|
|
190
|
+
holmesgpt-0.12.1.dist-info/LICENSE.txt,sha256=RdZMj8VXRQdVslr6PMYMbAEu5pOjOdjDqt3yAmWb9Ds,1072
|
|
191
|
+
holmesgpt-0.12.1.dist-info/METADATA,sha256=Oc42oZKE01SRf6qf2aPHXGqZqoevax1XWy3eht3Z45U,21701
|
|
192
|
+
holmesgpt-0.12.1.dist-info/WHEEL,sha256=kLuE8m1WYU0Ig0_YEGrXyTtiJvKPpLpDEiChiNyei5Y,88
|
|
193
|
+
holmesgpt-0.12.1.dist-info/entry_points.txt,sha256=JdzEyZhpaYr7Boo4uy4UZgzY1VsAEbzMgGmHZtx9KFY,42
|
|
194
|
+
holmesgpt-0.12.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|