Integrate NeuroRift with OpenClaw gateway (config, adapter, boot/heartbeat/persona)#24
Conversation
|
CodeAnt AI is reviewing your PR. |
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review infoConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThis pull request introduces a NeuroRift + OpenClaw gateway integration, consisting of a new adapter module that bridges tool calls between services, enforces high-risk command approvals via Discord and Telegram notifications, manages environment secrets across providers, and implements isolated session handling. Supporting documentation outlines boot sequences, monitoring checklists, and agent operating principles. Changes
Sequence Diagram(s)sequenceDiagram
participant GW as OpenClaw Gateway
participant Adapter as NeuroRiftOpenClawAdapter
participant Approver as ExecutionApprovalForwarder
participant Discord as Discord/Telegram
participant Bridge as NeuroRift Bridge
GW->>Adapter: neurorift.tool_call event
Adapter->>Adapter: _build_rpc_frame()
Adapter->>Approver: evaluate(command, session_id)
Approver->>Approver: _is_high_risk(command)
alt High-Risk Command
Approver->>Discord: _notify_discord/telegram(content)
Discord-->>Approver: approval response (or timeout)
Approver-->>Adapter: ApprovalResult {approved, reason}
else Low-Risk Command
Approver-->>Adapter: ApprovalResult {approved: true}
end
alt Approved
Adapter->>Bridge: _call_neurorift(payload) via HTTP POST
Bridge-->>Adapter: execution result
Adapter->>Adapter: build rpc.request frame
Adapter->>GW: send rpc.request
else Denied/Timeout
Adapter->>Adapter: build rpc.reject frame
Adapter->>GW: send rpc.reject (approval_required)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
|
|
Overall Grade Focus Area: Complexity |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| Python | Feb 27, 2026 12:09p.m. | Review ↗ |
Nitpicks 🔍
|
| async def _build_rpc_frame(self, tool_call: Dict[str, Any]) -> Dict[str, Any]: | ||
| rpc_method = self._map_method(tool_call) | ||
| command_preview = json.dumps(tool_call, ensure_ascii=False) | ||
|
|
||
| approval = await self.approval_forwarder.evaluate(command_preview, self.session_id) | ||
| if not approval.approved: | ||
| return { | ||
| "type": "rpc.reject", | ||
| "id": str(uuid.uuid4()), | ||
| "session": {"id": self.session_id, "mode": "isolated"}, | ||
| "error": { | ||
| "code": "approval_required", | ||
| "message": approval.reason, | ||
| }, | ||
| } | ||
|
|
||
| bridged = await self._call_neurorift(tool_call) | ||
|
|
||
| return { | ||
| "type": "rpc.request", | ||
| "id": str(uuid.uuid4()), | ||
| "session": { | ||
| "id": self.session_id, | ||
| "mode": "isolated", | ||
| "pipeline": ["planner", "tool-selector/manus", "operator", "analyst/cursor"], | ||
| }, | ||
| "method": rpc_method, | ||
| "params": { | ||
| "source": "neurorift-fastapi", | ||
| "bridgePort": 8766, | ||
| "gatewayPort": 18789, | ||
| "yieldMs": YIELD_MS, | ||
| "payload": bridged, | ||
| }, | ||
| "ts": int(time.time() * 1000), | ||
| } |
There was a problem hiding this comment.
Suggestion: The HTTP call to the NeuroRift FastAPI bridge in _call_neurorift is used directly in _build_rpc_frame without any error handling, so if /execute is unavailable or returns a non-2xx status (triggering httpx HTTP errors), the exception will bubble up and crash the adapter instead of returning a structured RPC error to the OpenClaw gateway. [possible bug]
Severity Level: Major ⚠️
- ❌ Adapter process crashes when NeuroRift FastAPI /execute returns error.
- ⚠️ OpenClaw gateway loses active isolated NeuroRift session connection.
- ⚠️ High-risk command approvals fail when bridge temporarily unavailable.| async def _build_rpc_frame(self, tool_call: Dict[str, Any]) -> Dict[str, Any]: | |
| rpc_method = self._map_method(tool_call) | |
| command_preview = json.dumps(tool_call, ensure_ascii=False) | |
| approval = await self.approval_forwarder.evaluate(command_preview, self.session_id) | |
| if not approval.approved: | |
| return { | |
| "type": "rpc.reject", | |
| "id": str(uuid.uuid4()), | |
| "session": {"id": self.session_id, "mode": "isolated"}, | |
| "error": { | |
| "code": "approval_required", | |
| "message": approval.reason, | |
| }, | |
| } | |
| bridged = await self._call_neurorift(tool_call) | |
| return { | |
| "type": "rpc.request", | |
| "id": str(uuid.uuid4()), | |
| "session": { | |
| "id": self.session_id, | |
| "mode": "isolated", | |
| "pipeline": ["planner", "tool-selector/manus", "operator", "analyst/cursor"], | |
| }, | |
| "method": rpc_method, | |
| "params": { | |
| "source": "neurorift-fastapi", | |
| "bridgePort": 8766, | |
| "gatewayPort": 18789, | |
| "yieldMs": YIELD_MS, | |
| "payload": bridged, | |
| }, | |
| "ts": int(time.time() * 1000), | |
| } | |
| async def _build_rpc_frame(self, tool_call: Dict[str, Any]) -> Dict[str, Any]: | |
| rpc_method = self._map_method(tool_call) | |
| command_preview = json.dumps(tool_call, ensure_ascii=False) | |
| approval = await self.approval_forwarder.evaluate(command_preview, self.session_id) | |
| if not approval.approved: | |
| return { | |
| "type": "rpc.reject", | |
| "id": str(uuid.uuid4()), | |
| "session": {"id": self.session_id, "mode": "isolated"}, | |
| "error": { | |
| "code": "approval_required", | |
| "message": approval.reason, | |
| }, | |
| } | |
| try: | |
| bridged = await self._call_neurorift(tool_call) | |
| except httpx.HTTPError as exc: | |
| return { | |
| "type": "rpc.reject", | |
| "id": str(uuid.uuid4()), | |
| "session": {"id": self.session_id, "mode": "isolated"}, | |
| "error": { | |
| "code": "bridge_unavailable", | |
| "message": f"neurorift-fastapi error: {exc}", | |
| }, | |
| } | |
| return { | |
| "type": "rpc.request", | |
| "id": str(uuid.uuid4()), | |
| "session": { | |
| "id": self.session_id, | |
| "mode": "isolated", | |
| "pipeline": ["planner", "tool-selector/manus", "operator", "analyst/cursor"], | |
| }, | |
| "method": rpc_method, | |
| "params": { | |
| "source": "neurorift-fastapi", | |
| "bridgePort": 8766, | |
| "gatewayPort": 18789, | |
| "yieldMs": YIELD_MS, | |
| "payload": bridged, | |
| }, | |
| "ts": int(time.time() * 1000), | |
| } |
Steps of Reproduction ✅
1. Configure and start the OpenClaw gateway using `openclaw.json5` at
`/workspace/NeuroRift/openclaw.json5`, which defines the `neurorift-primary` agent
entrypoint as `python3 integrations/openclaw/openclaw_gateway_adapter.py` (line 23).
2. Start the adapter process so `NeuroRiftOpenClawAdapter.run()` in
`integrations/openclaw/openclaw_gateway_adapter.py:171-201` connects to the WebSocket
gateway at `GATEWAY_WS_URL` and enters the `while True` loop receiving events.
3. Ensure the NeuroRift FastAPI bridge at `BRIDGE_URL` (default `http://127.0.0.1:8766`)
is unavailable or unhealthy, e.g. do not start the FastAPI service or configure it to
return HTTP 500 for `POST /execute`, which `NeuroRiftOpenClawAdapter._call_neurorift()` at
lines 128-132 calls via `httpx.AsyncClient.post(..., json=payload)` followed by
`response.raise_for_status()`.
4. From the OpenClaw side, trigger any workflow that causes a `neurorift.tool_call` event
to be sent over the gateway WebSocket; the adapter's `run()` method (lines 190-197)
receives the message, decodes it, and for events with `type == "neurorift.tool_call"`
calls `frame = await self._build_rpc_frame(event.get("payload", {}))` where
`_build_rpc_frame()` (lines 134-169) invokes `bridged = await
self._call_neurorift(tool_call)` (line 150), which raises `httpx.HTTPError` due to the
failing `/execute` call, propagating out of `_build_rpc_frame()` and `run()` without being
caught, causing `asyncio.run(NeuroRiftOpenClawAdapter().run())` at line 201 to terminate
and the adapter WebSocket session to drop instead of returning a structured `rpc.reject`
frame to the gateway.Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** integrations/openclaw/openclaw_gateway_adapter.py
**Line:** 134:169
**Comment:**
*Possible Bug: The HTTP call to the NeuroRift FastAPI bridge in `_call_neurorift` is used directly in `_build_rpc_frame` without any error handling, so if `/execute` is unavailable or returns a non-2xx status (triggering `httpx` HTTP errors), the exception will bubble up and crash the adapter instead of returning a structured RPC error to the OpenClaw gateway.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.|
CodeAnt AI finished reviewing your PR. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8e69408c56
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| }, | ||
| } | ||
|
|
||
| bridged = await self._call_neurorift(tool_call) |
There was a problem hiding this comment.
Send bridge-compatible command types
_build_rpc_frame posts the raw tool_call to /execute, but _map_method indicates those calls are run_terminal_cmd/read_file/write_file; the FastAPI bridge only handles ai_generate, tool_execute, robin_search, and browser_action (modules/web/bridge_server.py, lines 64-73), so these mapped calls are returned as "Unknown command type" and then forwarded as an RPC request payload. In practice this breaks the new adapter flow for the very command families it maps.
Useful? React with 👍 / 👎.
| # Placeholder for channel callback integration. | ||
| # Default-safe behavior is deny-on-timeout. | ||
| await asyncio.sleep(0) | ||
| return ApprovalResult(approved=False, reason="approval pending/timeout -> deny") | ||
|
|
There was a problem hiding this comment.
Honor approval responses before rejecting risky commands
For any command matching HIGH_RISK_PATTERNS, evaluate sends notifications and then immediately returns approved=False without waiting for any callback path, so high-risk operations are always denied even if an operator responds "APPROVE" in Discord/Telegram. This makes human-in-the-loop approval non-functional and blocks planned recon actions like full-port scans.
Useful? React with 👍 / 👎.
User description
Motivation
Description
openclaw.json5that registers NeuroRift asneurorift-primary, mapsrun_terminal_cmd/read_file/write_file/process_stateto OpenClaw RPC methods (exec/read/write/process), enables Docker sandboxing for offensive tools, configures channel routing, and registers a CronService jobweekly-attack-surface-reconwithcomputeNextRunAtMsenabled.integrations/openclaw/openclaw_gateway_adapter.pythat connects to the OpenClaw WebSocket (ws://127.0.0.1:18789/gateway), calls NeuroRift FastAPI athttp://127.0.0.1:8766/execute, translates tool calls into RPC frames, enforcesisolatedsession metadata, normalizes AI provider env keys, and forwards high-risk command approvals to Discord/Telegram (deny-on-timeout safe default).BOOT.md,HEARTBEAT.md, andSOUL.mdto document startup, proactive monitoring checks, and persistent persona/memory anchors for session state and attack-surface context.nmap -p-,--script,sqlmap,msfconsole,rm -rf,curl | sh) and sends notifications to configuredOPENCLAW_DISCORD_WEBHOOK_URLand Telegram bot settings as a secure baseline placeholder for human callbacks.Testing
python3 -m py_compile integrations/openclaw/openclaw_gateway_adapter.pywhich completed successfully.openclaw.json5,BOOT.md,HEARTBEAT.md, andSOUL.mdas part of the integration artifacts.Codex Task
CodeAnt-AI Description
Integrate NeuroRift with OpenClaw gateway; isolated sessions and approval forwarding
What Changed
Impact
✅ Isolated NeuroRift sessions✅ High-risk commands require approval via Discord/Telegram✅ Consistent AI provider env variables💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.
Summary by CodeRabbit
New Features
Documentation