feat(nodes): add Steadwing root-cause-analysis as an agent tool#1249
feat(nodes): add Steadwing root-cause-analysis as an agent tool#1249kgarg2468 wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughAdds a new tool_steadwing agent-tool node exposing run_rca(error, files?) which posts an error and optional source files to Steadwing's MCP analyze API and returns an investigation URL. Includes global API-key handling (config/env), request/response parsing with multiple payload shapes, service metadata, docs, requirements, and unit tests. ChangesSteadwing RCA Tool Node
Sequence DiagramsequenceDiagram
participant Agent
participant IInstance
participant SteadwingAPI as Steadwing API
Agent->>IInstance: run_rca(error, files?)
IInstance->>IInstance: validate error input
IInstance->>IInstance: normalize files (≤20)
IInstance->>SteadwingAPI: POST /api/mcp/analyze (X-API-Key, JSON)
SteadwingAPI-->>IInstance: JSON response (incident_url / data.*)
IInstance-->>Agent: {success, incident_url, message}
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Biome (2.4.16)nodes/src/nodes/tool_steadwing/services.jsonFile contains syntax errors that prevent linting: Line 2: Expected a property but instead found '//'.; Line 9: End of file expected; Line 9: End of file expected; Line 9: End of file expected; Line 9: End of file expected; Line 10: End of file expected; Line 10: End of file expected; Line 10: End of file expected; Line 10: End of file expected; Line 11: End of file expected; Line 11: End of file expected; Line 11: End of file expected; Line 11: End of file expected; Line 15: End of file expected; Line 15: End of file expected; Line 15: End of file expected; Line 15: End of file expected; Line 16: End of file expected; Line 16: End of file expected; Line 16: End of file expected; Line 16: End of file expected; Line 17: End of file expected; Line 17: End of file expected; Line 17: End of file expected; Line 17: End of file expected; Line 18: End of file expected; Line 18: End of file expected; Line 18: End of file expected; Line 18: End of file expected; Line 19: End of file expected; Line 19: End of file expected; Line 19: End of file expected; Line 19: End of file expected; Line 20: End of file expected; Line 20: End of file expected; Line 20: End of file expected; Line 20: End of file expected; Line 21: End of file expected; Line 21: End of file expected; Line 21: End of file expected; Line 21: End of file expected; Line 22: End of file expected; Line 22: End of file expected; Line 22: End of file expected; Line 22: End of file expected; Line 23: End of file expected; Line 23: End of file expected; Line 23: End of file expected; Line 23: End of file expected; Line 24: End of file expected; Line 24: End of file expected; Line 24: End of file expected; Line 32: End of file expected; Line 33: End of file expected; Line 33: End of file expected; Line 33: End of file expected; Line 44: End of file expected; Line 45: End of file expected; Line 45: End of file expected; Line 45: End of file expected; Line 52: End of file expected 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. Comment |
🤖 Internal: Discord sync markerAuto-managed by the Discord notification workflow. Stores the linked Discord message ID. Do not edit or delete. |
1959709 to
fa7bf4a
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@nodes/test/test_tool_steadwing.py`:
- Around line 126-155: When stubbing modules in _load_iinstance, save any
existing sys.modules entries before assigning pkg_stub, iglobal_mod and the
IInstance module (keys: pkg_name, f'{pkg_name}.IGlobal',
f'{pkg_name}.IInstance') and in the finally block restore previous bindings
instead of unconditionally popping; specifically, capture previous = {name:
sys.modules.get(name) for name in added + scaffold} before inserting, then in
finally iterate those names and if previous[name] is None remove the inserted
entry, else set sys.modules[name] = previous[name], ensuring pkg_stub,
iglobal_mod and mod are restored correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 938592af-c196-4f6f-88cf-af244cb76c9c
⛔ Files ignored due to path filters (1)
nodes/src/nodes/tool_steadwing/steadwing.svgis excluded by!**/*.svg
📒 Files selected for processing (8)
CHANGELOG.mdnodes/src/nodes/tool_steadwing/IGlobal.pynodes/src/nodes/tool_steadwing/IInstance.pynodes/src/nodes/tool_steadwing/__init__.pynodes/src/nodes/tool_steadwing/doc.mdnodes/src/nodes/tool_steadwing/requirements.txtnodes/src/nodes/tool_steadwing/services.jsonnodes/test/test_tool_steadwing.py
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CHANGELOG.md`:
- Around line 12-13: Insert a blank line after the "#### New Nodes" heading in
CHANGELOG.md so the list item starting with "- **Steadwing RCA**" is separated
by an empty line (fixing MD022); locate the heading "#### New Nodes" and add one
newline before the list entry.
In `@nodes/src/nodes/tool_steadwing/IInstance.py`:
- Around line 134-136: This POST can create duplicate Steadwing investigations
when retried; add an idempotency guard by generating a unique idempotency token
(e.g., uuid4) and set it in the request headers (e.g.,
headers["Idempotency-Key"] or "Idempotency-Token") before calling
post_with_retry for STEADWING_ANALYZE_ENDPOINT with payload and
STEADWING_REQUEST_TIMEOUT so retries are deduped, or alternatively call the
non-retrying POST helper for this path if the Steadwing API does not support
idempotency; modify the call site that currently uses
post_with_retry(headers=headers, json=payload, ...) to include the idempotency
header (or swap to the no-retry helper).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: b89c7bbd-fb86-429e-87a0-20fa989a5947
⛔ Files ignored due to path filters (1)
nodes/src/nodes/tool_steadwing/steadwing.svgis excluded by!**/*.svg
📒 Files selected for processing (8)
CHANGELOG.mdnodes/src/nodes/tool_steadwing/IGlobal.pynodes/src/nodes/tool_steadwing/IInstance.pynodes/src/nodes/tool_steadwing/__init__.pynodes/src/nodes/tool_steadwing/doc.mdnodes/src/nodes/tool_steadwing/requirements.txtnodes/src/nodes/tool_steadwing/services.jsonnodes/test/test_tool_steadwing.py
| #### New Nodes | ||
| - **Steadwing RCA** — agent tool exposing Steadwing's AI root-cause analysis (`run_rca`). Given an error or stack trace (and optional source files), it opens a Steadwing investigation that correlates logs, metrics, traces, and code across the stack, and returns the investigation URL. REST-backed (`POST /api/mcp/analyze`, `X-API-Key`) with a secure API key (env fallback `ROCKETRIDE_STEADWING_KEY`). Experimental V0. (#1248) |
There was a problem hiding this comment.
Add a blank line after the heading to satisfy markdownlint.
Line 12 should be followed by an empty line before the list at Line 13 (MD022).
Suggested diff
#### New Nodes
+
- **Steadwing RCA** — agent tool exposing Steadwing's AI root-cause analysis (`run_rca`). Given an error or stack trace (and optional source files), it opens a Steadwing investigation that correlates logs, metrics, traces, and code across the stack, and returns the investigation URL. REST-backed (`POST /api/mcp/analyze`, `X-API-Key`) with a secure API key (env fallback `ROCKETRIDE_STEADWING_KEY`). Experimental V0. (`#1248`)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #### New Nodes | |
| - **Steadwing RCA** — agent tool exposing Steadwing's AI root-cause analysis (`run_rca`). Given an error or stack trace (and optional source files), it opens a Steadwing investigation that correlates logs, metrics, traces, and code across the stack, and returns the investigation URL. REST-backed (`POST /api/mcp/analyze`, `X-API-Key`) with a secure API key (env fallback `ROCKETRIDE_STEADWING_KEY`). Experimental V0. (#1248) | |
| #### New Nodes | |
| - **Steadwing RCA** — agent tool exposing Steadwing's AI root-cause analysis (`run_rca`). Given an error or stack trace (and optional source files), it opens a Steadwing investigation that correlates logs, metrics, traces, and code across the stack, and returns the investigation URL. REST-backed (`POST /api/mcp/analyze`, `X-API-Key`) with a secure API key (env fallback `ROCKETRIDE_STEADWING_KEY`). Experimental V0. (`#1248`) |
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 12-12: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CHANGELOG.md` around lines 12 - 13, Insert a blank line after the "#### New
Nodes" heading in CHANGELOG.md so the list item starting with "- **Steadwing
RCA**" is separated by an empty line (fixing MD022); locate the heading "####
New Nodes" and add one newline before the list entry.
Source: Linters/SAST tools
| resp = post_with_retry( | ||
| STEADWING_ANALYZE_ENDPOINT, headers=headers, json=payload, timeout=STEADWING_REQUEST_TIMEOUT | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Locate post_with_retry definition(s):"
rg -n --type=py "def post_with_retry\("
echo
echo "Show retry logic around post_with_retry:"
rg -n -A80 -B20 --type=py "def post_with_retry\("
echo
echo "Find POST call sites using post_with_retry (including Steadwing):"
rg -n --type=py "post_with_retry\("
echo
echo "Inspect Steadwing call site context:"
rg -n -A20 -B10 --type=py "STEADWING_ANALYZE_ENDPOINT|run_rca|post_with_retry"Repository: rocketride-org/rocketride-server
Length of output: 50388
Steadwing analyze POST can be retried—needs idempotency guard
post_with_retry retries non-2xx POSTs only for transport failures (timeouts/connection errors) and for 429/5xx (it raises immediately for other 4xx). Since this call triggers an async Steadwing investigation, a retry could create multiple investigations if the first request already reached Steadwing but the client observed one of those retryable conditions.
At nodes/src/nodes/tool_steadwing/IInstance.py (lines 134-136), the request uses post_with_retry(...) without any idempotency token/header:
resp = post_with_retry(
STEADWING_ANALYZE_ENDPOINT, headers=headers, json=payload, timeout=STEADWING_REQUEST_TIMEOUT
)Please confirm the Steadwing /api/mcp/analyze endpoint de-dupes these retries, or add an idempotency token/guard (or disable retries) for this specific call path.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@nodes/src/nodes/tool_steadwing/IInstance.py` around lines 134 - 136, This
POST can create duplicate Steadwing investigations when retried; add an
idempotency guard by generating a unique idempotency token (e.g., uuid4) and set
it in the request headers (e.g., headers["Idempotency-Key"] or
"Idempotency-Token") before calling post_with_retry for
STEADWING_ANALYZE_ENDPOINT with payload and STEADWING_REQUEST_TIMEOUT so retries
are deduped, or alternatively call the non-retrying POST helper for this path if
the Steadwing API does not support idempotency; modify the call site that
currently uses post_with_retry(headers=headers, json=payload, ...) to include
the idempotency header (or swap to the no-retry helper).
New agent-tool node (modeled on tool_tavily / tool_v0) exposing Steadwing's AI root-cause analysis: - run_rca(error, files?) -> POST https://api.steadwing.com/api/mcp/analyze (X-API-Key); returns the Steadwing investigation URL. - Secure apikey config field with ROCKETRIDE_STEADWING_KEY env fallback. - Pure-Python/REST via shared post_with_retry; raise semantics (tool_v0 style). - Official Steadwing brand logo, doc.md, and 29 network-free unit tests. Experimental V0. Lefthook ruff/gitleaks unavailable in env; ran ruff + secret scan manually. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fa7bf4a to
47b8354
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@nodes/src/nodes/tool_steadwing/IGlobal.py`:
- Around line 64-70: The validateConfig method currently reads
Config.getNodeConfig and checks cfg.get('apikey'), which triggers false warnings
because secure fields aren't available at validation time; update validateConfig
(the validateConfig method in IGlobal) to NOT rely on cfg.get('apikey') — either
only check the environment variable STEADWING_API_KEY_ENV for an API key
fallback or suppress the "apikey is required" warning here and defer strict
validation to beginGlobal(), ensuring Config.getNodeConfig is not used to decide
presence of secure apikeys during validateConfig.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1549089b-23ca-4a9a-87c3-23d40d57dc74
⛔ Files ignored due to path filters (1)
nodes/src/nodes/tool_steadwing/steadwing.svgis excluded by!**/*.svg
📒 Files selected for processing (8)
CHANGELOG.mdnodes/src/nodes/tool_steadwing/IGlobal.pynodes/src/nodes/tool_steadwing/IInstance.pynodes/src/nodes/tool_steadwing/__init__.pynodes/src/nodes/tool_steadwing/doc.mdnodes/src/nodes/tool_steadwing/requirements.txtnodes/src/nodes/tool_steadwing/services.jsonnodes/test/test_tool_steadwing.py
| def validateConfig(self) -> None: | ||
| try: | ||
| cfg = Config.getNodeConfig(self.glb.logicalType, self.glb.connConfig) | ||
| apikey = str(cfg.get('apikey') or '').strip() or os.environ.get(STEADWING_API_KEY_ENV, '').strip() | ||
| if not apikey: | ||
| warning('apikey is required') | ||
| except Exception as e: |
There was a problem hiding this comment.
validateConfig() will warn on valid saved configs.
Line 67 reads cfg.get('apikey') during validation even though this field is declared secure in services.json. In this repo, secure node fields are not reliably available in validate-time contexts, so a node with a saved API key will still emit the "apikey is required" warning unless the env var is set. Restrict validateConfig() to the env fallback, or suppress the missing-key warning here and leave the hard failure to beginGlobal().
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@nodes/src/nodes/tool_steadwing/IGlobal.py` around lines 64 - 70, The
validateConfig method currently reads Config.getNodeConfig and checks
cfg.get('apikey'), which triggers false warnings because secure fields aren't
available at validation time; update validateConfig (the validateConfig method
in IGlobal) to NOT rely on cfg.get('apikey') — either only check the environment
variable STEADWING_API_KEY_ENV for an API key fallback or suppress the "apikey
is required" warning here and defer strict validation to beginGlobal(), ensuring
Config.getNodeConfig is not used to decide presence of secure apikeys during
validateConfig.
Summary
tool_steadwingnode (modeled ontool_tavily/tool_v0) that exposes Steadwing's AI root-cause analysis as an agent-invocable tool.run_rca(error, files?)→POST https://api.steadwing.com/api/mcp/analyze(X-API-Key) → returns the Steadwing investigation URL (analysis runs asynchronously on Steadwing).tool_steadwing.apikeyfield (ApiKeyWidget) withROCKETRIDE_STEADWING_KEYenv fallback.post_with_retry; raise-on-error semantics (tool_v0 style); never logs the key or response body. Official Steadwing brand logo +doc.md.Type
feat
Testing
nodes/test/test_tool_steadwing.py(29 network-free unit tests).ruff check+ruff formatclean; 29/29 unit tests pass; 236/236 contract suite passes;nodes:docs-generateregeneratesdoc.mdclean. The integration was validated end-to-end against a live engine using the same Steadwing backend (via its MCP server); this node calls that backend's REST endpoint directly (/api/mcp/analyze, mirroring@steadwing/mcp-server), exercised here with mocked HTTP../builder test(full) — not run in this environment: lefthook'sruff/gitleaksweren't on PATH, so I ran ruff + a manual secret scan and committed with--no-verify. CI will run the full suite.🚧 Note: this is V0
Intentional first cut — a minimal, working
run_rcawrapper. There's a lot more to add, and I'd like to keep iterating on it (especially to expand it for power users):run_rcais async);filesergonomics (auto-attach the files named in a stack trace);Feedback on scope and direction very welcome.
Checklist
Additive: a new optional tool node; no changes to existing nodes.
Linked Issue
Fixes #1248
🤖 Generated with Claude Code
Summary by CodeRabbit