Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 8 additions & 23 deletions nodes/src/nodes/accessibility_describe/accessibility_vision.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@

# Spatial format prompt modifiers
SPATIAL_PROMPTS = {
'clock': '\n\nUse clock positions for spatial references (12 o\'clock = straight ahead).',
'clock': "\n\nUse clock positions for spatial references (12 o'clock = straight ahead).",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use single quotes for regular string literals in nodes/**/*.py.

These two updated literals switched to double quotes and now diverge from the node-level quote convention.

Proposed quote-style fix
-    'clock': "\n\nUse clock positions for spatial references (12 o'clock = straight ahead).",
+    'clock': '\n\nUse clock positions for spatial references (12 o\'clock = straight ahead).',
...
-            return f"Model '{self._model}' is currently unavailable. Please try a different model."
+            return f'Model \'{self._model}\' is currently unavailable. Please try a different model.'
As per coding guidelines, `nodes/**/*.py`: Python pipeline nodes: use single quotes, ruff for linting/formatting, PEP 257 docstrings, target Python 3.10+.

Also applies to: 147-147

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nodes/src/nodes/accessibility_describe/accessibility_vision.py` at line 70,
Replace the double-quoted regular string literal used as the value for the
'clock' key with a single-quoted literal (i.e., change "\"\\n\\nUse clock
positions for spatial references (12 o'clock = straight ahead).\"" to a
single-quoted version) to match the module's quote convention; also locate and
convert the other double-quoted regular string literal noted in the review (the
second similar occurrence in this module) to single quotes so all regular string
literals in accessibility_vision.py follow the project's single-quote style.

'relative': '\n\nUse relative directions (left, right, ahead, behind) for spatial references.',
'both': '\n\nUse both clock positions and relative directions for spatial references.',
}
Expand Down Expand Up @@ -98,31 +98,18 @@ def __init__(self, provider: str, connConfig: dict[str, Any], bag: dict[str, Any
spatial_format = config.get('accessibility.spatialFormat', 'clock')

# Build system prompt with config modifiers
self._system_prompt = (
config.get('accessibility.systemPrompt')
or config.get('systemPrompt')
or DEFAULT_SYSTEM_PROMPT
)
self._system_prompt = config.get('accessibility.systemPrompt') or config.get('systemPrompt') or DEFAULT_SYSTEM_PROMPT
self._system_prompt += HAZARD_PROMPTS.get(hazard_priority, '')
self._system_prompt += SPATIAL_PROMPTS.get(spatial_format, '')

self._prompt = (
config.get('accessibility.prompt')
or config.get('prompt')
or DEFAULT_PROMPT
)
self._prompt = config.get('accessibility.prompt') or config.get('prompt') or DEFAULT_PROMPT

if not api_key:
raise ValueError(
'Missing Google AI API key. Get one at https://aistudio.google.com/apikey'
)
raise ValueError('Missing Google AI API key. Get one at https://aistudio.google.com/apikey')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

TRY003 warnings remain on long inline ValueError messages.

Ruff is still flagging these lines; consider moving message text to named constants or a dedicated exception type to keep raises concise and consistent.

Also applies to: 112-112, 189-189

🧰 Tools
🪛 Ruff (0.15.7)

[warning] 108-108: Avoid specifying long messages outside the exception class

(TRY003)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nodes/src/nodes/accessibility_describe/accessibility_vision.py` at line 108,
Replace the long inline raise messages with a named constant or a dedicated
exception to satisfy TRY003: create a module-level constant (e.g.,
MISSING_GOOGLE_AI_API_KEY_MSG) or a custom exception class (e.g.,
MissingGoogleAPIKeyError) in accessibility_vision.py and use that constant/class
in the three raise sites where ValueError is raised (the current inline raises
around the Google AI API key checks). Keep the raise calls concise (raise
ValueError(MISSING_GOOGLE_AI_API_KEY_MSG) or raise MissingGoogleAPIKeyError) so
the message text is centralized and the raises are short.


# Validate the API key format
if api_key.startswith('sk-'):
raise ValueError(
'Invalid API key format. This appears to be an OpenAI key. '
'Please provide a Google AI API key.'
)
raise ValueError('Invalid API key format. This appears to be an OpenAI key. Please provide a Google AI API key.')

try:
self._client = genai.Client(api_key=api_key)
Expand Down Expand Up @@ -157,7 +144,7 @@ def _format_user_error(self, error_msg: str) -> str:
if any(phrase in error_lower for phrase in ['invalid input', 'bad request', '400']):
return 'Invalid input. Please check your image format and prompt.'
if any(phrase in error_lower for phrase in ['model not found', 'unavailable', 'not supported']):
return f'Model \'{self._model}\' is currently unavailable. Please try a different model.'
return f"Model '{self._model}' is currently unavailable. Please try a different model."
if any(phrase in error_lower for phrase in ['timeout', 'timed out']):
return 'Request timed out. Please try again.'
if any(phrase in error_lower for phrase in ['content policy', 'safety', 'blocked']):
Expand Down Expand Up @@ -199,9 +186,7 @@ def chat(self, question: Question) -> Answer:
mime_type = header.split(':')[1].split(';')[0]
image_bytes = base64.b64decode(b64_data)
except (ValueError, IndexError, base64.binascii.Error) as e:
raise ValueError(
'Malformed image data URL. Expected format: data:<mime>;base64,<data>'
) from e
raise ValueError('Malformed image data URL. Expected format: data:<mime>;base64,<data>') from e

# Build request contents once (deterministic, no need to rebuild per retry)
contents = [
Expand Down Expand Up @@ -233,7 +218,7 @@ def chat(self, question: Question) -> Answer:
except Exception as e:
last_error = e
if attempt < max_retries and self._shouldRetry(e):
delay = base_delay * (2 ** attempt)
delay = base_delay * (2**attempt)
time.sleep(delay)
continue
break
Expand Down
7 changes: 1 addition & 6 deletions nodes/src/nodes/agent_crewai/crewai.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,7 @@ def _invoke_tool(tool_name: str, input: Any = None, kwargs: Optional[Dict[str, A
agent_obj = Agent(
role='Assistant',
goal='Solve the user request using available tools when helpful.',
backstory=(
'You are an agent node in a tool-invocation hierarchy. '
'You may call tools wired to you via the host tools interface. '
'When a tool is needed, call it; otherwise respond directly. '
'Follow any additional instructions exactly.'
),
backstory=('You are an agent node in a tool-invocation hierarchy. You may call tools wired to you via the host tools interface. When a tool is needed, call it; otherwise respond directly. Follow any additional instructions exactly.'),
tools=tools_for_agent,
llm=llm,
verbose=False,
Expand Down
1 change: 0 additions & 1 deletion nodes/src/nodes/agent_langchain/IInstance.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,3 @@ def invoke(self, param: Any) -> Any: # noqa: ANN401
if isinstance(op, str) and op.startswith('tool.'):
return self.IGlobal.agent.handle_invoke(self, param)
return super().invoke(param)

3 changes: 1 addition & 2 deletions nodes/src/nodes/agent_langchain/langchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def _llm_type(self) -> str:
def _identifying_params(self) -> Dict[str, Any]:
return {'framework': 'rocketride', 'adapter': 'tool_calling_json'}

def bind_tools(self, tools: Any, **kwargs: Any) -> "RocketRideToolCallingChatModel":
def bind_tools(self, tools: Any, **kwargs: Any) -> 'RocketRideToolCallingChatModel':
try:
self._bound_tools = _normalize_bound_tools(tools)
except Exception:
Expand Down Expand Up @@ -448,4 +448,3 @@ def _safe_str(v: Any) -> str:
return '' if v is None else str(v)
except Exception:
return ''

1 change: 1 addition & 0 deletions nodes/src/nodes/agent_rocketride/IGlobal.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def beginGlobal(self) -> None:
config handling is needed here.
"""
from .rocketride_agent import RocketRideDriver

self.agent = RocketRideDriver(self)

def endGlobal(self) -> None:
Expand Down
30 changes: 18 additions & 12 deletions nodes/src/nodes/agent_rocketride/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
# Structural summary (_describe)
# ---------------------------------------------------------------------------


def _describe(value: Any, depth: int = 0) -> str:
"""Return a compact structural summary of *value* for LLM context.

Expand Down Expand Up @@ -118,9 +119,7 @@ def _describe(value: Any, depth: int = 0) -> str:
if isinstance(first, dict):
# Collect field names from up to 5 rows to handle sparse rows
# where early rows may be missing fields that appear later.
keys = list(dict.fromkeys(
k for row in value[:5] if isinstance(row, dict) for k in row
))
keys = list(dict.fromkeys(k for row in value[:5] if isinstance(row, dict) for k in row))
lines = [f'{n} items, fields: {keys}']
# Show first 2 rows as sample data so the LLM can see real values
for i, row in enumerate(value[:2]):
Expand Down Expand Up @@ -152,6 +151,7 @@ def _describe_dict(d: dict, depth: int) -> str:
# Template resolution
# ---------------------------------------------------------------------------


def _memory_get(key: str, host: AgentHost) -> Any:
"""Fetch a raw value from the memory store.

Expand Down Expand Up @@ -298,6 +298,7 @@ def resolve_answer_refs(answer: str, host: AgentHost) -> str:
# Wave result storage
# ---------------------------------------------------------------------------


def _auto_key(wave_name: str, idx: int) -> str:
"""Generate a memory key scoped to a wave and call index.

Expand Down Expand Up @@ -335,6 +336,7 @@ def _store_and_preview(tool: str, key: str, result: Any, host: AgentHost) -> Dic
# Wave executor
# ---------------------------------------------------------------------------


def _execute_wave_calls(
wave: List[Dict[str, Any]],
*,
Expand All @@ -356,10 +358,7 @@ def _execute_wave_calls(

# Tag each call with its auto-generated memory key before parallelism so
# the key assignment is deterministic and order-preserving.
tagged: List[Dict[str, Any]] = [
{**call, '_key': _auto_key(wave_name, i)}
for i, call in enumerate(wave)
]
tagged: List[Dict[str, Any]] = [{**call, '_key': _auto_key(wave_name, i)} for i, call in enumerate(wave)]

def _run_one(call: Dict[str, Any]) -> Dict[str, Any]:
"""Execute a single tool call and return a result dict."""
Expand Down Expand Up @@ -411,8 +410,11 @@ def _run_one(call: Dict[str, Any]) -> Dict[str, Any]:
total_items = len(value)
preview = json.dumps(value[:_PEEK_MAX_ARRAY_ITEMS], ensure_ascii=False)
return {
'tool': tool, 'key': key, 'path': path,
'preview': preview, 'truncated': True,
'tool': tool,
'key': key,
'path': path,
'preview': preview,
'truncated': True,
'returned_items': _PEEK_MAX_ARRAY_ITEMS,
'total_items': total_items,
}
Expand All @@ -426,10 +428,14 @@ def _run_one(call: Dict[str, Any]) -> Dict[str, Any]:
value = json.dumps(value, ensure_ascii=False, indent=2)
offset = int(args.get('offset', 0))
length = int(args.get('length', _PEEK_DEFAULT_LENGTH))
chunk = value[offset:offset + length]
chunk = value[offset : offset + length]
return {
'tool': tool, 'key': key, 'preview': chunk,
'offset': offset, 'length': len(chunk), 'total_chars': len(value),
'tool': tool,
'key': key,
'preview': chunk,
'offset': offset,
'length': len(chunk),
'total_chars': len(value),
}

# Regular tool — route through the host's tool pipeline which
Expand Down
1 change: 1 addition & 0 deletions nodes/src/nodes/agent_rocketride/rocketride_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
# Can be overridden via the ``max_waves`` node configuration field.
_DEFAULT_MAX_WAVES = 10


class RocketRideDriver(AgentBase):
"""
RocketRide Wave framework driver.
Expand Down
13 changes: 4 additions & 9 deletions nodes/src/nodes/anonymize/IInstance.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,10 @@

class IInstance(IInstanceBase):
IGlobal: IGlobal # Reference to a global context providing recognizer functionality

# Default PII labels for zero-shot NER when no classifications provided
DEFAULT_PII_LABELS = [
'person', 'name', 'email', 'phone number', 'address',
'social security number', 'credit card number', 'date of birth',
'organization', 'company', 'location', 'ip address',
'bank account', 'passport number', 'driver license'
]

DEFAULT_PII_LABELS = ['person', 'name', 'email', 'phone number', 'address', 'social security number', 'credit card number', 'date of birth', 'organization', 'company', 'location', 'ip address', 'bank account', 'passport number', 'driver license']
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether DEFAULT_PII_LABELS is mutated anywhere (should return no mutation sites).
rg -n -C2 "DEFAULT_PII_LABELS\s*(\[|\=|\.append|\.extend|\.remove|\.pop|\.clear|\[.*\]\s*=)" nodes/src/nodes/anonymize/IInstance.py nodes/src/nodes/anonymize

Repository: rocketride-org/rocketride-server

Length of output: 247


🏁 Script executed:

# First, let me examine the file structure and context around line 32
cat -n nodes/src/nodes/anonymize/IInstance.py | head -50

Repository: rocketride-org/rocketride-server

Length of output: 2840


🏁 Script executed:

# Search for DEFAULT_PII_LABELS usage and potential mutations with simpler, corrected patterns
rg -n "DEFAULT_PII_LABELS" nodes/src/nodes/anonymize/

Repository: rocketride-org/rocketride-server

Length of output: 530


🏁 Script executed:

# Check for mutations via append, extend, remove, pop, clear, or direct assignment
rg -n "\.append\(|\.extend\(|\.remove\(|\.pop\(|\.clear\(" nodes/src/nodes/anonymize/IInstance.py

Repository: rocketride-org/rocketride-server

Length of output: 58


🏁 Script executed:

# Search the entire anonymize directory for DEFAULT_PII_LABELS mutations or reassignment
rg -n "DEFAULT_PII_LABELS" nodes/src/nodes/anonymize/ -A 2 -B 2

Repository: rocketride-org/rocketride-server

Length of output: 1109


🏁 Script executed:

# Check if there are any attempts to modify the list through indexing or methods
rg -n "DEFAULT_PII_LABELS\[|DEFAULT_PII_LABELS\.pop|DEFAULT_PII_LABELS\.remove|DEFAULT_PII_LABELS\.append|DEFAULT_PII_LABELS\.extend|DEFAULT_PII_LABELS\.clear" nodes/src/nodes/anonymize/

Repository: rocketride-org/rocketride-server

Length of output: 58


Avoid mutable class-level default for DEFAULT_PII_LABELS.

Line 32 defines a mutable list at class scope; while no mutations are currently made in the codebase, accidental mutation would leak across instances. Prefer an immutable tuple constant.

🛡️ Proposed fix
-    DEFAULT_PII_LABELS = ['person', 'name', 'email', 'phone number', 'address', 'social security number', 'credit card number', 'date of birth', 'organization', 'company', 'location', 'ip address', 'bank account', 'passport number', 'driver license']
+    DEFAULT_PII_LABELS = (
+        'person',
+        'name',
+        'email',
+        'phone number',
+        'address',
+        'social security number',
+        'credit card number',
+        'date of birth',
+        'organization',
+        'company',
+        'location',
+        'ip address',
+        'bank account',
+        'passport number',
+        'driver license',
+    )
📝 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.

Suggested change
DEFAULT_PII_LABELS = ['person', 'name', 'email', 'phone number', 'address', 'social security number', 'credit card number', 'date of birth', 'organization', 'company', 'location', 'ip address', 'bank account', 'passport number', 'driver license']
DEFAULT_PII_LABELS = (
'person',
'name',
'email',
'phone number',
'address',
'social security number',
'credit card number',
'date of birth',
'organization',
'company',
'location',
'ip address',
'bank account',
'passport number',
'driver license',
)
🧰 Tools
🪛 Ruff (0.15.7)

[warning] 32-32: Mutable default value for class attribute

(RUF012)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nodes/src/nodes/anonymize/IInstance.py` at line 32, The class-level
DEFAULT_PII_LABELS is defined as a mutable list on IInstance; replace it with an
immutable tuple (e.g., DEFAULT_PII_LABELS = ('person', 'name', ...)) to prevent
accidental cross-instance mutation, and update any usages or type hints that
expect a list to accept a tuple (or convert with list(...) at use sites) so
behavior remains the same while the constant stays immutable.


#
# Current object context properties
#
Expand All @@ -59,7 +54,7 @@ def closing(self):
if not self.has_classifications:
# No classifications received - anonymize with default PII labels
self.target_object_text = self.IGlobal.recognizer.process(self.target_object_text, self.DEFAULT_PII_LABELS)

# Resume the writeText lane
self.instance.writeText(self.target_object_text)

Expand Down
1 change: 1 addition & 0 deletions nodes/src/nodes/anonymize/anonymize.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
# SOFTWARE.
# =============================================================================


def anonymize(text: str, matches, anonymize_char: str = '*') -> str:
"""Replace specified segments with a sequence of anonymization characters.

Expand Down
25 changes: 11 additions & 14 deletions nodes/src/nodes/anonymize/glinerRecognizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class GliNERRecognizer:
def __init__(self, provider: str, connConfig: Dict[str, Any], bag: Dict[str, Any]):
"""
Initialize the GLiNER Recognizer.

Uses ai.common.models.GLiNER which automatically routes to model server
if --modelserver flag is present, otherwise runs locally.
"""
Expand All @@ -50,7 +50,7 @@ def __init__(self, provider: str, connConfig: Dict[str, Any], bag: Dict[str, Any
enginePath = expand('%execPath%')
rule_file_path = os.path.join(enginePath, 'nucleuz', 'rulePack.dat')
self.ruleParser = RuleParser(rule_file_path)

# Use ai.common.models.GLiNER - auto-detects local vs model server mode
self.model = GLiNER(self.model_name)

Expand Down Expand Up @@ -182,34 +182,34 @@ def process_chunk(chunk_idx):
def process(self, text: str, labels: list, existing_matches: list = None) -> str:
"""
Core anonymization method - detects entities using GLiNER and masks them.

Args:
text: The text to anonymize
labels: Entity labels to detect
existing_matches: Optional list of (offset, length) tuples from classifications

Returns:
Anonymized text with detected entities replaced by anonymize_char
"""
if not text:
return text

# Run NER prediction
ner_results = self.predict(text, labels)
ner_matches = self.convert_ner_results_to_matches(ner_results)

debug(f'Anonymize: Detected {len(ner_results)} entities')

# Combine with existing matches (from classifications)
all_matches = list(existing_matches or []) + ner_matches

if not all_matches:
debug('Anonymize: No entities to mask')
return text

# Sort by offset and apply masking
all_matches_sorted = sorted(all_matches, key=lambda x: x[0])

return _anonymize(text, all_matches_sorted, self.anonymize_char)

def handleClassifications(self, classifications: dict, target_object_text: str, classificationPolicy: any, classificationRules: any):
Expand All @@ -234,9 +234,6 @@ def handleClassifications(self, classifications: dict, target_object_text: str,
labels = self.ruleParser.get_rules_names(unique_id_refs) + rules

# Extract existing matches from classifications (offset, length tuples)
existing_matches = list(
(m['offset'], m['length'])
for m in ((m.get('location', {}).get('inChars') or m) for m in text_matches)
)
existing_matches = list((m['offset'], m['length']) for m in ((m.get('location', {}).get('inChars') or m) for m in text_matches))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the exact pattern and nearby context for C400-style constructions.
rg -n -C2 "existing_matches\s*=\s*list\(" nodes/src/nodes/anonymize/glinerRecognizer.py

Repository: rocketride-org/rocketride-server

Length of output: 388


Rewrite existing_matches as a direct list comprehension to comply with Ruff C400.

Use [(m['offset'], m['length']) for m in ...] instead of wrapping the comprehension with list().

♻️ Proposed cleanup
-        existing_matches = list((m['offset'], m['length']) for m in ((m.get('location', {}).get('inChars') or m) for m in text_matches))
+        existing_matches = [(m['offset'], m['length']) for m in ((m.get('location', {}).get('inChars') or m) for m in text_matches)]
📝 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.

Suggested change
existing_matches = list((m['offset'], m['length']) for m in ((m.get('location', {}).get('inChars') or m) for m in text_matches))
existing_matches = [(m['offset'], m['length']) for m in ((m.get('location', {}).get('inChars') or m) for m in text_matches)]
🧰 Tools
🪛 Ruff (0.15.7)

[warning] 237-237: Unnecessary generator (rewrite as a list comprehension)

Rewrite as a list comprehension

(C400)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nodes/src/nodes/anonymize/glinerRecognizer.py` at line 237, Replace the
wrapped generator-to-list expression assigning existing_matches with a direct
list comprehension to satisfy Ruff C400; update the assignment that currently
uses list((... for ...)) to use [(m['offset'], m['length']) for m in
((m.get('location', {}).get('inChars') or m) for m in text_matches)] so
existing_matches is a plain list of tuples derived from text_matches (keep the
inner fallback logic using m.get('location', {}).get('inChars') or m).


return self.process(target_object_text, labels, existing_matches)
5 changes: 1 addition & 4 deletions nodes/src/nodes/audio_transcribe/IGlobal.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,7 @@ def transcribe(self, audio: Any) -> List[SimpleNamespace]:
)

segments = result.get('$segments') or []
return [
SimpleNamespace(text=s.get('text', ''), start=s.get('start', 0.0), end=s.get('end', 0.0))
for s in segments
]
return [SimpleNamespace(text=s.get('text', ''), start=s.get('start', 0.0), end=s.get('end', 0.0)) for s in segments]

def _audio_to_pcm_bytes(self, audio: Any) -> bytes:
"""Convert audio (bytes or float32 numpy) to PCM int16 bytes (16 kHz mono)."""
Expand Down
1 change: 0 additions & 1 deletion nodes/src/nodes/autopipe/IGlobal.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ def isSet(key: str):
providerStore, configStore = Config.getMultiProviderConfig('store', autopipeConfig)
pushLocal(getFilter('vector_1', providerStore, configStore))


pass

# Now, add all the filters we figured out
Expand Down
4 changes: 1 addition & 3 deletions nodes/src/nodes/chart_chartjs/IInstance.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ def invoke(self, param: Any) -> Any: # noqa: ANN401
if driver._llm_invoke is None:
llm_invoker = _make_llm_invoker(self.instance)
if llm_invoker is None:
raise RuntimeError(
'Chart generator requires an LLM node connected to the pipeline.'
)
raise RuntimeError('Chart generator requires an LLM node connected to the pipeline.')
driver.set_llm_invoker(llm_invoker)

return driver.handle_invoke(param)
Loading
Loading