feat(node): add Nebius Agentic Search (llm_nebius + tool_tavily)#1050
feat(node): add Nebius Agentic Search (llm_nebius + tool_tavily)#1050EdwardLien0426 wants to merge 16 commits into
Conversation
Self-contained agentic search node mirroring search_exa: a Nebius Token Factory LLM runs a bounded native-function-calling loop over an internal Tavily web-search tool and returns a cited answer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(Shape B) Build Nebius Agentic Search by composing the engine's existing agent pattern: new tool_tavily_search + new llm_nebius (Token Factory) wired into the existing agent_deepagent loop, plus a pipeline template. Chosen over a self-contained bundled-LLM node because every agent in the repo is built this way and it reuses a battle-tested loop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…SRF guard Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Scaffolds llm_nebius as an OpenAI-compatible LLM provider pointing at https://api.tokenfactory.nebius.com/v1/ with profiles for Llama 3.3 70B (default), Qwen3 235B, DeepSeek V3, and a custom slot.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…oss-test contamination The unit-test bootstrap stubbed rocketlib/ai.common/requests via sys.modules.setdefault but never removed them. Under the full `builder nodes:test-full` run (shared pytest session, xdist workers) the leaked MagicMock stubs overrode the real modules for sibling node tests, causing 27 spurious failures in tool_git and tool_filesystem (real on this branch, absent on develop). Now stubs are injected only when missing and dropped immediately after importing the module under test, so nothing leaks into the shared session. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The design spec and implementation plan under docs/superpowers/ are internal workflow artifacts (and carry author/personal info); they are not part of the shippable node deliverable. Remove them so the PR contains only the two nodes, the example pipeline, the node-registry doc entry, and tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
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:
📝 WalkthroughWalkthroughAdds two new nodes: ChangesNebius LLM Provider Node
Tavily Search Tool Node
Documentation and Example Pipeline
Sequence Diagram: Nebius Agentic Search (high-level) sequenceDiagram
participant User
participant ChatTrigger as chat_1
participant Agent as agent_deepagent_1
participant Nebius as llm_nebius_1
participant Tavily as tool_tavily_1
participant Response as response_answers_1
User->>ChatTrigger: submit query
ChatTrigger->>Agent: questions lane
Agent->>Nebius: reasoning / generate search queries
Agent->>Tavily: invoke search tool (query)
Tavily-->>Agent: search results (filtered)
Agent->>Nebius: refine + answer
Nebius-->>Agent: concise answer with citations
Agent->>Response: answers lane
Response-->>User: present answer
Estimated code review effort: Suggested reviewers:
🚥 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)
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 |
|
No description provided. |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@examples/nebius-agentic-search.pipe`:
- Line 94: Remove the redundant config.type property from the
tool_tavily_search_1 component since tool_tavily_search reads only apikey,
maxResults, searchDepth and topic and the server-side
PipelineConfig::encryptComponent will derive type from provider when config.type
is absent; edit the tool_tavily_search_1 config to drop the "type" field so only
the required fields remain, leaving provider (if present) intact for type
derivation.
In `@nodes/src/nodes/tool_tavily_search/requirements.txt`:
- Line 1: The Tavily node's requirements file lists a bare "requests" causing
inconsistent resolution; update the shared baseline
nodes/src/nodes/requirements.txt to specify a consistent minimum (e.g.
requests>=2.34.2) and make the Tavily file
(nodes/src/nodes/tool_tavily_search/requirements.txt) match that same lower
bound (or remove the duplicate if you want the baseline to be authoritative) so
both files reference the same requests>=2.34.2 baseline and avoid
scanner/old-version drift.
In `@nodes/test/test_tool_tavily_search.py`:
- Around line 100-109: The test test_shape_results_maps_tavily_fields is doing a
real DNS lookup because _shape_results calls _validate_public_url which uses
socket.getaddrinfo; stub out DNS in the test by monkeypatching
socket.getaddrinfo (or monkeypatching the module's _validate_public_url to
always allow the example URL) before calling mod._shape_results so the result
isn't dropped—ensure the monkeypatch returns a harmless truthy response
consistent with getaddrinfo's expected return type, then call _shape_results and
run the existing assertions.
🪄 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: 33e85298-f9ac-4faa-83e6-1877c7c33060
⛔ Files ignored due to path filters (2)
nodes/src/nodes/llm_nebius/nebius.svgis excluded by!**/*.svgnodes/src/nodes/tool_tavily_search/tavily.svgis excluded by!**/*.svg
📒 Files selected for processing (16)
docs/README-nodes.mdexamples/nebius-agentic-search.pipenodes/src/nodes/llm_nebius/IGlobal.pynodes/src/nodes/llm_nebius/IInstance.pynodes/src/nodes/llm_nebius/README.mdnodes/src/nodes/llm_nebius/__init__.pynodes/src/nodes/llm_nebius/nebius.pynodes/src/nodes/llm_nebius/requirements.txtnodes/src/nodes/llm_nebius/services.jsonnodes/src/nodes/tool_tavily_search/IGlobal.pynodes/src/nodes/tool_tavily_search/IInstance.pynodes/src/nodes/tool_tavily_search/README.mdnodes/src/nodes/tool_tavily_search/__init__.pynodes/src/nodes/tool_tavily_search/requirements.txtnodes/src/nodes/tool_tavily_search/services.jsonnodes/test/test_tool_tavily_search.py
| @@ -0,0 +1 @@ | |||
| requests | |||
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# How do sibling tool/search nodes declare the requests dependency?
fd 'requirements.txt' nodes/src/nodes --exec sh -c 'echo "== $1 =="; grep -i requests "$1"' _ {}Repository: rocketride-org/rocketride-server
Length of output: 4300
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the shared requirements file and look for any version pins for requests
targets=(
"nodes/src/nodes/requirements.txt"
)
for f in "${targets[@]}"; do
if [ -f "$f" ]; then
echo "==== $f ===="
nl -ba "$f" | sed -n '1,120p'
else
echo "Missing $f"
fi
done
# Look for requests version pins in nodes/src (requirements/constraints/lock files)
rg -n --hidden -S "(requests\s*[<>=!]=\s*|requests==|requests>=)" nodes/src || true
rg -n --hidden -S "(constraints|constraint).*requirements" -g'*.txt' . || true
# Find common pip lock/constraints files at repo root
ls -la | head -n 50
find . -maxdepth 3 -type f \( -iname '*constraints*.txt' -o -iname '*requirements*.txt' -o -iname '*requirements*.in' -o -iname '*poetry*.lock' -o -iname '*pipfile*' \) | head -n 200Repository: rocketride-org/rocketride-server
Length of output: 181
🏁 Script executed:
#!/bin/bash
set -euo pipefail
targets=("nodes/src/nodes/requirements.txt")
for f in "${targets[@]}"; do
if [ -f "$f" ]; then
echo "==== $f ===="
nl -ba "$f" | sed -n '1,120p'
else
echo "Missing $f"
fi
done
rg -n -S "(requests\s*[<>=!]=\s*|requests==|requests>=)" . || true
find . -maxdepth 4 -type f \( -iname '*constraints*.txt' -o -iname '*requirements*.txt' -o -iname '*requirements*.in' -o -iname '*poetry.lock' -o -iname '*Pipfile*' -o -iname 'poetry*.lock' \) | head -n 200Repository: rocketride-org/rocketride-server
Length of output: 180
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "==== nodes/src/nodes/requirements.txt (first 120 lines) ===="
if [ -f "nodes/src/nodes/requirements.txt" ]; then
cat -n "nodes/src/nodes/requirements.txt" | sed -n '1,120p'
else
echo "Missing nodes/src/nodes/requirements.txt"
fi
echo
echo "==== Any explicit requests pins/constraints anywhere in repo ===="
rg -n -S "(^|\s)requests\s*(==|>=|<=|!=|<|>)" . -g'*.txt' || true
rg -n -S "(constraints|constraint).*requests" . -g'*.txt' || true
echo
echo "==== Candidate constraints/lock files (top 3 levels) ===="
find . -maxdepth 5 -type f \( -iname '*constraints*.txt' -o -iname '*requirements*.txt' -o -iname '*requirements*.in' -o -iname '*pipfile*' -o -iname 'poetry*.lock' \) | head -n 200
echo
echo "==== Contents of any constraints*.txt/requirements*.txt that mention requests (top 50 matches) ===="
rg -n -S "requests" . -g'*constraints*.txt' -g'*requirements*.txt' -m 50 || trueRepository: rocketride-org/rocketride-server
Length of output: 5852
Align requests version pinning to repo convention (prefer shared baseline).
nodes/src/nodes/tool_tavily_search/requirements.txt uses bare requests, and the shared baseline nodes/src/nodes/requirements.txt also uses bare requests (only nodes/src/nodes/tool_github/requirements.txt pins requests>=2.34.2). If you’re trying to prevent OSV/CVE scanner noise and block old requests resolution, apply a consistent lower bound (preferably in nodes/src/nodes/requirements.txt, e.g. requests>=2.34.2) rather than pinning only the Tavily node.
🧰 Tools
🪛 OSV Scanner (2.3.8)
[HIGH] 1-1: requests 2.9.2: undefined
(PYSEC-2018-28)
[HIGH] 1-1: requests 2.9.2: undefined
(PYSEC-2023-74)
[HIGH] 1-1: requests 2.9.2: Requests vulnerable to .netrc credentials leak via malicious URLs
[HIGH] 1-1: requests 2.9.2: Requests Session object does not verify requests after making first request with verify=False
[HIGH] 1-1: requests 2.9.2: Requests has Insecure Temp File Reuse in its extract_zipped_paths() utility function
[HIGH] 1-1: requests 2.9.2: Unintended leak of Proxy-Authorization header in requests
[HIGH] 1-1: requests 2.9.2: Insufficiently Protected Credentials in Requests
🤖 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_tavily_search/requirements.txt` at line 1, The Tavily
node's requirements file lists a bare "requests" causing inconsistent
resolution; update the shared baseline nodes/src/nodes/requirements.txt to
specify a consistent minimum (e.g. requests>=2.34.2) and make the Tavily file
(nodes/src/nodes/tool_tavily_search/requirements.txt) match that same lower
bound (or remove the duplicate if you want the baseline to be authoritative) so
both files reference the same requests>=2.34.2 baseline and avoid
scanner/old-version drift.
…ew nits CI 'Test' step ran the services.json dynamic tests for both nodes with no API key (no NEBIUS_API_KEY/TAVILY_API_KEY in CI), and beginGlobal raises when the key is missing -> RuntimeError. Add 'requires' to both test blocks so the dynamic test is filtered out at collection when the key env var is absent (matches llm_openai/llm_ollama/rerank_cohere). Also addresses CodeRabbit review: - test_shape_results: stub socket.getaddrinfo so it is network-independent. - examples/.pipe: drop redundant config.type (server derives type from provider). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
nodes/src/nodes/tool_tavily_search/services.json (1)
118-133:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
requires: ["TAVILY_API_KEY"]contradicts this test case's documented intent.The comment at Lines 118-122 explains this case deliberately runs with no apikey so
validateConfigemits a warning (not an error), exercising config validation without live API calls. Gating it behind"requires": ["TAVILY_API_KEY"]means it is now filtered out in keyless CI — so the keyless validation path it was designed to cover no longer runs there. Either drop therequiresgate (and keep this as a true no-key validation case) or update the comment to reflect that the case now expects the key to be present.🤖 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_tavily_search/services.json` around lines 118 - 133, The test entry named "Config validation with placeholder key" documents that it should run without an API key to exercise validateConfig's warning path, but the test object includes requires: ["TAVILY_API_KEY"] which prevents keyless CI runs; remove the requires gate from the "test" object (or alternatively update the comment to state the test now requires a key) so the test either truly runs keyless to exercise validateConfig or the documentation matches the new requirement; reference the "test" JSON block and the requires field and validateConfig behavior when making the change.
🤖 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.
Outside diff comments:
In `@nodes/src/nodes/tool_tavily_search/services.json`:
- Around line 118-133: The test entry named "Config validation with placeholder
key" documents that it should run without an API key to exercise
validateConfig's warning path, but the test object includes requires:
["TAVILY_API_KEY"] which prevents keyless CI runs; remove the requires gate from
the "test" object (or alternatively update the comment to state the test now
requires a key) so the test either truly runs keyless to exercise validateConfig
or the documentation matches the new requirement; reference the "test" JSON
block and the requires field and validateConfig behavior when making the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 09cb55e9-447d-4824-a75a-50f4f2ad1f38
📒 Files selected for processing (4)
examples/nebius-agentic-search.pipenodes/src/nodes/llm_nebius/services.jsonnodes/src/nodes/tool_tavily_search/services.jsonnodes/test/test_tool_tavily_search.py
💤 Files with no reviewable changes (1)
- examples/nebius-agentic-search.pipe
No code change. The previous run's failure was tests/RocketRideClient.test.ts (client-typescript disconnect teardown leak), unrelated to this PR's Python nodes; macOS passed. Empty commit to re-run CI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…gate The 'test' case comment claimed it runs keyless to exercise validateConfig, but the dynamic test builds+runs the node (calls beginGlobal, which needs a key) and the block now carries requires:[TAVILY_API_KEY]. Update the comment to state the case is skipped without the key, and rename it accordingly. Addresses CodeRabbit. (Contract tests still cover structure keyless.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the redundant _search suffix from the node id/provider (the agent tool method is still tavily_search). Updates the directory, services.json protocol/path/field keys, IGlobal messages, README, the example pipeline (provider + component id), the node-registry doc, and the unit-test module. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename the agent tool method tavily_search -> tavily and the display name "Tavily Search" -> "Tavily" (Tavily is a search tool, so the suffix is redundant). The agent trace now shows tool_tavily_1.tavily. Also completes the node-id rename that 78fd9a1 captured only as file moves: this carries the in-file content edits (services.json protocol/path/field keys, IGlobal messages, README, example pipeline, node-registry doc, unit-test module) from tool_tavily_search -> tool_tavily. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@examples/nebius-agentic-search.pipe`:
- Line 145: The example pipeline contains a hardcoded "project_id" value that
ties the template to a specific UUID; remove the "project_id":
"c5ba857f-30ff-4f3d-b5bf-9ee90d3ee33b" entry from the
examples/nebius-agentic-search.pipe example (or replace it with a short comment
like // set your project_id here) so the example is generic and copy-paste
ready; locate the "project_id" key in the JSON block and either delete that line
or change it to a placeholder/comment accordingly.
In `@nodes/src/nodes/tool_tavily/IGlobal.py`:
- Around line 55-59: The apikey selection currently does cfg.get('apikey') or
os.environ.get(...) then .strip(), which treats whitespace-only cfg values as
truthy and prevents falling back to TAVILY_API_KEY; change beginGlobal() (and
the similar logic in validateConfig()) to strip each candidate first (e.g.,
cfg_apikey = (cfg.get('apikey') or '').strip(), env_apikey =
os.environ.get('TAVILY_API_KEY','').strip()) and then set apikey = cfg_apikey or
env_apikey so a whitespace-only configured key no longer blocks the environment
variable fallback and the error message is accurate.
In `@nodes/src/nodes/tool_tavily/IInstance.py`:
- Around line 159-162: _request_with_retry currently only retries
requests.exceptions.Timeout and thus treats requests.exceptions.ConnectionError
as a fatal requests.RequestException; update _request_with_retry to include
requests.exceptions.ConnectionError (and/or broaden to retry
requests.RequestException where appropriate) in its retryable exceptions list
and ensure the retry/backoff logic in _request_with_retry (referenced by the
call in the try block where body = _request_with_retry(...)) handles
ConnectionError the same way as Timeout so connection-level transport failures
are retried rather than immediately returning an error.
🪄 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: 8c87c376-3a94-481a-8439-c4eaca637000
📒 Files selected for processing (7)
docs/README-nodes.mdexamples/nebius-agentic-search.pipenodes/src/nodes/tool_tavily/IGlobal.pynodes/src/nodes/tool_tavily/IInstance.pynodes/src/nodes/tool_tavily/README.mdnodes/src/nodes/tool_tavily/services.jsonnodes/test/test_tool_tavily.py
| } | ||
| ], | ||
| "source": "chat_1", | ||
| "project_id": "c5ba857f-30ff-4f3d-b5bf-9ee90d3ee33b", |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | 💤 Low value
Consider omitting the hardcoded project_id in the example pipeline.
The project_id field is optional and ties the example to a specific project UUID. For an example that users may copy, omitting this field would make the template more immediately usable without requiring users to replace the ID. Alternatively, a comment could indicate that users should set their own project ID.
📝 Optional simplification
],
"source": "chat_1",
- "project_id": "c5ba857f-30ff-4f3d-b5bf-9ee90d3ee33b",
"viewport": {📝 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.
| "project_id": "c5ba857f-30ff-4f3d-b5bf-9ee90d3ee33b", | |
| ], | |
| "source": "chat_1", | |
| "viewport": { | |
| "x": 0, | |
| "y": 0, | |
| "zoom": 1 | |
| }, | |
| "version": 1, | |
| "docRevision": 1 | |
| } |
🤖 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 `@examples/nebius-agentic-search.pipe` at line 145, The example pipeline
contains a hardcoded "project_id" value that ties the template to a specific
UUID; remove the "project_id": "c5ba857f-30ff-4f3d-b5bf-9ee90d3ee33b" entry from
the examples/nebius-agentic-search.pipe example (or replace it with a short
comment like // set your project_id here) so the example is generic and
copy-paste ready; locate the "project_id" key in the JSON block and either
delete that line or change it to a placeholder/comment accordingly.
| apikey = str(cfg.get('apikey') or os.environ.get('TAVILY_API_KEY', '')).strip() | ||
|
|
||
| if not apikey: | ||
| error('tool_tavily: apikey is required — set it in node config or TAVILY_API_KEY env var') | ||
| raise ValueError('tool_tavily: apikey is required') |
There was a problem hiding this comment.
Strip the configured key before falling back to TAVILY_API_KEY.
A whitespace-only apikey is truthy, so the current cfg.get('apikey') or ... path wins and then .strip() turns it into ''. In that case beginGlobal() still raises even when TAVILY_API_KEY is set, so the new message overstates the fallback behavior. validateConfig() has the same bug.
Suggested fix
- apikey = str(cfg.get('apikey') or os.environ.get('TAVILY_API_KEY', '')).strip()
+ cfg_apikey = str(cfg.get('apikey') or '').strip()
+ env_apikey = str(os.environ.get('TAVILY_API_KEY', '')).strip()
+ apikey = cfg_apikey or env_apikey
@@
- apikey = str(cfg.get('apikey') or os.environ.get('TAVILY_API_KEY', '')).strip()
+ cfg_apikey = str(cfg.get('apikey') or '').strip()
+ env_apikey = str(os.environ.get('TAVILY_API_KEY', '')).strip()
+ apikey = cfg_apikey or env_apikeyAlso applies to: 73-76
🤖 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_tavily/IGlobal.py` around lines 55 - 59, The apikey
selection currently does cfg.get('apikey') or os.environ.get(...) then .strip(),
which treats whitespace-only cfg values as truthy and prevents falling back to
TAVILY_API_KEY; change beginGlobal() (and the similar logic in validateConfig())
to strip each candidate first (e.g., cfg_apikey = (cfg.get('apikey') or
'').strip(), env_apikey = os.environ.get('TAVILY_API_KEY','').strip()) and then
set apikey = cfg_apikey or env_apikey so a whitespace-only configured key no
longer blocks the environment variable fallback and the error message is
accurate.
| try: | ||
| body = _request_with_retry(url=TAVILY_API_URL, headers=headers, payload=payload) | ||
| except RuntimeError as exc: | ||
| return {'success': False, 'query': query, 'num_results': 0, 'results': [], 'error': str(exc)} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo 'Inspect the retry branches in the Tavily helper:'
rg -n -A6 -B3 'except requests\.exceptions\.Timeout|except requests\.RequestException|requests\.post|time\.sleep' nodes/src/nodes/tool_tavily/IInstance.py
echo
echo 'Check whether the Tavily tests cover ConnectionError retries yet:'
fd -i 'test_tool_tavily.py' nodes/test --exec rg -n -A2 -B2 'ConnectionError|Timeout|429|500|retry' {}Repository: rocketride-org/rocketride-server
Length of output: 2345
Retry connection-level transport failures in _request_with_retry
_request_with_retry()retries onlyrequests.exceptions.Timeout;requests.exceptions.ConnectionErrorfalls intorequests.RequestExceptionand fails immediately (lines ~247-258).- Tavily tests mock
requests.exceptions.Timeout/requests.exceptions.RequestExceptionbut don’t exercise aConnectionErrorretry path.
Suggested fix
- except requests.exceptions.Timeout:
+ except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as exc:
if attempt < max_retries:
delay = base_delay * (2**attempt)
- debug(f'Tavily request timeout, retrying in {delay}s ({attempt + 1}/{max_retries})')
+ debug(
+ f'Tavily transport error ({type(exc).__name__}), retrying in {delay}s '
+ f'({attempt + 1}/{max_retries})'
+ )
time.sleep(delay)
continue
- raise RuntimeError('Tavily: request timed out after all retries') from None
+ raise RuntimeError(
+ f'Tavily: request failed after all retries ({type(exc).__name__})'
+ ) from None🤖 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_tavily/IInstance.py` around lines 159 - 162,
_request_with_retry currently only retries requests.exceptions.Timeout and thus
treats requests.exceptions.ConnectionError as a fatal requests.RequestException;
update _request_with_retry to include requests.exceptions.ConnectionError
(and/or broaden to retry requests.RequestException where appropriate) in its
retryable exceptions list and ensure the retry/backoff logic in
_request_with_retry (referenced by the call in the try block where body =
_request_with_retry(...)) handles ConnectionError the same way as Timeout so
connection-level transport failures are retried rather than immediately
returning an error.
No code change. The previous run failed only on Ubuntu in RocketRideClient.test.ts afterEach teardown (a pre-existing flaky integration-test disconnect race); macOS + Windows passed. This PR touches zero client-typescript files. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Superseded — split into two focused PRs per review feedback (land the LLM provider first, then the search tool):
Both target |
Superseded by #1071 + #1072 (originally targeted #1047 — closing keyword moved to #1072).
What
Adds Nebius Agentic Search by composing the engine's existing agent pattern — no new agent loop:
llm_nebius— Nebius Token Factory LLM provider node (OpenAI-compatible, fixed base URLhttps://api.tokenfactory.nebius.com/v1/,NEBIUS_API_KEYenv fallback). Cloned fromllm_gmi_cloud.tool_tavily— Tavily real-time web search exposed as an agent tool (POST https://api.tavily.com/search, retry + SSRF guard,TAVILY_API_KEYenv fallback). Cloned fromtool_exa_search.agent_deepagentto drive the LLM↔tool loop.examples/nebius-agentic-search.pipe— template wiring chat → agent_deepagent ← llm_nebius + tool_tavily.Why this shape
Every agent node in the repo (
agent_deepagent/crewai/langchain/rocketride) drives a wiredllm+toolchannel; there is no precedent for a self-contained node bundling its own LLM loop, and the engine's LLM seam is text-only. Composing existing infra reuses a battle-tested loop and keeps the change small (the only substantive new code is the Tavily tool).Verification
builder nodes:test— 670 passed / 0 failed.tavily→ reasoned again → returned a correct, grounded answer.Notes
meta-llama/Llama-3.3-70B-Instruct, configurable); search runs on Tavily (Nebius-acquired). Both require their own API key.classType:llm_nebius→ LLM group,tool_tavily→ Tools group.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests