feat: add SKALE facilitator integration prototype with x402 fallback bypass#485
feat: add SKALE facilitator integration prototype with x402 fallback bypass#485Subhajitdas99 wants to merge 15 commits intoGetBindu:mainfrom
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughRenames Changes
Sequence DiagramsequenceDiagram
participant User
participant Test as test_local.py
participant Handler as agent.handler()
participant Router as router
participant Retriever as retriever
participant Domain as domain_agent
participant LLM as OpenRouter_LLM
participant Facilitator as SKALE_Facilitator
User->>Test: run with query
Test->>Handler: handler(messages)
Handler->>Router: classify_intent(query)
Router-->>Handler: intent
Handler->>Router: route_db(intent)
Router-->>Handler: db_path
Handler->>Retriever: retrieve_docs(db_path, query)
Retriever-->>Handler: documents
Handler->>Router: route_agent(intent)
Router-->>Handler: agent_fn
Handler->>Domain: agent_fn(query, context)
Domain-->>Handler: agent_response
Handler->>LLM: agent.run(refinement_prompt)
LLM-->>Handler: refined_answer
Handler->>Facilitator: call_skale_facilitator()
Facilitator-->>Handler: payment_result
Handler-->>Test: structured response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (4)
examples/rag_router_agent/README.md (1)
46-86: Documentation is out of sync with the actual response schema and project layout.This PR's central feature is the SKALE facilitator integration, and responses now include
docs_usedandpaymentfields (see_base_responseinagent.pyat lines 128-136), but:
- The example response JSON (lines 48-55) omits
docs_usedandpayment, so it no longer matches whathandler()actually returns.- The Project Structure block (lines 72-86) does not list
skale_payment.pyorx402_patch.py, even though both are imported at startup byagent.py.- There is no mention of the SKALE facilitator step, the expected 401 behavior, or any facilitator-related env/config — i.e. the user-visible change called out in the PR description is not documented here.
Given this is the example README that users will follow, it's worth updating so the docs reflect the new behavior before merging.
📝 Suggested additions
```json { "answer": "GST is a tax applied on goods and services...", "intent": "finance", "agent_used": "finance", - "db_used": "db/finance.txt" + "db_used": "db/finance.txt", + "docs_used": ["..."], + "payment": { + "status": "reachable", + "code": 401, + "note": "Authentication required (expected for prototype)" + } }```diff rag_router_agent/ │ ├── agent.py # Main handler (orchestration + LLM) ├── router.py # Intent + routing logic ├── retriever.py # Document retrieval +├── skale_payment.py # SKALE facilitator call (x402 prototype) +├── x402_patch.py # Simulated x402 layer (fallback bypass) ├── agents/ # Domain agents (A2A)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/rag_router_agent/README.md` around lines 46 - 86, Update the README to match the new response schema and project layout: modify the example JSON response to include the docs_used and payment fields to mirror the _base_response defined in agent.py and handler() return shape; add skale_payment.py and x402_patch.py to the Project Structure list under agents/startup imports; and add a short note describing the SKALE facilitator step including expected 401 behavior, required env/config (e.g., facilitator auth), and what the payment.status/code fields mean for users.examples/rag_router_agent/router.py (1)
1-49: Replacesys.pathhack + mid-file absolute imports with package-relative imports, and fix the EOF newline to unblock CI.A few related issues:
- CI is failing on
end-of-file-fixer(see pipeline failure). The file needs a trailing newline after line 49. Runningpre-commit run --all-fileslocally will fix it.sys.path.insert(0, BASE_DIR)at lines 9-10 mutates global import state at module-import time. This only works when the example is executed from its own directory and can shadow top-level packages in a larger environment (a user with aagentspackage installed will silently get the wrong module).- Mid-file absolute imports at lines 35-37 violate PEP 8 E402 and rely on the
sys.pathhack above. Using explicit relative imports removes both problems and lets the file keep all imports at the top.- Minor:
import reis top-level but the domain-agent imports are pushed past function definitions; moving them up keeps static tools happy.♻️ Proposed refactor
import os import re -import sys # 📁 Resolve base directory safely BASE_DIR = os.path.dirname(os.path.abspath(__file__)) -# (Optional but safer import handling) -if BASE_DIR not in sys.path: - sys.path.insert(0, BASE_DIR) +# 🤖 Import domain agents (A2A delegation) +from .agents.finance_agent import finance_agent +from .agents.legal_agent import legal_agent +from .agents.tech_agent import tech_agent # 🔤 Intent classification (robust + explicit) def classify_intent(query: str) -> str | None: ... - -# 🤖 Import domain agents (A2A delegation) -from agents.finance_agent import finance_agent -from agents.legal_agent import legal_agent -from agents.tech_agent import tech_agent - - # 🔀 Route to correct agent def route_agent(intent: str):Note: relative imports require
examples/rag_router_agent/(andagents/) to contain__init__.pyfiles and be run as a package. If you prefer to keep the flat-script style, at minimum please move thefrom agents...imports to the top of the file and drop thesys.pathmutation, or move it into an explicitif __name__ == "__main__":bootstrap.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/rag_router_agent/router.py` around lines 1 - 49, The file mutates global import state with sys.path.insert(0, BASE_DIR) and performs mid-file absolute imports (from agents.finance_agent, legal_agent, tech_agent) which causes E402 and brittle behavior; remove the sys.path mutation, move all imports to the top, and switch to package-relative imports (e.g., from .agents.finance_agent import finance_agent, .agents.legal_agent import legal_agent, .agents.tech_agent import tech_agent) or alternatively keep absolute imports but only after adding a guarded bootstrap (move sys.path insertion into if __name__ == "__main__":). Also ensure there's a trailing newline at EOF and keep functions like classify_intent, route_db, and route_agent unchanged except for relying on the new import paths; verify examples/rag_router_agent and agents directories have __init__.py if using relative imports.examples/rag_router_agent/agent.py (2)
97-102: ReplaceExceptionwithlogging.exception.For a code sample that will be copied into real agents,
print(f"[ERROR] ...")loses stack traces and bypasses Bindu's log routing; catching bareException(ruff BLE001) also hides things likeKeyboardInterruptsubclasses of BaseException edge cases in tests. A one-liner change keeps behavior but gives much better diagnostics.♻️ Suggested fix
+import logging @@ +logger = logging.getLogger(__name__) @@ try: result = agent.run(final_prompt) answer = result.content if hasattr(result, "content") else str(result) - except Exception as e: - print(f"[ERROR] LLM call failed: {e}") + except Exception: + logger.exception("LLM call failed") answer = "Error generating response. Please try again."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/rag_router_agent/agent.py` around lines 97 - 102, Replace the print in the agent.run try/except with logging.exception to capture the full stack trace and integrate with the app's logging; in the except block that catches exceptions from agent.run(final_prompt) (the try/except surrounding agent.run and the answer assignment), call logging.exception with a descriptive message instead of print, ensure the logging module is imported, and keep the existing fallback assignment to answer ("Error generating response. Please try again.").
140-149: Add realisticBINDU_AUTHORvalue and populateskillslist to match other examples.The default
authoris a placeholder (your.email@example.com) that passesbindufy()'s non-empty validation but shouldn't appear in shipped example code. Similarly,skills: []is valid but inconsistent—other examples (ag2_research_team,agent_swarm) populate skills to demonstrate A2A capability advertisement.Recommended changes:
- Add
BINDU_AUTHORenvironment variable documentation toREADME.md(alongsideOPENROUTER_API_KEYandBINDU_DEPLOYMENT_URL).- Replace
"skills": []with at least one example skill (e.g.,["skills/rag-query"]) to show the capability advertisement path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/PAYMENT.md`:
- Around line 260-286: Update the text that currently attributes SKALE support
limitations to the upstream `x402` package: clarify that `x402==0.2.1` uses
CAIP-2 identifiers and can support arbitrary EVM chains (e.g., SKALE at
`eip155:324705682`), and instead state that the real blocker is the CDP
facilitator which lacks native SKALE support; modify the sections that start
with "These upstream `x402` constraints..." and "What this means" to distinguish
SDK capability from facilitator choice, and add a short note that Bindu's
payment middleware and RPC configuration are already flexible but require
facilitator updates for full SKALE integration.
In `@examples/rag_router_agent/agent.py`:
- Around line 6-15: The import of x402_patch in agent.py will raise ImportError
because the module is missing; add a new module named x402_patch.py alongside
the example (implement a patch_x402() function that safely applies the
monkey-patch only once — idempotent — e.g., guard with a module-level flag or
check), update the README Project Structure to list x402_patch.py and briefly
describe its purpose, and ensure agent.py continues to call patch_x402()
unconditionally at startup so the patch is applied early without causing errors.
In `@examples/rag_router_agent/db/legal.txt`:
- Line 2: Replace the stale phrase "Indian Penal Code" with the updated statute
name "Bharatiya Nyaya Sanhita, 2023" and include its effective date "came into
force on July 1, 2024" so the document reflects current law; update the sentence
in the legal.txt content (the string containing "Indian Penal Code") to read
something like "Bharatiya Nyaya Sanhita, 2023 replaced the Indian Penal Code and
came into force on July 1, 2024" and optionally add a brief citation note for
the RAG knowledge base.
In `@examples/rag_router_agent/retriever.py`:
- Around line 6-24: Open the DB file with explicit encoding by changing the open
call to include encoding="utf-8" when reading db_path, and replace the substring
membership check with a true token-based match: build doc_tokens (e.g., using
re.findall(r"\w+", doc_lower) or splitting) and compute score as the count of
query_words that exactly appear in the doc_tokens (use a set for doc_tokens for
O(1) lookups) instead of using "word in doc_lower"; keep the existing filter
that only appends (score, doc) when score > 0 so irrelevant docs are excluded.
In `@examples/rag_router_agent/skale_payment.py`:
- Around line 4-55: call_skale_facilitator currently issues a GET to a hardcoded
FACILITATOR_URL and treats 401 as proof of protocol reachability; change it to
POST to the protocol endpoint (e.g., "/verify") with a minimal x402-style JSON
payload when the intent is to simulate a payment verification (or alternatively
rename the function/docstring to a plain liveness check if you want only a GET),
read FACILITATOR_URL from an environment variable (os.getenv("FACILITATOR_URL",
"https://facilitator.x402.fi")) instead of hardcoding, and replace the broad
except Exception: with a narrower requests.exceptions.RequestException (or log
the caught exception) so programming errors aren't swallowed; update response
handling in call_skale_facilitator to inspect the POST response codes and body
accordingly.
In `@examples/rag_router_agent/test_local.py`:
- Around line 1-9: The test file runs the handler at import time (handler,
messages, print(response)), which causes external API/LLM calls during pytest
collection; to fix, keep the top-level import of handler but move the invocation
(messages = [...], response = handler(messages), print(response)) into an if
__name__ == "__main__": block so pytest import/discovery won't execute it
(alternatively rename the file to avoid the test_ prefix), ensuring only manual
runs trigger the integration.
---
Nitpick comments:
In `@examples/rag_router_agent/agent.py`:
- Around line 97-102: Replace the print in the agent.run try/except with
logging.exception to capture the full stack trace and integrate with the app's
logging; in the except block that catches exceptions from
agent.run(final_prompt) (the try/except surrounding agent.run and the answer
assignment), call logging.exception with a descriptive message instead of print,
ensure the logging module is imported, and keep the existing fallback assignment
to answer ("Error generating response. Please try again.").
In `@examples/rag_router_agent/README.md`:
- Around line 46-86: Update the README to match the new response schema and
project layout: modify the example JSON response to include the docs_used and
payment fields to mirror the _base_response defined in agent.py and handler()
return shape; add skale_payment.py and x402_patch.py to the Project Structure
list under agents/startup imports; and add a short note describing the SKALE
facilitator step including expected 401 behavior, required env/config (e.g.,
facilitator auth), and what the payment.status/code fields mean for users.
In `@examples/rag_router_agent/router.py`:
- Around line 1-49: The file mutates global import state with sys.path.insert(0,
BASE_DIR) and performs mid-file absolute imports (from agents.finance_agent,
legal_agent, tech_agent) which causes E402 and brittle behavior; remove the
sys.path mutation, move all imports to the top, and switch to package-relative
imports (e.g., from .agents.finance_agent import finance_agent,
.agents.legal_agent import legal_agent, .agents.tech_agent import tech_agent) or
alternatively keep absolute imports but only after adding a guarded bootstrap
(move sys.path insertion into if __name__ == "__main__":). Also ensure there's a
trailing newline at EOF and keep functions like classify_intent, route_db, and
route_agent unchanged except for relying on the new import paths; verify
examples/rag_router_agent and agents directories have __init__.py if using
relative imports.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7465e2e5-ac07-4aae-a83b-00a2bbb36cfa
📒 Files selected for processing (13)
docs/PAYMENT.mdexamples/rag_router_agent/README.mdexamples/rag_router_agent/agent.pyexamples/rag_router_agent/agents/finance_agent.pyexamples/rag_router_agent/agents/legal_agent.pyexamples/rag_router_agent/agents/tech_agent.pyexamples/rag_router_agent/db/finance.txtexamples/rag_router_agent/db/legal.txtexamples/rag_router_agent/db/tech.txtexamples/rag_router_agent/retriever.pyexamples/rag_router_agent/router.pyexamples/rag_router_agent/skale_payment.pyexamples/rag_router_agent/test_local.py
| # 🔥 NEW: x402 patch (must run early) | ||
| from x402_patch import patch_x402 | ||
|
|
||
| from skale_payment import call_skale_facilitator | ||
| from router import classify_intent, route_db, route_agent | ||
| from retriever import retrieve_docs | ||
|
|
||
|
|
||
| # 🔧 Apply x402 monkey patch at startup | ||
| patch_x402() |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm x402_patch.py exists in the PR tree and inspect its contents.
fd -a -t f 'x402_patch' examples
rg -n -C2 'def patch_x402' -g '*.py'
rg -n 'x402_patch|patch_x402' -g '*.py'
rg -n 'x402_patch|skale_payment' -g '*.md'Repository: GetBindu/Bindu
Length of output: 179
x402_patch module is missing — importing it at line 7 will cause ImportError and the example is unrunnable.
Line 7 imports from x402_patch import patch_x402 and line 15 invokes patch_x402() unconditionally at import time. The module does not exist in the repository, is not documented in the README, and is not included in this PR. The code will fail immediately when loaded.
Add x402_patch.py to examples/rag_router_agent/, document it in the README's Project Structure section, and ensure patch_x402() is idempotent since it executes unconditionally on import.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/rag_router_agent/agent.py` around lines 6 - 15, The import of
x402_patch in agent.py will raise ImportError because the module is missing; add
a new module named x402_patch.py alongside the example (implement a patch_x402()
function that safely applies the monkey-patch only once — idempotent — e.g.,
guard with a module-level flag or check), update the README Project Structure to
list x402_patch.py and briefly describe its purpose, and ensure agent.py
continues to call patch_x402() unconditionally at startup so the patch is
applied early without causing errors.
| @@ -0,0 +1,2 @@ | |||
| A contract is legally binding between two parties. | |||
| Indian Penal Code defines criminal law. | |||
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "legal.txt" -type fRepository: GetBindu/Bindu
Length of output: 98
🌐 Web query:
Bharatiya Nyaya Sanhita 2023 replaced Indian Penal Code July 1 2024
💡 Result:
Yes, the Bharatiya Nyaya Sanhita (BNS) 2023 replaced the Indian Penal Code (IPC) effective July 1, 2024. The BNS was enacted on December 25, 2023 (Act No. 45 of 2023), with Section 1(2) stating it comes into force on a date notified by the Central Government in the Official Gazette. Multiple official and reliable sources confirm the notification appointed July 1, 2024, as the commencement date for BNS (except sub-section (2) of Section 106), thereby repealing the IPC. As of today's date (2026-04-20), BNS remains in force.
Citations:
- 1: https://www.mha.gov.in/sites/default/files/250883_english_01042024.pdf
- 2: https://en.wikipedia.org/wiki/Bharatiya_Nyaya_Sanhita
- 3: https://en.wikipedia.org/wiki/Bharatiya_Nyaya_Sanhita,_2023
- 4: https://www.lexisnexis.com/blogs/in-legal/b/law/posts/reforming-the-indian-penal-code-insights-into-bharatiya-nyaya-sanhita-2023
- 5: https://www.newsonair.gov.in/new-criminal-laws-bharatiya-nyaya-sanhita-2023-and-others-to-come-into-force-on-1st-july-2024/
- 6: https://bprd.nic.in/uploads/pdf/COMPARISON%20SUMMARY%20BNS%20to%20IPC%20.pdf
- 7: http://indiankanoon.org/doc/149679501/
- 8: https://www.advocatekhoj.com/library/bareacts/bharatiyanyayasanhita/1.php?STitle=Short+title%2C+commencement+and+application&Title=Bharatiya+Nyaya+Sanhita%2C+2023
- 9: https://cdnbbsr.s3waas.gov.in/s3ec0548042b1dae4950fef2bd2aafa0b9/uploads/2024/05/2024050922.pdf
- 10: https://www.pib.gov.in/PressReleseDetailm.aspx?PRID=2082757
- 11: https://www.pib.gov.in/PressReleseDetailm.aspx?PRID=2039055&lang=1®=3
🏁 Script executed:
cat -n ./examples/rag_router_agent/db/legal.txtRepository: GetBindu/Bindu
Length of output: 162
Update the stale Indian criminal-law fact.
Line 2 states outdated information for a current legal knowledge base. The Bharatiya Nyaya Sanhita, 2023 replaced the Indian Penal Code and came into force on July 1, 2024. For a RAG system, this outdated reference will produce incorrect legal answers.
⚖️ Proposed update
-Indian Penal Code defines criminal law.
+Bharatiya Nyaya Sanhita, 2023 is India's current criminal code; the Indian Penal Code, 1860 remains relevant for historical and pre-1 July 2024 context.📝 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.
| Indian Penal Code defines criminal law. | |
| Bharatiya Nyaya Sanhita, 2023 is India's current criminal code; the Indian Penal Code, 1860 remains relevant for historical and pre-1 July 2024 context. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/rag_router_agent/db/legal.txt` at line 2, Replace the stale phrase
"Indian Penal Code" with the updated statute name "Bharatiya Nyaya Sanhita,
2023" and include its effective date "came into force on July 1, 2024" so the
document reflects current law; update the sentence in the legal.txt content (the
string containing "Indian Penal Code") to read something like "Bharatiya Nyaya
Sanhita, 2023 replaced the Indian Penal Code and came into force on July 1,
2024" and optionally add a brief citation note for the RAG knowledge base.
| FACILITATOR_URL = "https://facilitator.x402.fi" | ||
|
|
||
|
|
||
| def call_skale_facilitator() -> dict: | ||
| """ | ||
| Minimal prototype for SKALE facilitator integration. | ||
|
|
||
| This simulates an x402 payment call by checking connectivity | ||
| with a facilitator endpoint. | ||
|
|
||
| NOTE: | ||
| - No authentication is included (expected 401 response). | ||
| - This is intentional for prototype validation. | ||
| """ | ||
|
|
||
| try: | ||
| # 🔐 Minimal headers (good practice even for prototype) | ||
| headers = { | ||
| "Content-Type": "application/json" | ||
| } | ||
|
|
||
| response = requests.get( | ||
| FACILITATOR_URL, | ||
| headers=headers, | ||
| timeout=5 | ||
| ) | ||
|
|
||
| status_code = response.status_code | ||
|
|
||
| # ✅ Successful response | ||
| if status_code == 200: | ||
| return { | ||
| "status": "success", | ||
| "message": "Facilitator reachable", | ||
| "code": status_code | ||
| } | ||
|
|
||
| # ⚠️ Expected case (no auth yet) | ||
| elif status_code == 401: | ||
| return { | ||
| "status": "reachable", | ||
| "code": status_code, | ||
| "note": "Authentication required (expected for prototype)" | ||
| } | ||
|
|
||
| # ⚠️ Other responses | ||
| else: | ||
| return { | ||
| "status": "unexpected_response", | ||
| "code": status_code, | ||
| "response_preview": response.text[:200] | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
x402 facilitator HTTP API endpoints verify settle
💡 Result:
x402 facilitators provide standardized HTTP API endpoints for verifying and settling payments in the x402 protocol (HTTP 402 Payment Required for micropayments). Servers POST payment payloads and requirements to these endpoints. Core endpoints (common across implementations like official docs, Cronos, Coinbase CDP, OpenFacilitator): - GET /supported (or /v2/x402/supported): Lists supported networks, schemes (e.g., "exact"), assets, signers. - POST /verify (or /v2/x402/verify): Validates payment signature/payload against requirements without on-chain tx. Request body: {x402Version, paymentHeader (base64), paymentRequirements {scheme, network, payTo, asset, maxAmountRequired}}. Response: {isValid: true, payer: "0x..."} or error. - POST /settle (or /v2/x402/settle): Submits verified payment to blockchain, waits for confirmation. Same request as /verify. Response: {success: true, txHash: "0x...", payer, network} or settlement details. Example request format (from OpenFacilitator/Cronos): POST https://facilitator.example/v2/x402/verify Content-Type: application/json X402-Version: 1 { "x402Version": 1, "paymentPayload": { "x402Version": 1, "scheme": "exact", "network": "eip155:8453", "payload": { "signature": "0x...", "authorization": { "from": "0x...", "to": "0x...", "amount": "1000000", "asset": "0x..." } } }, "paymentRequirements": { "scheme": "exact", "network": "eip155:8453", "payTo": "0x...", "asset": "0x...", "maxAmountRequired": "1000000" } } Additional endpoints in some (e.g., x402facilitator.dev): /api/deposit, /api/balance (account management). Official x402 docs confirm servers POST to facilitator's /verify then /settle. Use HTTPFacilitatorClient(url) in JS libs for abstraction. Live facilitators: CDP (Base/Solana/Polygon), Cronos, Monad, x402facilitator.dev, etc.
Citations:
- 1: https://docs.x402.org/core-concepts/facilitator
- 2: https://x402facilitator.dev/
- 3: https://docs.monad.xyz/guides/x402
- 4: https://docs.cronos.org/cronos-x402-facilitator/api-reference
- 5: https://docs.cdp.coinbase.com/api-reference/v2/rest-api/x402-facilitator/x402-facilitator
- 6: https://www.openfacilitator.io/docs/api
🏁 Script executed:
find . -name "skale_payment.py" -o -name "*skale*" | head -20Repository: GetBindu/Bindu
Length of output: 102
🏁 Script executed:
cat -n ./examples/rag_router_agent/skale_payment.pyRepository: GetBindu/Bindu
Length of output: 2454
🏁 Script executed:
# Check how other config values are managed in the project
rg "os\.getenv|OPENROUTER_API_KEY|BINDU_DEPLOYMENT_URL" -A 2 -B 2 | head -50Repository: GetBindu/Bindu
Length of output: 3258
🏁 Script executed:
# Check if there are any imports of os in the examples directory
rg "^import os" examples/ | head -10Repository: GetBindu/Bindu
Length of output: 593
🏁 Script executed:
# Check how os is used in the rag_router_agent directory
rg "os\.getenv|os\." examples/rag_router_agent/ -B 1 -A 1Repository: GetBindu/Bindu
Length of output: 1088
GET to the base URL doesn't validate the x402 protocol; use a POST endpoint with a proper payload, and make the URL configurable.
The x402 facilitator specification (POST /verify and /settle with JSON payload) confirms three issues with this prototype:
-
Endpoint/method choice. x402 facilitators require
POSTto/verifyor/settlewith a payment payload—notGETto the base host. A bareGETwill return whatever the edge/load balancer serves (often 401, 404, or HTML), so the 401 this code treats as "reachable, auth required" isn't evidence the facilitator protocol works. The docstring claims to "simulate an x402 payment call," but this doesn't. If the intent is only a liveness check, rename the function and docstring; otherwise,POSTto/verifywith a stub payload would be a much more honest prototype. -
Configurability. The comment says the facilitator "can be swapped easily," but
FACILITATOR_URLis hardcoded. The rest of the project already usesos.getenv()forOPENROUTER_API_KEYandBINDU_DEPLOYMENT_URL(inagent.py). Read it from an environment variable with the current value as a default. -
Exception handling (minor). The catch-all
Exceptionat line 69 silently swallows programming errors. Specify the exception type or at least log it.
♻️ Suggested changes
+import logging
+import os
+
import requests
-# 🔗 Choose one facilitator (can be swapped easily)
-FACILITATOR_URL = "https://facilitator.x402.fi"
+logger = logging.getLogger(__name__)
+
+# 🔗 Choose one facilitator (can be swapped easily via env)
+FACILITATOR_URL = os.getenv("SKALE_FACILITATOR_URL", "https://facilitator.x402.fi")
def call_skale_facilitator() -> dict:
"""
- Minimal prototype for SKALE facilitator integration.
+ Liveness check for SKALE facilitator endpoint (not x402 protocol validation).and
except Exception as e:
+ logger.exception("Facilitator call failed")
return {
"status": "error",
"message": str(e)
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/rag_router_agent/skale_payment.py` around lines 4 - 55,
call_skale_facilitator currently issues a GET to a hardcoded FACILITATOR_URL and
treats 401 as proof of protocol reachability; change it to POST to the protocol
endpoint (e.g., "/verify") with a minimal x402-style JSON payload when the
intent is to simulate a payment verification (or alternatively rename the
function/docstring to a plain liveness check if you want only a GET), read
FACILITATOR_URL from an environment variable (os.getenv("FACILITATOR_URL",
"https://facilitator.x402.fi")) instead of hardcoding, and replace the broad
except Exception: with a narrower requests.exceptions.RequestException (or log
the caught exception) so programming errors aren't swallowed; update response
handling in call_skale_facilitator to inspect the POST response codes and body
accordingly.
|
Addressed review feedback:
Thanks for the detailed review! |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
examples/rag_router_agent/agent.py (2)
17-33: Module-level side effects make the file unimportable withoutOPENROUTER_API_KEY.Reading the env var and constructing
Agent(...)at import time means any tool that merely imports this module (tests, linters, docs generators, orbindufyintrospection) will fail withRuntimeErrorif the key is missing. Consider deferring construction into a small_get_agent()accessor (or lazily initializing on firsthandlercall) so the module is importable without secrets.♻️ Suggested refactor
-api_key = os.getenv("OPENROUTER_API_KEY") -if not api_key: - raise RuntimeError( - "OPENROUTER_API_KEY is not set. See examples/rag_router_agent/README.md." - ) - - -# 🤖 LLM setup (OpenRouter) -agent = Agent( - instructions="You are a helpful assistant that answers based only on the given context.", - model=OpenAIChat( - id="openai/gpt-4o-mini", - api_key=api_key, - base_url="https://openrouter.ai/api/v1" - ), -) +_agent = None + +def _get_agent() -> Agent: + global _agent + if _agent is None: + api_key = os.getenv("OPENROUTER_API_KEY") + if not api_key: + raise RuntimeError( + "OPENROUTER_API_KEY is not set. See examples/rag_router_agent/README.md." + ) + _agent = Agent( + instructions="You are a helpful assistant that answers based only on the given context.", + model=OpenAIChat( + id="openai/gpt-4o-mini", + api_key=api_key, + base_url="https://openrouter.ai/api/v1", + ), + ) + return _agent🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/rag_router_agent/agent.py` around lines 17 - 33, The module reads OPENROUTER_API_KEY and constructs Agent/OpenAIChat at import time which raises RuntimeError on import; refactor by moving the env read and Agent creation into a lazily-invoked accessor (e.g., create a function named _get_agent() that reads os.getenv("OPENROUTER_API_KEY"), validates it, constructs and returns Agent(model=OpenAIChat(...)) ), and update any callers (such as handler) to call _get_agent() at runtime instead of using a module-level api_key/Agent so the module can be imported without the secret.
99-101: Replaceexcept Exceptionwith logging, and narrow the catch if feasible.Using
except Exception. Preferlogging.exception(...)so stack traces are captured, and consider catching the specific exception typesagent.runcan raise (e.g.,agno/OpenAI client errors) while still having a final safety net.♻️ Suggested change
+import logging +logger = logging.getLogger(__name__) @@ - except Exception as e: - print(f"[ERROR] LLM call failed: {e}") - answer = "Error generating response. Please try again." + except Exception: # noqa: BLE001 — final safety net around external LLM call + logger.exception("LLM call failed") + answer = "Error generating response. Please try again."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/rag_router_agent/agent.py` around lines 99 - 101, Replace the print + bare except around the agent.run call with proper logging and narrower exception handling: import logging, catch the specific client/LLM errors that agent.run can raise (e.g., OpenAIError, HTTPError or the agent/SDK-specific exception classes) to handle known failures, and add a final broad except Exception as a safety net that calls logging.exception("LLM call failed") to capture the stack trace; ensure you still set answer = "Error generating response. Please try again." in the error handlers and reference the existing agent.run call and answer variable when applying the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@examples/rag_router_agent/agent.py`:
- Line 83: The call to the user-supplied domain function agent_fn(query,
context) in handler is unguarded and can raise exceptions; wrap the call to
agent_fn in a try/except, catch broad exceptions, set agent_response = "" on
error, and emit a warning or error log that includes the exception and
identifies the agent (e.g., finance_agent/legal_agent/tech_agent) and the
query/context for debugging; ensure subsequent logic that expects agent_response
still runs (matching the existing LLM-call error handling pattern used around
the LLM invocation).
- Around line 9-11: The top-level imports (skale_payment, router, retriever)
will break outside the example directory; update the imports to package-relative
imports (e.g., change to from .skale_payment import call_skale_facilitator, from
.router import classify_intent, route_db, route_agent, and from .retriever
import retrieve_docs), add an __init__.py to examples/rag_router_agent so the
package is importable, and ensure README / example instructions say to run the
example as a module (python -m examples.rag_router_agent.agent) or from the
package root.
---
Nitpick comments:
In `@examples/rag_router_agent/agent.py`:
- Around line 17-33: The module reads OPENROUTER_API_KEY and constructs
Agent/OpenAIChat at import time which raises RuntimeError on import; refactor by
moving the env read and Agent creation into a lazily-invoked accessor (e.g.,
create a function named _get_agent() that reads os.getenv("OPENROUTER_API_KEY"),
validates it, constructs and returns Agent(model=OpenAIChat(...)) ), and update
any callers (such as handler) to call _get_agent() at runtime instead of using a
module-level api_key/Agent so the module can be imported without the secret.
- Around line 99-101: Replace the print + bare except around the agent.run call
with proper logging and narrower exception handling: import logging, catch the
specific client/LLM errors that agent.run can raise (e.g., OpenAIError,
HTTPError or the agent/SDK-specific exception classes) to handle known failures,
and add a final broad except Exception as a safety net that calls
logging.exception("LLM call failed") to capture the stack trace; ensure you
still set answer = "Error generating response. Please try again." in the error
handlers and reference the existing agent.run call and answer variable when
applying the change.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: e9e78752-d886-4384-a6dc-9f3034fa8a09
📒 Files selected for processing (2)
examples/rag_router_agent/agent.pyexamples/rag_router_agent/retriever.py
🚧 Files skipped from review as they are similar to previous changes (1)
- examples/rag_router_agent/retriever.py
…LE docs clarification)
|
Addressed remaining feedback:
Please let me know if anything else should be adjusted. |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
docs/PAYMENT.md (3)
36-36: Optional: Clarify that x402 SDK already supports EVM chains.Step 1 mentions "Extend or confirm upstream x402 support for SKALE networks," but x402 already supports any EVM chain via CAIP-2 identifiers. Consider rephrasing to focus on confirming SKALE's CAIP-2 identifier (eip155:324705682) works with x402 and adding it to facilitator configurations.
📝 Suggested revision
-1. Extend or confirm upstream x402 support for SKALE networks +1. Confirm SKALE's CAIP-2 identifier (eip155:324705682) with x402 SDK🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/PAYMENT.md` at line 36, Update Step 1 to clarify that x402 already supports EVM chains via CAIP-2 identifiers and instruct readers to verify SKALE's CAIP-2 id works: explicitly state that x402 accepts CAIP-2 (e.g., eip155:324705682) and change the wording from "Extend or confirm upstream x402 support for SKALE networks" to something like "Confirm SKALE CAIP-2 compatibility (eip155:324705682) with x402 and add it to facilitator configurations"; ensure the note references CAIP-2 and the facilitator configuration entry so integrators know where to add the identifier.
27-30: Optional: Make facilitator-side gaps more explicit.The phrase "On the facilitator / SDK side" (line 27) could more explicitly distinguish what's missing. Since the SDK technically supports EVM chains via CAIP-2, the missing pieces are primarily facilitator-level configurations and endpoints. Consider rephrasing to emphasize that facilitators are the primary blocker.
📝 Suggested clarification
-On the facilitator / SDK side: -- Network definitions and mappings are not yet available +On the facilitator side: +- SKALE network configurations are not yet available in facilitator deployments - Facilitators do not yet expose SKALE-compatible endpoints - Full x402-compliant payment validation cannot be completed🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/PAYMENT.md` around lines 27 - 30, The heading/text "On the facilitator / SDK side" is ambiguous about where the missing functionality lives; update the sentence to explicitly state that the SDK already supports EVM (via CAIP-2) and that the missing pieces are facilitator-level artifacts (network definitions/mappings, SKALE-compatible endpoints, and x402 payment validation hooks) so readers understand facilitators—not the SDK—are the primary blocker; locate the phrase "On the facilitator / SDK side" in PAYMENT.md and replace it with a clarified sentence calling out "Facilitator-level gaps (SDK supports EVM via CAIP-2):" followed by the three bullet points as currently listed.
11-18: Consider clarifying "SDK configuration" vs facilitator-specific mappings.Line 12 states "the currently available facilitators and SDK configuration do not yet include" SKALE network mappings. Since x402 SDK supports any EVM chain via CAIP-2 (per previous review research), consider rephrasing to clarify that the SDK is capable but requires facilitator-specific configuration (chain ID, RPC endpoints, token contracts) that hasn't been provided yet. This would strengthen the SDK-vs-facilitator distinction established in the introduction.
📝 Suggested clarification
-While x402 is designed to support EVM-compatible chains, the currently available -facilitators and SDK configuration do not yet include: +While x402 is designed to support EVM-compatible chains via CAIP-2 identifiers, +the currently available facilitators do not yet include: - SKALE network mappings - SKALE chain ID configuration - Token metadata (e.g., USDC contract on SKALE)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/PAYMENT.md` around lines 11 - 18, Rephrase the sentence that currently reads "the currently available facilitators and SDK configuration do not yet include" to explicitly distinguish SDK capability from facilitator-specific setup: state that the x402 SDK supports EVM chains via CAIP-2 but the facilitator-side configuration (e.g., SKALE network mappings, SKALE chain ID, RPC endpoints, and token contract metadata like USDC) has not been provided; update the phrases "SDK configuration" and "facilitators" so the SDK is described as compatible while the missing items are attributed to facilitator-specific configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@docs/PAYMENT.md`:
- Line 36: Update Step 1 to clarify that x402 already supports EVM chains via
CAIP-2 identifiers and instruct readers to verify SKALE's CAIP-2 id works:
explicitly state that x402 accepts CAIP-2 (e.g., eip155:324705682) and change
the wording from "Extend or confirm upstream x402 support for SKALE networks" to
something like "Confirm SKALE CAIP-2 compatibility (eip155:324705682) with x402
and add it to facilitator configurations"; ensure the note references CAIP-2 and
the facilitator configuration entry so integrators know where to add the
identifier.
- Around line 27-30: The heading/text "On the facilitator / SDK side" is
ambiguous about where the missing functionality lives; update the sentence to
explicitly state that the SDK already supports EVM (via CAIP-2) and that the
missing pieces are facilitator-level artifacts (network definitions/mappings,
SKALE-compatible endpoints, and x402 payment validation hooks) so readers
understand facilitators—not the SDK—are the primary blocker; locate the phrase
"On the facilitator / SDK side" in PAYMENT.md and replace it with a clarified
sentence calling out "Facilitator-level gaps (SDK supports EVM via CAIP-2):"
followed by the three bullet points as currently listed.
- Around line 11-18: Rephrase the sentence that currently reads "the currently
available facilitators and SDK configuration do not yet include" to explicitly
distinguish SDK capability from facilitator-specific setup: state that the x402
SDK supports EVM chains via CAIP-2 but the facilitator-side configuration (e.g.,
SKALE network mappings, SKALE chain ID, RPC endpoints, and token contract
metadata like USDC) has not been provided; update the phrases "SDK
configuration" and "facilitators" so the SDK is described as compatible while
the missing items are attributed to facilitator-specific configuration.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 913f98d1-34a8-4e51-8153-45e3db1213ef
📒 Files selected for processing (3)
docs/PAYMENT.mdexamples/rag_router_agent/skale_payment.pyexamples/rag_router_agent/test_local.py
✅ Files skipped from review due to trivial changes (1)
- examples/rag_router_agent/test_local.py
🚧 Files skipped from review as they are similar to previous changes (1)
- examples/rag_router_agent/skale_payment.py
|
Addressed CI issues:
Should now pass across environments. |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
examples/rag_router_agent/test_local.py (1)
1-18: CI guard is in place; importingagentat module top still triggers side effects during pytest collection.The
__main__guard prevents the handler invocation during test discovery (addressing the prior review). However, because the file is still namedtest_local.py, pytest will import it during collection, which executesfrom agent import handlerand in turn runsagent.py's module-level code (env read,Agent(...)instantiation, warn print). This is low-risk but could be eliminated entirely by renaming to e.g.run_local.py(not collected by pytest) or moving the import insiderun_test().♻️ Optional tightening
-from agent import handler - - def run_test(): + from agent import handler + messages = [ {"role": "user", "content": "What is GST?"} ]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/rag_router_agent/test_local.py` around lines 1 - 18, The test module imports agent at top-level which triggers module-level side effects during pytest collection; to fix, remove the module-level import and instead import the handler inside run_test() (e.g., put "from agent import handler" as the first line of run_test()) so pytest collection won't execute agent.py, or alternatively rename this file so it is not prefixed with "test_" (e.g., run_local.py).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@examples/rag_router_agent/agent.py`:
- Around line 61-80: Early-return branches currently return via _base_response
when docs is empty or agent_fn is None without calling call_skale_facilitator,
causing payment to be null; fix by invoking call_skale_facilitator() before
those early returns and include its result in the _base_response payload so
every response path (including the docs-empty and agent_fn is None branches)
contains the facilitator reachability info (refer to call_skale_facilitator,
_base_response, route_agent, docs, agent_fn, intent, db_path to locate and
update the logic).
- Around line 100-111: The code may set answer = result.content (from agent.run)
which can be None and then call answer.strip(), causing AttributeError and
bypassing the fallback; update the logic around agent.run/result.content to
coerce non-string or None values to a safe string (e.g., use str(result.content)
or default to agent_response or "" when result.content is None), so that answer
is always a string before calling answer.strip(); ensure the except block still
assigns agent_response as fallback and that _base_response receives a safe
string for the answer.
---
Nitpick comments:
In `@examples/rag_router_agent/test_local.py`:
- Around line 1-18: The test module imports agent at top-level which triggers
module-level side effects during pytest collection; to fix, remove the
module-level import and instead import the handler inside run_test() (e.g., put
"from agent import handler" as the first line of run_test()) so pytest
collection won't execute agent.py, or alternatively rename this file so it is
not prefixed with "test_" (e.g., run_local.py).
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: eb806593-cd43-42dd-91d8-3bb3d56700f3
📒 Files selected for processing (2)
examples/rag_router_agent/agent.pyexamples/rag_router_agent/test_local.py
|
Validated full flow locally:
All review points addressed. Ready for final review. |
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
examples/rag_router_agent/test_local.py (1)
1-5:⚠️ Potential issue | 🟡 MinorRemove the remaining top-level
agentimport.
test_local.pyis still discoverable as a test file, and Line 1 importsagent.pyduring collection. That can initialize optional LLM dependencies even though the actual run is guarded. Keep the import insiderun_test()only.🧪 Proposed fix
-from agent import handler - - def run_test(): - from agent import handler # ✅ moved inside + try: + from .agent import handler + except ImportError: + from agent import handler🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/rag_router_agent/test_local.py` around lines 1 - 5, Remove the remaining top-level import of the agent module so importing happens only inside the guarded runner: delete the top-level "from agent import handler" and ensure the only import of agent.handler is the one inside the run_test() function (function name: run_test), and verify there are no other module-level references to agent in this file so test discovery won't import agent during collection.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@examples/rag_router_agent/agent.py`:
- Around line 104-115: The code calls agent.run(final_prompt) even when no
OpenRouter key is configured; change the flow to skip the LLM refinement when
the global api_key (OPENROUTER_API_KEY) is empty: before calling
agent.run(final_prompt) check if api_key is truthy, and if not set answer =
agent_response directly (no try/except or external call); if api_key is present,
proceed with the existing try block that invokes agent.run, extracts content
(getattr(result, "content", None)), and falls back to str(result) or
agent_response as currently implemented.
---
Duplicate comments:
In `@examples/rag_router_agent/test_local.py`:
- Around line 1-5: Remove the remaining top-level import of the agent module so
importing happens only inside the guarded runner: delete the top-level "from
agent import handler" and ensure the only import of agent.handler is the one
inside the run_test() function (function name: run_test), and verify there are
no other module-level references to agent in this file so test discovery won't
import agent during collection.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9aaeea5f-d8fd-404e-bfde-b0f77fae98a8
📒 Files selected for processing (2)
examples/rag_router_agent/agent.pyexamples/rag_router_agent/test_local.py
|
Final fixes applied:
Should now be clean across CI and local runs. |
Summary
Adds a SKALE facilitator integration prototype to the RAG router agent, with a controlled fallback bypass due to current x402 SDK limitations.
Problem
The intended flow was:
Bindu agent → x402 SDK → SKALE facilitator → response
However, during implementation:
x402Python package does not expose chain/network mappingsWhat I tried
Solution (Implemented)
Switched to a controlled bypass approach:
Bindu agent → simulated x402 layer → SKALE facilitator → response
This allows:
What changed
skale_payment.pyto interact with SKALE facilitatorsWhat did NOT change
User-visible changes
Agent response now includes:
{ "payment": { "status": "reachable", "code": 401, "note": "Authentication required (expected for prototype)" } }Why this matters
Verification
Steps
Result
Risks
External dependency on facilitator endpoint
Checklist
Summary by CodeRabbit
Documentation
New Features