Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions holmes/plugins/toolsets/prometheus/prometheus.py
Original file line number Diff line number Diff line change
Expand Up @@ -1611,7 +1611,7 @@ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolRes
# Get timeout parameter and enforce limits
default_timeout = self.toolset.config.query_timeout_seconds_default
max_timeout = self.toolset.config.query_timeout_seconds_hard_max
timeout = params.get("timeout", default_timeout)
timeout = params.get("timeout") or default_timeout
if timeout > max_timeout:
timeout = max_timeout
logging.warning(
Expand Down Expand Up @@ -1865,7 +1865,7 @@ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolRes
# Get timeout parameter and enforce limits
default_timeout = self.toolset.config.query_timeout_seconds_default
max_timeout = self.toolset.config.query_timeout_seconds_hard_max
timeout = params.get("timeout", default_timeout)
timeout = params.get("timeout") or default_timeout
if timeout > max_timeout:
timeout = max_timeout
logging.warning(
Expand Down
75 changes: 75 additions & 0 deletions tests/plugins/toolsets/test_prometheus_unit.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import logging
from unittest.mock import MagicMock

import pytest

from holmes.plugins.toolsets.prometheus.prometheus import (
DEFAULT_QUERY_TIMEOUT_SECONDS,
AzurePrometheusConfig,
ExecuteInstantQuery,
ExecuteRangeQuery,
PrometheusConfig,
PrometheusToolset,
adjust_step_for_max_points,
Expand Down Expand Up @@ -329,3 +333,74 @@ def test_determine_prometheus_class_with_partial_azure_env(
)
assert cls is PrometheusConfig
assert "Partial Azure" in caplog.text


class TestNullTimeout:
"""Regression: explicit null timeout from the LLM must not raise TypeError."""

def _make_toolset(self) -> PrometheusToolset:
toolset = PrometheusToolset()
toolset.config = PrometheusConfig(
prometheus_url="http://prometheus.example:9090"
)
return toolset

def _fake_response(self):
resp = MagicMock()
resp.status_code = 200
resp.json.return_value = {
"status": "success",
"data": {"resultType": "vector", "result": []},
}
return resp

def test_instant_query_null_timeout_falls_back_to_default(self, monkeypatch):
toolset = self._make_toolset()
tool = ExecuteInstantQuery(toolset)

captured: dict = {}

def fake_do_request(*args, **kwargs):
captured["timeout"] = kwargs.get("timeout")
return self._fake_response()

monkeypatch.setattr(
"holmes.plugins.toolsets.prometheus.prometheus.do_request",
fake_do_request,
)

result = tool._invoke(
{"query": "up", "description": "test", "timeout": None},
context=MagicMock(),
)

assert "timeout" in captured
assert captured["timeout"] == DEFAULT_QUERY_TIMEOUT_SECONDS

def test_range_query_null_timeout_falls_back_to_default(self, monkeypatch):
toolset = self._make_toolset()
tool = ExecuteRangeQuery(toolset)

captured: dict = {}

def fake_do_request(*args, **kwargs):
captured["timeout"] = kwargs.get("timeout")
return self._fake_response()

monkeypatch.setattr(
"holmes.plugins.toolsets.prometheus.prometheus.do_request",
fake_do_request,
)

result = tool._invoke(
{
"query": "up",
"description": "test",
"output_type": "Plain",
"timeout": None,
},
context=MagicMock(),
)

assert "timeout" in captured
assert captured["timeout"] == DEFAULT_QUERY_TIMEOUT_SECONDS