-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat(node): add Nebius Agentic Search (llm_nebius + tool_tavily) #1050
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
EdwardLien0426
wants to merge
16
commits into
rocketride-org:develop
from
EdwardLien0426:feat/RR-1047-nebius-agentic-search
+1,327
−0
Closed
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
1019878
docs(nebius_search): add design spec for Nebius Agentic Search node
eebc900
docs(nebius_search): rewrite spec to compose-existing-infra approach …
a577b79
docs(nebius_search): add step-by-step implementation plan
4ae8c0e
feat(tool_tavily_search): scaffold Tavily web-search tool node
29fbbf5
feat(tool_tavily_search): implement Tavily search tool with retry + S…
46819a2
feat(llm_nebius): add Nebius Token Factory LLM provider node
c86711e
feat(examples): add Nebius Agentic Search pipeline template
1734e6b
docs(nodes): document tool_tavily_search and llm_nebius
22e586f
fix(tool_tavily_search): isolate test sys.modules stubs to prevent cr…
59fd146
chore: remove internal planning docs from the PR set
3781aba
fix(nebius_search): gate dynamic node tests on API keys; address revi…
30d8c74
chore: re-trigger CI (unrelated flaky TS client test on Ubuntu/Windows)
44c6e1a
docs(tool_tavily_search): align test-block comment with the requires …
78fd9a1
refactor(tool_tavily): rename node tool_tavily_search -> tool_tavily
c3d1665
refactor(tool_tavily): drop redundant "search" from name and tool method
3bd0a31
chore: re-trigger CI (known-flaky RocketRideClient teardown on Ubuntu)
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| { | ||
| "name": "Nebius Agentic Search", | ||
| "description": "A web-research agent powered by Nebius (Llama 3.3 70B) and Tavily real-time search. Ask any question and the agent will search the web, refine its queries, and return a cited answer.", | ||
| "components": [ | ||
| { | ||
| "id": "chat_1", | ||
| "provider": "chat", | ||
| "name": "Trigger", | ||
| "config": { | ||
| "hideForm": true, | ||
| "mode": "Source", | ||
| "parameters": {}, | ||
| "type": "chat" | ||
| }, | ||
| "ui": { | ||
| "position": { | ||
| "x": 20, | ||
| "y": 200 | ||
| }, | ||
| "measured": { | ||
| "width": 150, | ||
| "height": 66 | ||
| }, | ||
| "nodeType": "default", | ||
| "formDataValid": true | ||
| } | ||
| }, | ||
| { | ||
| "id": "agent_deepagent_1", | ||
| "provider": "agent_deepagent", | ||
| "name": "Nebius Agentic Search", | ||
| "config": { | ||
| "instructions": [ | ||
| "You are an agentic web-research assistant.", | ||
| "Use the tavily tool to find current information; refine your query and search again when results are weak.", | ||
| "Cite the source URLs you used and answer concisely." | ||
| ], | ||
| "parameters": {} | ||
| }, | ||
| "ui": { | ||
| "position": { | ||
| "x": 240, | ||
| "y": 200 | ||
| }, | ||
| "measured": { | ||
| "width": 150, | ||
| "height": 86 | ||
| }, | ||
| "nodeType": "default", | ||
| "formDataValid": true | ||
| }, | ||
| "input": [ | ||
| { | ||
| "lane": "questions", | ||
| "from": "chat_1" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "id": "llm_nebius_1", | ||
| "provider": "llm_nebius", | ||
| "name": "Nebius LLM", | ||
| "config": { | ||
| "profile": "llama-3-3-70b", | ||
| "llama-3-3-70b": { | ||
| "apikey": "${NEBIUS_API_KEY}" | ||
| }, | ||
| "parameters": {} | ||
| }, | ||
| "ui": { | ||
| "position": { | ||
| "x": 130, | ||
| "y": 380 | ||
| }, | ||
| "measured": { | ||
| "width": 150, | ||
| "height": 66 | ||
| }, | ||
| "nodeType": "default", | ||
| "formDataValid": true | ||
| }, | ||
| "control": [ | ||
| { | ||
| "classType": "llm", | ||
| "from": "agent_deepagent_1" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "id": "tool_tavily_1", | ||
| "provider": "tool_tavily", | ||
| "name": "Tavily", | ||
| "config": { | ||
| "apikey": "${TAVILY_API_KEY}", | ||
| "maxResults": 5, | ||
| "searchDepth": "advanced", | ||
| "topic": "general" | ||
| }, | ||
| "ui": { | ||
| "position": { | ||
| "x": 350, | ||
| "y": 380 | ||
| }, | ||
| "measured": { | ||
| "width": 150, | ||
| "height": 37 | ||
| }, | ||
| "nodeType": "default", | ||
| "formDataValid": true | ||
| }, | ||
| "control": [ | ||
| { | ||
| "classType": "tool", | ||
| "from": "agent_deepagent_1" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "id": "response_answers_1", | ||
| "provider": "response_answers", | ||
| "config": { | ||
| "laneName": "answers" | ||
| }, | ||
| "ui": { | ||
| "position": { | ||
| "x": 447, | ||
| "y": 222 | ||
| }, | ||
| "measured": { | ||
| "width": 150, | ||
| "height": 66 | ||
| }, | ||
| "nodeType": "default", | ||
| "formDataValid": true | ||
| }, | ||
| "input": [ | ||
| { | ||
| "lane": "answers", | ||
| "from": "agent_deepagent_1" | ||
| } | ||
| ] | ||
| } | ||
| ], | ||
| "source": "chat_1", | ||
| "project_id": "c5ba857f-30ff-4f3d-b5bf-9ee90d3ee33b", | ||
| "viewport": { | ||
| "x": 15.5, | ||
| "y": -120.9, | ||
| "zoom": 1.04 | ||
| }, | ||
| "version": 1, | ||
| "docRevision": 1 | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| # ============================================================================= | ||
| # MIT License | ||
| # Copyright (c) 2026 Aparavi Software AG | ||
| # | ||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| # of this software and associated documentation files (the "Software"), to deal | ||
| # in the Software without restriction, including without limitation the rights | ||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| # copies of the Software, and to permit persons to whom the Software is | ||
| # furnished to do so, subject to the following conditions: | ||
| # | ||
| # The above copyright notice and this permission notice shall be included in | ||
| # all copies or substantial portions of the Software. | ||
| # | ||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| # SOFTWARE. | ||
| # ============================================================================= | ||
|
|
||
| import os | ||
| from typing import Optional | ||
| from rocketlib import IGlobalBase, warning | ||
| from ai.common.config import Config | ||
| from ai.common.chat import ChatBase | ||
|
|
||
|
|
||
| class IGlobal(IGlobalBase): | ||
| """Global handler for the Nebius Token Factory LLM node.""" | ||
|
|
||
| _chat: Optional[ChatBase] = None | ||
|
|
||
| _VALIDATION_PROMPT = 'Hi' | ||
| _BASE_URL = 'https://api.tokenfactory.nebius.com/v1/' | ||
|
|
||
| def _resolve_apikey(self, config) -> str: | ||
| return str(config.get('apikey') or os.environ.get('NEBIUS_API_KEY', '')).strip() | ||
|
|
||
| def validateConfig(self): | ||
| """Probe the model with a 1-token request to validate key + model at save time.""" | ||
| from depends import depends # type: ignore | ||
|
|
||
| requirements = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'requirements.txt') | ||
| depends(requirements) | ||
|
|
||
| try: | ||
| from openai import ( | ||
| OpenAI, | ||
| APIStatusError, | ||
| OpenAIError, | ||
| AuthenticationError, | ||
| RateLimitError, | ||
| APIConnectionError, | ||
| ) | ||
|
|
||
| config = Config.getNodeConfig(self.glb.logicalType, self.glb.connConfig) | ||
| apikey = self._resolve_apikey(config) | ||
| model = config.get('model') | ||
| if not model or not apikey: | ||
| return | ||
| try: | ||
| client = OpenAI(api_key=apikey, base_url=self._BASE_URL) | ||
| client.chat.completions.create( | ||
| model=model, | ||
| messages=[{'role': 'user', 'content': self._VALIDATION_PROMPT}], | ||
| max_tokens=1, | ||
| ) | ||
| except RateLimitError: | ||
| return | ||
| except APIStatusError as e: | ||
| status = getattr(e, 'status_code', None) or getattr(e, 'status', None) | ||
| if status == 429: | ||
| return | ||
| warning(f'Nebius validation error {status}: {e}') | ||
| return | ||
| except (AuthenticationError, APIConnectionError, OpenAIError) as e: | ||
| warning(str(e)) | ||
| return | ||
| except Exception as e: | ||
| warning(str(e)) | ||
|
|
||
| def beginGlobal(self): | ||
| """Initialize the Nebius chat client.""" | ||
| from depends import depends # type: ignore | ||
|
|
||
| requirements = os.path.dirname(os.path.realpath(__file__)) + '/requirements.txt' | ||
| depends(requirements) | ||
|
|
||
| from .nebius import Chat | ||
|
|
||
| bag = self.IEndpoint.endpoint.bag | ||
| config = Config.getNodeConfig(self.glb.logicalType, self.glb.connConfig) | ||
| if not self._resolve_apikey(config): | ||
| raise ValueError('Nebius API key is required.') | ||
| self._chat = Chat(self.glb.logicalType, config, bag) | ||
|
|
||
| def endGlobal(self): | ||
| self._chat = None |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # ============================================================================= | ||
| # MIT License | ||
| # Copyright (c) 2026 Aparavi Software AG | ||
| # | ||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| # of this software and associated documentation files (the "Software"), to deal | ||
| # in the Software without restriction, including without limitation the rights | ||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| # copies of the Software, and to permit persons to whom the Software is | ||
| # furnished to do so, subject to the following conditions: | ||
| # | ||
| # The above copyright notice and this permission notice shall be included in | ||
| # all copies or substantial portions of the Software. | ||
| # | ||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| # SOFTWARE. | ||
| # ============================================================================= | ||
|
|
||
| from ai.common.llm_base import LLMBase | ||
|
|
||
|
|
||
| class IInstance(LLMBase): | ||
| pass |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| --- | ||
| title: Nebius | ||
| date: 2026-06-01 | ||
| sidebar_position: 1 | ||
| --- | ||
|
|
||
| <head> | ||
| <title>Nebius - RocketRide Documentation</title> | ||
| </head> | ||
|
|
||
| ## What it does | ||
|
|
||
| Connects Nebius Token Factory-hosted models to your pipeline via an OpenAI-compatible API. The base URL is fixed at `https://api.tokenfactory.nebius.com/v1/` — no endpoint configuration needed. Used primarily as an `llm` invoke connection by agents (including Nebius Agentic Search) and other nodes that need an LLM. Can also be used directly via lanes. | ||
|
|
||
| **Lanes:** | ||
|
|
||
| | Lane in | Lane out | Description | | ||
| | ----------- | --------- | ---------------------------------------------------- | | ||
| | `questions` | `answers` | Send a question directly, receive a generated answer | | ||
|
|
||
| ## Configuration | ||
|
|
||
| | Field | Description | | ||
| | ------- | ----------------------------------------------- | | ||
| | Model | Model profile or custom model ID (see below) | | ||
| | API Key | Nebius Token Factory API key (`NEBIUS_API_KEY`) | | ||
|
|
||
| The API key can be supplied via the node's **API Key** field or the `NEBIUS_API_KEY` environment variable. | ||
|
|
||
| ## Model profiles | ||
|
|
||
| | Profile | Model ID | Context | | ||
| | -------------------------- | --------------------------------------- | ------- | | ||
| | Llama 3.3 70B _(default)_ | `meta-llama/Llama-3.3-70B-Instruct` | 131,072 | | ||
| | Qwen3 235B | `Qwen/Qwen3-235B-A22B` | 131,072 | | ||
| | DeepSeek V3 | `deepseek-ai/DeepSeek-V3` | 131,072 | | ||
| | Custom | any Token Factory model ID | 131,072 | | ||
|
|
||
| **Custom** — specify any Nebius Token Factory model ID and token limit directly. | ||
|
|
||
| ## Upstream docs | ||
|
|
||
| - [Nebius Token Factory model catalogue](https://tokenfactory.nebius.com/models) | ||
| - [Nebius AI documentation](https://docs.nebius.com) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| # ============================================================================= | ||
| # MIT License | ||
| # Copyright (c) 2026 Aparavi Software AG | ||
| # | ||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| # of this software and associated documentation files (the "Software"), to deal | ||
| # in the Software without restriction, including without limitation the rights | ||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| # copies of the Software, and to permit persons to whom the Software is | ||
| # furnished to do so, subject to the following conditions: | ||
| # | ||
| # The above copyright notice and this permission notice shall be included in | ||
| # all copies or substantial portions of the Software. | ||
| # | ||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| # SOFTWARE. | ||
| # ============================================================================= | ||
|
|
||
| from .IGlobal import IGlobal | ||
| from .IInstance import IInstance | ||
|
|
||
|
|
||
| def getChat(): | ||
| """Get the Chat class from the module.""" | ||
| from .nebius import Chat | ||
|
|
||
| return Chat | ||
|
|
||
|
|
||
| __all__ = [ | ||
| 'IGlobal', | ||
| 'IInstance', | ||
| 'getChat', | ||
| ] |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial | 💤 Low value
Consider omitting the hardcoded
project_idin the example pipeline.The
project_idfield 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
🤖 Prompt for AI Agents