Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Added tool timeout for when it takes too long to run pre-check #874

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
pavangudiwada wants to merge 10 commits into master
base: master
Choose a base branch
Loading
from add-toolcheck-timeout

Conversation

Copy link
Contributor

@pavangudiwada pavangudiwada commented Aug 19, 2025

Helps in cases like #873

Copy link
Contributor

coderabbitai bot commented Aug 19, 2025
edited
Loading

Walkthrough

Adds a 60-second timeout to subprocess.run in ToolsetCommandPrerequisite, includes stdout/stderr in CalledProcessError diagnostics when present, and handles subprocess.TimeoutExpired by marking the prerequisite failed and reporting partial outputs with a timeout notice.

Changes

Cohort / File(s) Summary
Prerequisite execution and diagnostics
holmes/core/tools.py
Add 60s timeout to ToolsetCommandPrerequisite subprocess.run; include stdout/stderr in CalledProcessError diagnostics; handle subprocess.TimeoutExpired to report partial outputs and a 60s timeout failure.

Sequence Diagram(s)

sequenceDiagram
 autonumber
 participant Caller
 participant Prereq as ToolsetCommandPrerequisite
 participant Sub as Subprocess
 Caller->>Prereq: run()
 Prereq->>Sub: execute command (timeout=60s)
 alt Success (exit 0)
 Sub-->>Prereq: exit 0 + stdout/stderr
 Prereq-->>Caller: success
 else Non-zero exit (CalledProcessError)
 Sub-->>Prereq: non-zero exit + stdout/stderr
 Note right of Prereq #f9f0c1: include return code, stdout, stderr in error message
 Prereq-->>Caller: failure with diagnostics
 else TimeoutExpired
 Sub-->>Prereq: timeout + partial stdout/stderr
 Note right of Prereq #fdecea: report 60s timeout and partial outputs
 Prereq-->>Caller: failure with timeout notice
 end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly summarizes the primary change: adding a timeout when running a tool pre-check. This directly matches the changes in holmes/core/tools.py which add a 60-second timeout and new handling for subprocess.TimeoutExpired and subprocess.CalledProcessError output. The phrasing is specific and concise, so a teammate scanning the PR history will understand the main intent.
Description Check ✅ Passed The description "Helps in cases like #873" is on-topic because the PR explicitly targets issue #873 by adding a timeout for tool pre-checks; the raw summary confirms the 60-second timeout and TimeoutExpired handling. Although brief, it relates to the changes and therefore passes this lenient check. For reviewer clarity the description could be expanded to state the timeout length and the expected behavior when a subprocess times out or fails.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-toolcheck-timeout

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
 pre_merge_checks:
 custom_checks:
 - name: "Undocumented Breaking Changes"
 mode: "warning"
 instructions: |
 Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
holmes/core/tools.py (1)

228-231: Fix __invoke_script return type and remove unnecessary type: ignore

__invoke_script returns (output, return_code, rendered_script) but is annotated as -> str, which contradicts the actual return and forces # type: ignore at the call-site. This will trip mypy against the project’s typing guidelines.

- raw_output, return_code, invocation = self.__invoke_script(params) # type: ignore
+ raw_output, return_code, invocation = self.__invoke_script(params)
-def __invoke_script(self, params) -> str:
+def __invoke_script(self, params) -> Tuple[str, int, str]:
@@
- return output, return_code, rendered_script # type: ignore
+ return output, return_code, rendered_script

Also applies to: 282-300

🧹 Nitpick comments (3)
holmes/core/tools.py (3)

432-433: Avoid magic-number timeout; centralize it and align the timeout message

Nice addition. To prevent drift between the timeout argument and the error message (and to make it configurable), single-source the timeout via a module-level constant. While here, prefer showing the fully interpolated command in the timeout error for easier repro, and truncate very large partial outputs to keep status logs readable.

Apply this diff:

- timeout=60,
+ timeout=PREREQUISITE_TIMEOUT_SECONDS,
...
- except subprocess.TimeoutExpired as e:
+ except subprocess.TimeoutExpired as e:
 self.status = ToolsetStatusEnum.FAILED
- output_info = (
- f"\nPartial stdout: {e.stdout}\nPartial stderr: {e.stderr}"
- if e.stdout or e.stderr
- else ""
- )
- self.error = (
- f"`{prereq.command}` timed out after 60 seconds{output_info}"
- )
+ stdout = (e.stdout or "")
+ stderr = (e.stderr or "")
+ max_len = 10_000
+ if len(stdout) > max_len or len(stderr) > max_len:
+ stdout = stdout[:max_len] + "... [truncated]"
+ stderr = stderr[:max_len] + "... [truncated]"
+ output_info = f"\nPartial stdout: {stdout}\nPartial stderr: {stderr}"
+ self.error = (
+ f"`{command}` timed out after {PREREQUISITE_TIMEOUT_SECONDS} seconds{output_info}"
+ )

Add this near the imports to define a single source of truth (optionally configurable via env):

# at module top
PREREQUISITE_TIMEOUT_SECONDS = int(os.getenv("HOLMES_PREREQ_TIMEOUT_SECONDS", "60"))

Also applies to: 450-459


442-449: Great diagnostics; prefer interpolated command and truncate outputs to avoid log bloat

Including stdout/stderr is helpful. Two small improvements:

  • Use the interpolated command (command) rather than the template (prereq.command) in the error for easier repro.
  • Truncate very large outputs to avoid flooding the status/error UI.
- output_info = (
- f"\nStdout: {e.stdout}\nStderr: {e.stderr}"
- if e.stdout or e.stderr
- else ""
- )
- self.error = (
- f"`{prereq.command}` returned {e.returncode}{output_info}"
- )
+ stdout = (e.stdout or "")
+ stderr = (e.stderr or "")
+ max_len = 10_000
+ if len(stdout) > max_len or len(stderr) > max_len:
+ stdout = stdout[:max_len] + "... [truncated]"
+ stderr = stderr[:max_len] + "... [truncated]"
+ output_info = f"\nStdout: {stdout}\nStderr: {stderr}"
+ self.error = (
+ f"`{command}` returned {e.returncode}{output_info}"
+ )

474-476: Ensure config type aligns with the CallablePrerequisite contract

Defaulting None to {} is good. To avoid runtime surprises when self.config is set to a non-dict (its type is Optional[Any]), guard the type before passing it to the callable which expects dict[str, Any].

- config = self.config if self.config is not None else {}
- (enabled, error_message) = prereq.callable(config)
+ cfg = self.config
+ config: dict[str, Any] = cfg if isinstance(cfg, dict) else {}
+ if cfg is not None and not isinstance(cfg, dict):
+ logging.debug(
+ "CallablePrerequisite expected dict config; got %s",
+ type(cfg).__name__,
+ )
+ (enabled, error_message) = prereq.callable(config)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 696287f and 1e00c0a.

📒 Files selected for processing (1)
  • holmes/core/tools.py (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.py: ALWAYS place Python imports at the top of the file, not inside functions or methods
Type hints are required (project is type-checked with mypy)
Use Ruff for formatting and linting (configured in pyproject.toml)

Files:

  • holmes/core/tools.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: llm_evals

@aantn aantn requested review from moshemorad and removed request for aantn August 20, 2025 06:31
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
holmes/core/tools.py (5)

442-449: Include the expanded command in error messages for better diagnosability.

When a check fails, showing the post-interpolation command (command) is more actionable than the original template (prereq.command).

- self.error = (
- f"`{prereq.command}` returned {e.returncode}{output_info}"
- )
+ self.error = (
+ f"`{command}` returned {e.returncode}{output_info}"
+ )

450-459: Reuse the computed timeout and show the expanded command in timeout errors.

This keeps messages consistent and accurate if the timeout is made configurable.

- self.error = (
- f"`{prereq.command}` timed out after 60 seconds{output_info}"
- )
+ self.error = (
+ f"`{command}` timed out after {prereq_timeout} seconds{output_info}"
+ )

425-433: Optional: ensure child processes are terminated on timeout.

shell=True may spawn a shell that then spawns children; the default subprocess.run kill on timeout targets only the shell process. If a prerequisite command starts grandchildren, consider starting a new session and killing the process group on timeout. This requires switching from subprocess.run to Popen + communicate and calling os.killpg on TimeoutExpired.

Happy to provide a concrete refactor if needed.


425-433: Make subprocess timeout configurable and disable stdin prompts

Nice work adding a timeout to the subprocess invocation. To avoid a magic constant and prevent commands from blocking on stdin prompts, consider these refinements:

• In holmes/core/tools.py (around the subprocess.run call):

- result = subprocess.run(
+ # Determine timeout: use per-prerequisite override or fall back to module default
+ prereq_timeout = getattr(prereq, "timeout_seconds", None) or DEFAULT_PREREQ_TIMEOUT_S
+ result = subprocess.run(
 command,
 shell=True,
 check=True,
 text=True,
+ stdin=subprocess.DEVNULL,
 stdout=subprocess.PIPE,
 stderr=subprocess.PIPE,
- timeout=60,
+ timeout=prereq_timeout,
 )

• At the top of holmes/core/tools.py, add a module-level default:

DEFAULT_PREREQ_TIMEOUT_S: int = 60

• In the ToolsetCommandPrerequisite model (around line 333), add an optional override field:

class ToolsetCommandPrerequisite(BaseModel):
 command: str
 expected_output: Optional[str] = None
 timeout_seconds: Optional[int] = Field(
 default=None,
 ge=1,
 description="Override the default command pre-check timeout (seconds)."
 )

All existing instantiations of ToolsetCommandPrerequisite (in code and tests) use keyword args for command/expected_output and will continue to work without changes.


442-459: Cap and Sanitize Subprocess Error Output

It’s easy for e.stdout/e.stderr to become very large or leak sensitive data; I recommend truncating and sanitizing before assigning to self.error:

• Add a module-level constant and helper in holmes/core/tools.py:

MAX_ERROR_OUTPUT_CHARS: int = 4096
def _truncate_text(s: Optional[str], max_chars: int = MAX_ERROR_OUTPUT_CHARS) -> str:
 if not s:
 return ""
 return s if len(s) <= max_chars else s[:max_chars] + "... [truncated]"

• In both exception handlers (CalledProcessError and TimeoutExpired), build output_info with truncated stdout/stderr:

- output_info = (
- f"\nStdout: {e.stdout}\nStderr: {e.stderr}"
- if e.stdout or e.stderr
- else ""
- )
+ out = _truncate_text(e.stdout)
+ err = _truncate_text(e.stderr)
+ output_info = ""
+ if out:
+ output_info += f"\nStdout: {out}"
+ if err:
+ output_info += f"\nStderr: {err}"

• Sanitize the final error string via your toolset’s sanitizer (e.g. the existing _sanitize_error in the Git toolset) before storing:

- self.error = (
- f"`{prereq.command}` returned {e.returncode}{output_info}"
- )
+ raw = f"`{prereq.command}` returned {e.returncode}{output_info}"
+ self.error = self.toolset._sanitize_error(raw)

• Repeat the same pattern in the TimeoutExpired block.

This will (1) limit log/UI spam, (2) reduce risk of leaking tokens or PII, and (3) ensure you don’t accidentally expose sensitive data in error messages.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1e00c0a and 8c6b16a.

📒 Files selected for processing (1)
  • holmes/core/tools.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: ALWAYS place Python imports at the top of the file, not inside functions or methods
Type hints are required (project is type-checked with mypy)
Use Ruff for formatting and linting (configured in pyproject.toml)

Files:

  • holmes/core/tools.py
🧠 Learnings (1)
📚 Learning: 2025年07月08日T08:45:41.069Z
Learnt from: nherment
PR: robusta-dev/holmesgpt#610
File: .github/workflows/llm-evaluation.yaml:39-42
Timestamp: 2025年07月08日T08:45:41.069Z
Learning: When suggesting improvements to environment variable handling in robusta-dev/holmesgpt, check first if validation logic already exists rather than reimplementing it.

Applied to files:

  • holmes/core/tools.py
🧬 Code graph analysis (1)
holmes/core/tools.py (1)
holmes/plugins/toolsets/git.py (1)
  • error (406-411)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: llm_evals
  • GitHub Check: Pre-commit checks
  • GitHub Check: Pre-commit checks

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
holmes/core/tools.py (3)

441-449: Make timeout configurable and prevent stdin hangs

Good addition. Recommend making the timeout configurable per prerequisite and closing stdin to avoid interactive blocks.

Apply within this hunk:

 result = subprocess.run(
 command,
 shell=True,
 check=True,
 text=True,
+ stdin=subprocess.DEVNULL,
 stdout=subprocess.PIPE,
 stderr=subprocess.PIPE,
- timeout=60,
+ timeout=getattr(prereq, "timeout_seconds", 60),
 )

Add a field to ToolsetCommandPrerequisite (outside this hunk) to keep strong typing and mypy happy:

class ToolsetCommandPrerequisite(BaseModel):
 command: str # must complete successfully (error code 0) for prereq to be satisfied
 expected_output: Optional[str] = None # optional
 timeout_seconds: int = 60 # seconds

458-465: Harden error message formatting and avoid "None" leakage; prefer interpolated command

Avoid printing "None" and cap output size to keep errors readable. Also show the interpolated command.

- except subprocess.CalledProcessError as e:
- self.status = ToolsetStatusEnum.FAILED
- output_info = (
- f"\nStdout: {e.stdout}\nStderr: {e.stderr}"
- if e.stdout or e.stderr
- else ""
- )
- self.error = (
- f"`{prereq.command}` returned {e.returncode}{output_info}"
- )
+ except subprocess.CalledProcessError as e:
+ self.status = ToolsetStatusEnum.FAILED
+ def _trim(s: str) -> str:
+ return s if len(s) <= 10000 else s[:10000] + "... [truncated]"
+ output_info = ""
+ if e.stdout:
+ output_info += f"\nStdout:\n{_trim(e.stdout)}"
+ if e.stderr:
+ output_info += f"\nStderr:\n{_trim(e.stderr)}"
+ self.error = (
+ f"`{command}` returned {e.returncode}{output_info}"
+ )

466-475: Timeout path: use dynamic timeout value, avoid "None", cap output, and show interpolated command

Make the message reflect the actual timeout and keep partial outputs tidy.

- except subprocess.TimeoutExpired as e:
- self.status = ToolsetStatusEnum.FAILED
- output_info = (
- f"\nPartial stdout: {e.stdout}\nPartial stderr: {e.stderr}"
- if e.stdout or e.stderr
- else ""
- )
- self.error = (
- f"`{prereq.command}` timed out after 60 seconds{output_info}"
- )
+ except subprocess.TimeoutExpired as e:
+ self.status = ToolsetStatusEnum.FAILED
+ def _trim(s: str) -> str:
+ return s if len(s) <= 10000 else s[:10000] + "... [truncated]"
+ output_info = ""
+ if e.stdout:
+ output_info += f"\nPartial stdout:\n{_trim(e.stdout)}"
+ if e.stderr:
+ output_info += f"\nPartial stderr:\n{_trim(e.stderr)}"
+ timeout_s = getattr(prereq, "timeout_seconds", 60)
+ self.error = (
+ f"`{command}` timed out after {timeout_s} seconds{output_info}"
+ )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8c6b16a and 53d667b.

📒 Files selected for processing (1)
  • holmes/core/tools.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always place Python imports at the top of the file, not inside functions or methods
Type hints are required (mypy is configured in pyproject.toml)

Files:

  • holmes/core/tools.py
🧠 Learnings (1)
📚 Learning: 2025年07月08日T08:45:41.069Z
Learnt from: nherment
PR: robusta-dev/holmesgpt#610
File: .github/workflows/llm-evaluation.yaml:39-42
Timestamp: 2025年07月08日T08:45:41.069Z
Learning: When suggesting improvements to environment variable handling in robusta-dev/holmesgpt, check first if validation logic already exists rather than reimplementing it.

Applied to files:

  • holmes/core/tools.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Pre-commit checks
  • GitHub Check: llm_evals
  • GitHub Check: Pre-commit checks

Copy link
Contributor

github-actions bot commented Sep 4, 2025

Results of HolmesGPT evals

  • ask_holmes: 33/37 test cases were successful, 0 regressions, 2 skipped, 1 setup failures
Test suite Test case Status
ask 01_how_many_pods
ask 02_what_is_wrong_with_pod
ask 04_related_k8s_events ↪️
ask 05_image_version
ask 09_crashpod
ask 10_image_pull_backoff
ask 110_k8s_events_image_pull
ask 11_init_containers
ask 13a_pending_node_selector_basic
ask 14_pending_resources
ask 15_failed_readiness_probe
ask 17_oom_kill
ask 18_crash_looping_v2
ask 19_detect_missing_app_details
ask 20_long_log_file_search
ask 24_misconfigured_pvc
ask 24a_misconfigured_pvc_basic
ask 28_permissions_error 🚧
ask 29_events_from_alert_manager ↪️
ask 39_failed_toolset
ask 41_setup_argo
ask 42_dns_issues_steps_new_tools ⚠️
ask 43_current_datetime_from_prompt
ask 45_fetch_deployment_logs_simple
ask 51_logs_summarize_errors
ask 53_logs_find_term
ask 54_not_truncated_when_getting_pods
ask 59_label_based_counting
ask 60_count_less_than
ask 61_exact_match_counting
ask 63_fetch_error_logs_no_errors
ask 79_configmap_mount_issue
ask 83_secret_not_found
ask 86_configmap_like_but_secret
ask 93_calling_datadog[0]
ask 93_calling_datadog[1]
ask 93_calling_datadog[2]

Legend

  • ✅ the test was successful
  • ↪️ the test was skipped
  • ⚠️ the test failed but is known to be flaky or known to fail
  • 🚧 the test had a setup failure (not a code regression)
  • 🔧 the test failed due to mock data issues (not a code regression)
  • ❌ the test failed and should be fixed before merging the PR

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
holmes/core/tools.py (2)

671-679: Make timeout configurable and prevent interactive hangs.

Use a per-prereq timeout and close stdin so checks can’t block on prompts.

- result = subprocess.run(
+ timeout_secs = getattr(prereq, "timeout_seconds", 60)
+ result = subprocess.run(
 command,
 shell=True,
 check=True,
 text=True,
+ stdin=subprocess.DEVNULL,
 stdout=subprocess.PIPE,
 stderr=subprocess.PIPE,
- timeout=60,
+ timeout=timeout_secs,
 )

Add the field to the model (outside this hunk):

 class ToolsetCommandPrerequisite(BaseModel):
- command: str # must complete successfully (error code 0) for prereq to be satisfied
- expected_output: Optional[str] = None # optional
+ command: str # must complete successfully (error code 0) for prereq to be satisfied
+ expected_output: Optional[str] = None # optional
+ timeout_seconds: Optional[int] = Field(
+ default=60, description="Timeout for the prerequisite command"
+ )

688-695: Use the interpolated command in error messages.

This makes diagnostics clearer than showing the unexpanded template.

- self.error = (
- f"`{prereq.command}` returned {e.returncode}{output_info}"
- )
+ self.error = (
+ f"`{command}` returned {e.returncode}{output_info}"
+ )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 53d667b and f376fcb.

📒 Files selected for processing (1)
  • holmes/core/tools.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always place Python imports at the top of the file, not inside functions or methods
Type hints are required (mypy is configured in pyproject.toml)

Files:

  • holmes/core/tools.py
🧠 Learnings (1)
📚 Learning: 2025年07月08日T08:45:41.069Z
Learnt from: nherment
PR: robusta-dev/holmesgpt#610
File: .github/workflows/llm-evaluation.yaml:39-42
Timestamp: 2025年07月08日T08:45:41.069Z
Learning: When suggesting improvements to environment variable handling in robusta-dev/holmesgpt, check first if validation logic already exists rather than reimplementing it.

Applied to files:

  • holmes/core/tools.py
🧬 Code graph analysis (1)
holmes/core/tools.py (2)
holmes/plugins/toolsets/newrelic.py (2)
  • error (50-55)
  • error (130-135)
holmes/plugins/toolsets/git.py (1)
  • error (414-419)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: llm_evals
  • GitHub Check: Pre-commit checks

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
holmes/core/tools.py (1)

701-710: TimeoutExpired bug: use e.output (not e.stdout) and print the actual timeout; include e.cmd.

Using e.stdout here will raise AttributeError and mask the real timeout failure. Also avoid hard-coding "60 seconds".

- except subprocess.TimeoutExpired as e:
- self.status = ToolsetStatusEnum.FAILED
- output_info = (
- f"\nPartial stdout: {e.stdout}\nPartial stderr: {e.stderr}"
- if e.stdout or e.stderr
- else ""
- )
- self.error = (
- f"`{prereq.command}` timed out after 60 seconds{output_info}"
- )
+ except subprocess.TimeoutExpired as e:
+ self.status = ToolsetStatusEnum.FAILED
+ # TimeoutExpired exposes .output for captured stdout
+ partial_stdout = getattr(e, "output", None)
+ partial_stderr = e.stderr
+ output_info = (
+ f"\nPartial stdout: {partial_stdout}\nPartial stderr: {partial_stderr}"
+ if partial_stdout or partial_stderr
+ else ""
+ )
+ cmd = getattr(e, "cmd", command)
+ self.error = f"`{cmd}` timed out after {secs} seconds{output_info}"
#!/bin/bash
# Verify there are no other TimeoutExpired handlers using e.stdout
rg -nP 'except\s+subprocess\.TimeoutExpired.*\n(?s).*e\.stdout' -C2
🧹 Nitpick comments (2)
holmes/core/tools.py (2)

676-684: Avoid hard-coded 60s; make timeout configurable and reuse the value in errors.

Expose a per-prereq timeout and pass it to subprocess.run. This also lets you print the actual value in the TimeoutExpired message.

Apply within this block:

- result = subprocess.run(
+ secs = getattr(prereq, "timeout_seconds", DEFAULT_PREREQ_TIMEOUT)
+ result = subprocess.run(
 command,
 shell=True,
 check=True,
 text=True,
 stdout=subprocess.PIPE,
 stderr=subprocess.PIPE,
- timeout=60,
+ timeout=secs,
 )

Additions outside this block:

+DEFAULT_PREREQ_TIMEOUT: int = 60 # default prereq timeout (seconds)

And extend the model:

 class ToolsetCommandPrerequisite(BaseModel):
 command: str # must complete successfully (error code 0) for prereq to be satisfied
 expected_output: Optional[str] = None # optional
+ timeout_seconds: Optional[int] = Field(
+ default=None, gt=0, description="Max seconds to wait before failing the prereq"
+ )

691-700: Use the executed command from the exception (e.cmd) instead of prereq.command.

Improves accuracy when env vars expand or templates modify the command. Keep current stdout/stderr inclusion.

 except subprocess.CalledProcessError as e:
 self.status = ToolsetStatusEnum.FAILED
- output_info = (
+ output_info = (
 f"\nStdout: {e.stdout}\nStderr: {e.stderr}"
 if e.stdout or e.stderr
 else ""
 )
- self.error = (
- f"`{prereq.command}` returned {e.returncode}{output_info}"
- )
+ cmd = getattr(e, "cmd", command)
+ self.error = f"`{cmd}` returned {e.returncode}{output_info}"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f376fcb and 3dd6f93.

📒 Files selected for processing (1)
  • holmes/core/tools.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always place Python imports at the top of the file, not inside functions or methods
All Python code must include type hints (mypy enforced)

Files:

  • holmes/core/tools.py
holmes/{core,plugins}/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

All tools must return detailed error messages from underlying APIs, including executed command/query, time ranges/parameters, and full API error response; 'no data' responses must specify what was searched and where

Files:

  • holmes/core/tools.py
🧠 Learnings (1)
📚 Learning: 2025年07月08日T08:45:41.069Z
Learnt from: nherment
PR: robusta-dev/holmesgpt#610
File: .github/workflows/llm-evaluation.yaml:39-42
Timestamp: 2025年07月08日T08:45:41.069Z
Learning: When suggesting improvements to environment variable handling in robusta-dev/holmesgpt, check first if validation logic already exists rather than reimplementing it.

Applied to files:

  • holmes/core/tools.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: llm_evals
  • GitHub Check: Pre-commit checks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@coderabbitai coderabbitai[bot] coderabbitai[bot] left review comments

@moshemorad moshemorad moshemorad approved these changes

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /