Skip to content

fix: @Bartok9 contributions#824

Open
maciejmajek wants to merge 16 commits into
mainfrom
bartok9/fixes
Open

fix: @Bartok9 contributions#824
maciejmajek wants to merge 16 commits into
mainfrom
bartok9/fixes

Conversation

@maciejmajek

@maciejmajek maciejmajek commented Jul 22, 2026

Copy link
Copy Markdown
Member

Purpose

Salvaging all the fixes into one single PR to simplify CI process.

Proposed Changes

What does this PR add, remove or fix?

Issues

  • Links to relevant issues

Testing

  • How was it tested, what were the results?

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of custom artifact database paths, including automatic file and directory creation.
    • ROS2 discovery now matches names consistently with or without leading slashes.
    • Unexpected log levels no longer cause aggregation failures.
    • Image-difference summaries now report the original image buffer size accurately.
  • Validation

    • Added clear errors for invalid timeouts, buffer sizes, worker counts, agent lists, and other configuration values.
  • Tests

    • Expanded coverage for validation, ROS2 edge cases, artifact persistence, and aggregator behavior.
  • Chores

    • Updated the package version to 2.12.2 and corrected wording in tests and comments.

@maciejmajek
maciejmajek marked this pull request as ready for review July 22, 2026 10:44
@maciejmajek

Copy link
Copy Markdown
Member Author

@Bartok9 once again thanks for the contributions. I'm planning to merge this first batch of fixes and then proceed with the other PRs. Would you mind taking a look at CI errors?

@Bartok9

Bartok9 commented Jul 22, 2026

Copy link
Copy Markdown

Thanks @maciejmajek — happy to help, and glad these are going in! 🙏

I dug into the two CI failures. Both are small and here are the exact fixes:

1. check-license-lines — one file is missing the header:
tests/communication/__init__.py (currently empty). Adding the standard Apache header (same as the sibling __init__.py files) clears it:

# Copyright (C) 2025 Robotec.AI
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

2. build-and-test-ros2 (humble + jazzy) — one stale test:
tests/communication/ros2/test_ros2_async.py::test_get_future_result_zero_timeout still asserts None, but #808 (in this batch) intentionally makes get_future_result reject non-positive timeout_sec with ValueError. The pre-existing edge-case test just needs to align with the new (intended) behavior:

 def test_get_future_result_zero_timeout():
-    """Test with zero timeout."""
+    """Test that a zero timeout is rejected as non-positive."""
     future = Future()
-    result = get_future_result(future, timeout_sec=0.0)
-    assert result is None
+    with pytest.raises(ValueError, match="timeout_sec must be positive"):
+        get_future_result(future, timeout_sec=0.0)

Since the salvage branch lives on RobotecAI/rai, I can't push to it directly — I've committed both fixes on my end (520f5ad) if it's easier to cherry-pick, or feel free to apply the two snippets above. Let me know if you'd prefer I re-open these as a fresh PR from my fork instead. 🎻

@maciejmajek

Copy link
Copy Markdown
Member Author

@Bartok9 Please create a PR for these fixes. Thanks!

@Bartok9

Bartok9 commented Jul 22, 2026

Copy link
Copy Markdown

Done! Opened #826 with both CI fixes (license header + zero-timeout test alignment). I based it on this bartok9/fixes branch so the #808 rejection is in scope — happy to retarget or squash however is cleanest for you. Thanks again @maciejmajek! 🙏

@maciejmajek

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The change adds validation for invalid configuration and timeout values, rejects empty agent collections, normalizes ROS2 entity names, fixes artifact database path usage, improves aggregator edge-case handling, and adds corresponding tests. Package metadata and spelling are also corrected.

Changes

Validation and edge-case corrections

Layer / File(s) Summary
Agent configuration and runner validation
src/rai_core/rai/agents/..., tests/agents/...
Agent sizes, callback buffers, state-based configuration values, and agent collections now reject invalid inputs with explicit exceptions and test coverage.
Aggregator bounds and rendering corrections
src/rai_core/rai/aggregators/..., tests/aggregators/...
Aggregator size validation, unknown log-level rendering, and original image-buffer count reporting are updated and tested.
ROS2 communication validation and normalization
src/rai_core/rai/communication/..., tests/communication/...
Timeouts and callback worker counts are validated, while ROS2 entity matching normalizes leading slashes.
Artifact database path handling
src/rai_core/rai/messages/artifacts.py, tests/messages/test_artifacts_db_path.py
Artifact reads and writes consistently use the supplied database path and create missing directories and files.
CLI timeout validation
src/rai_core/rai/tools/ros2/cli.py, tests/tools/test_ros2_cli_timeout.py
CLI timeout validation runs before timer creation, with offline tests covering invalid values and the successful path.
Version and naming updates
src/rai_core/pyproject.toml, src/rai_bench/rai_bench/test_models.py, tests/rai_bench/...
The package version is bumped to 2.12.2, and spelling in a comment and test name is corrected.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • RobotecAI/rai#450: Introduced the HRICallbackHandler validation area updated here.
  • RobotecAI/rai#524: Introduced the runner module receiving empty-agent validation.
  • RobotecAI/rai#529: Introduced StateBasedConfig, which receives positive-value validators here.

Suggested reviewers: rachwalk

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is missing substantive Proposed Changes, Issues, and Testing details required by the template. Fill in the Proposed Changes, Issues, and Testing sections with concrete bullets and test results.
Docstring Coverage ⚠️ Warning Docstring coverage is 19.30% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is too generic and doesn't describe the actual fixes in the PR. Rename it to summarize the main change, e.g. validation fixes and test/license updates.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bartok9/fixes

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 7

🧹 Nitpick comments (1)
src/rai_core/rai/tools/ros2/cli.py (1)

25-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align the annotation with the accepted timeout values.

The validation accepts floats, and the happy-path test passes 1.0, but timeout_sec is annotated as int. Change the annotation to int | float or reject floats so static and runtime contracts agree.

🤖 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 `@src/rai_core/rai/tools/ros2/cli.py` around lines 25 - 30, Update the
timeout_sec annotation in the affected ROS2 CLI function to int | float,
matching its existing runtime validation and float-based happy path. Preserve
the current rejection of booleans and other non-numeric values.
🤖 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 `@src/rai_core/rai/agents/langchain/agent.py`:
- Around line 118-119: Update the max_size validation in the surrounding agent
initialization logic to require a positive int that is not a bool, rejecting
values such as True and 1.5 while preserving the existing error for non-positive
values. Add regression tests covering both invalid non-integer cases.

In `@src/rai_core/rai/agents/langchain/state_based_agent.py`:
- Around line 45-50: Update the _time_interval_positive validator to reject any
non-finite value by checking math.isfinite(v) alongside the existing
positive-value condition, while preserving the current error behavior for
invalid intervals. Add a regression test covering NaN input.

In `@src/rai_core/rai/aggregators/base.py`:
- Around line 31-32: Use one non-boolean positive-integer validation contract
for buffer sizes: update the constructor validation in
src/rai_core/rai/aggregators/base.py lines 31-32 to reject booleans and
non-integer max_size values while preserving None as unbounded; apply the same
validation to the bounded buffer-size check in
src/rai_core/rai/agents/langchain/agent.py lines 118-119, explicitly preserving
its existing None sentinel behavior.

In `@src/rai_core/rai/communication/ros2/api/action.py`:
- Around line 155-165: Update timeout validation in action.py lines 155-165 and
ros_async.py lines 29-30 to reject non-finite values at both API entry points,
while preserving rejection of non-positive values and booleans. Use the existing
validation paths and ensure valid positive finite numbers remain accepted.

In `@src/rai_core/rai/communication/ros2/waiters.py`:
- Around line 33-34: Update the timeout-reporting calculation in the waiter flow
to compare normalized entity names consistently, matching the normalized
requested_set and available_set built from ensure_slash. Reuse the normalized
available set when determining missing entities so names available without a
leading slash are not reported as missing.

In `@src/rai_core/rai/messages/artifacts.py`:
- Around line 29-33: Update store_artifacts in
src/rai_core/rai/messages/artifacts.py to create path.parent with parents=True
and exist_ok=True before opening the database file. In
tests/messages/test_artifacts_db_path.py, remove the test’s db.parent.mkdir call
so the test exercises production directory creation.

In `@src/rai_core/rai/tools/ros2/cli.py`:
- Around line 25-30: Update the timeout_sec validation in the ROS2 CLI timeout
handling to reject non-finite numeric values by checking
math.isfinite(timeout_sec) alongside the existing type and positive-value
checks. Preserve the current TypeError behavior for invalid types and raise the
appropriate validation error before creating the Timer for NaN or infinity.

---

Nitpick comments:
In `@src/rai_core/rai/tools/ros2/cli.py`:
- Around line 25-30: Update the timeout_sec annotation in the affected ROS2 CLI
function to int | float, matching its existing runtime validation and
float-based happy path. Preserve the current rejection of booleans and other
non-numeric values.
🪄 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: CHILL

Plan: Pro

Run ID: 4d07b9e9-30eb-4499-a3d4-f494f6cbb52e

📥 Commits

Reviewing files that changed from the base of the PR and between e54f8ca and e1745a6.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (28)
  • src/rai_bench/rai_bench/test_models.py
  • src/rai_core/pyproject.toml
  • src/rai_core/rai/agents/langchain/agent.py
  • src/rai_core/rai/agents/langchain/callback.py
  • src/rai_core/rai/agents/langchain/state_based_agent.py
  • src/rai_core/rai/agents/runner.py
  • src/rai_core/rai/aggregators/base.py
  • src/rai_core/rai/aggregators/ros2/aggregators.py
  • src/rai_core/rai/communication/base_connector.py
  • src/rai_core/rai/communication/ros2/api/action.py
  • src/rai_core/rai/communication/ros2/ros_async.py
  • src/rai_core/rai/communication/ros2/waiters.py
  • src/rai_core/rai/messages/artifacts.py
  • src/rai_core/rai/tools/ros2/cli.py
  • tests/agents/langchain/test_hri_callback_handler.py
  • tests/agents/langchain/test_langchain_agent_max_size.py
  • tests/agents/langchain/test_state_based_config.py
  • tests/agents/test_agent_runner.py
  • tests/aggregators/test_base_aggregator.py
  • tests/aggregators/test_ros2_logs_aggregator.py
  • tests/communication/__init__.py
  • tests/communication/ros2/test_get_future_result_timeout.py
  • tests/communication/ros2/test_ros2_async.py
  • tests/communication/ros2/test_waiters.py
  • tests/communication/test_base_connector.py
  • tests/messages/test_artifacts_db_path.py
  • tests/rai_bench/manipulation_o3de/tasks/test_build_tower_task.py
  • tests/tools/test_ros2_cli_timeout.py

Comment on lines +118 to +119
if max_size <= 0:
raise ValueError(f"max_size must be positive, got {max_size!r}")

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'File map:\n'
git ls-files 'src/rai_core/rai/agents/langchain/agent.py'

printf '\nRelevant lines:\n'
sed -n '1,220p' src/rai_core/rai/agents/langchain/agent.py

printf '\nSearch for max_size usage:\n'
rg -n "max_size" src/rai_core/rai/agents/langchain/agent.py src/rai_core/rai -g '*.py'

printf '\nPython probe for the current guard semantics:\n'
python3 - <<'PY'
def guard(max_size):
    if max_size <= 0:
        return "raise"
    return "ok"

cases = [None, 0, 1, 1.5, True, False, -1]
for case in cases:
    try:
        print(repr(case), "=>", guard(case))
    except Exception as e:
        print(repr(case), "=>", type(e).__name__, str(e))
PY

Repository: RobotecAI/rai

Length of output: 11112


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Search for LangChainAgent tests and callers:\n'
rg -n "LangChainAgent\(" src tests -g '*.py' || true

printf '\nSearch for max_size=None with LangChainAgent or its subclasses:\n'
rg -n "max_size\s*=\s*None|max_size:\s*int\s*\|\s*None" src tests -g '*.py' || true

printf '\nInspect nearby class doc/contract for state_based_agent:\n'
sed -n '1,160p' src/rai_core/rai/agents/langchain/state_based_agent.py

printf '\nInspect aggregator base contract for comparison:\n'
sed -n '1,120p' src/rai_core/rai/aggregators/base.py

Repository: RobotecAI/rai

Length of output: 9010


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' tests/agents/langchain/test_langchain_agent_max_size.py

Repository: RobotecAI/rai

Length of output: 1310


Reject non-integer max_size values. max_size is documented and typed as an int, but True and 1.5 still pass this guard. Require a non-bool positive int and add regression tests for those cases.

🤖 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 `@src/rai_core/rai/agents/langchain/agent.py` around lines 118 - 119, Update
the max_size validation in the surrounding agent initialization logic to require
a positive int that is not a bool, rejecting values such as True and 1.5 while
preserving the existing error for non-positive values. Add regression tests
covering both invalid non-integer cases.

Comment on lines +45 to +50
@field_validator("time_interval")
@classmethod
def _time_interval_positive(cls, v: float) -> float:
if v <= 0:
raise ValueError(f"time_interval must be positive, got {v!r}")
return v

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject non-finite time_interval values.

float("nan") passes v <= 0, although NaN is not a valid positive interval. Reject non-finite values with math.isfinite and add a NaN regression test.

Proposed validation
+import math
+
     `@field_validator`("time_interval")
     `@classmethod`
     def _time_interval_positive(cls, v: float) -> float:
-        if v <= 0:
+        if not math.isfinite(v) or v <= 0:
             raise ValueError(f"time_interval must be positive, got {v!r}")
📝 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
@field_validator("time_interval")
@classmethod
def _time_interval_positive(cls, v: float) -> float:
if v <= 0:
raise ValueError(f"time_interval must be positive, got {v!r}")
return v
import math
`@field_validator`("time_interval")
`@classmethod`
def _time_interval_positive(cls, v: float) -> float:
if not math.isfinite(v) or v <= 0:
raise ValueError(f"time_interval must be positive, got {v!r}")
return v
🤖 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 `@src/rai_core/rai/agents/langchain/state_based_agent.py` around lines 45 - 50,
Update the _time_interval_positive validator to reject any non-finite value by
checking math.isfinite(v) alongside the existing positive-value condition, while
preserving the current error behavior for invalid intervals. Add a regression
test covering NaN input.

Comment on lines +31 to +32
if max_size is not None and max_size <= 0:
raise ValueError(f"max_size must be positive or None, got {max_size}")

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use one consistent integer-size validation contract.

Both constructors accept positive floats and booleans as buffer sizes, causing inaccurate queue capacities. Apply the same non-boolean positive-integer validation in both locations, while preserving None as an unbounded sentinel where supported.

  • src/rai_core/rai/aggregators/base.py#L31-L32: reject boolean and non-integer max_size values while retaining None.
  • src/rai_core/rai/agents/langchain/agent.py#L118-L119: reject boolean and non-integer bounded values, and either retain or explicitly remove the existing None sentinel behavior.
📍 Affects 2 files
  • src/rai_core/rai/aggregators/base.py#L31-L32 (this comment)
  • src/rai_core/rai/agents/langchain/agent.py#L118-L119
🤖 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 `@src/rai_core/rai/aggregators/base.py` around lines 31 - 32, Use one
non-boolean positive-integer validation contract for buffer sizes: update the
constructor validation in src/rai_core/rai/aggregators/base.py lines 31-32 to
reject booleans and non-integer max_size values while preserving None as
unbounded; apply the same validation to the bounded buffer-size check in
src/rai_core/rai/agents/langchain/agent.py lines 118-119, explicitly preserving
its existing None sentinel behavior.

Comment on lines +155 to +165
TypeError: If result_timeout is not a positive number (bool rejected).
ValueError: If the action server cannot be created or result_timeout <= 0.
"""
if isinstance(result_timeout, bool) or not isinstance(
result_timeout, (int, float)
):
raise TypeError(
f"result_timeout must be a positive number, got {type(result_timeout).__name__}"
)
if result_timeout <= 0:
raise ValueError(f"result_timeout must be positive, got {result_timeout!r}")

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep timeout validation consistent across both APIs.

src/rai_core/rai/communication/ros2/api/action.py#L155-L165 still accepts non-finite timeouts, and src/rai_core/rai/communication/ros2/ros_async.py#L29-L30 also accepts True because it only checks <= 0. Reject non-finite values at both entry points.

📍 Affects 2 files
  • src/rai_core/rai/communication/ros2/api/action.py#L155-L165 (this comment)
  • src/rai_core/rai/communication/ros2/ros_async.py#L29-L30
🤖 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 `@src/rai_core/rai/communication/ros2/api/action.py` around lines 155 - 165,
Update timeout validation in action.py lines 155-165 and ros_async.py lines
29-30 to reject non-finite values at both API entry points, while preserving
rejection of non-positive values and booleans. Use the existing validation paths
and ensure valid positive finite numbers remain accepted.

Comment on lines +33 to +34
requested_set = {ensure_slash(name) for name in requested_entities}
available_set = {ensure_slash(name) for name in callable_get_entities()}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Normalize the timeout-reporting path too.

Polling uses normalized sets, but the final timeout calculation still compares normalized requested names with raw available_entities. If only some entities are available without /, the timeout error incorrectly includes those entities as missing.

Proposed fix
-    available_entities = get_entities()
-
-    missing = set(requested) - set(available_entities)
+    missing = get_missing_entities(get_entities, requested)
🤖 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 `@src/rai_core/rai/communication/ros2/waiters.py` around lines 33 - 34, Update
the timeout-reporting calculation in the waiter flow to compare normalized
entity names consistently, matching the normalized requested_set and
available_set built from ensure_slash. Reuse the normalized available set when
determining missing entities so names available without a leading slash are not
reported as missing.

Comment on lines +29 to 33
path = Path(db_path)
if not path.is_file():
artifact_database: dict = {}
with path.open("wb") as file:
pickle.dump(artifact_database, file)

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix the missing-parent contract in both implementation and test.

store_artifacts only creates the file, while the test creates the parent directory first, so the nested-path failure is hidden.

  • src/rai_core/rai/messages/artifacts.py#L29-L33: call path.parent.mkdir(parents=True, exist_ok=True) before opening the file.
  • tests/messages/test_artifacts_db_path.py#L30-L34: remove db.parent.mkdir(...) so the test verifies that production creates the missing directory.
📍 Affects 2 files
  • src/rai_core/rai/messages/artifacts.py#L29-L33 (this comment)
  • tests/messages/test_artifacts_db_path.py#L30-L34
🤖 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 `@src/rai_core/rai/messages/artifacts.py` around lines 29 - 33, Update
store_artifacts in src/rai_core/rai/messages/artifacts.py to create path.parent
with parents=True and exist_ok=True before opening the database file. In
tests/messages/test_artifacts_db_path.py, remove the test’s db.parent.mkdir call
so the test exercises production directory creation.

Comment on lines +25 to +30
if isinstance(timeout_sec, bool) or not isinstance(timeout_sec, (int, float)):
raise TypeError(
f"timeout_sec must be a positive number, got {type(timeout_sec).__name__}"
)
if timeout_sec <= 0:
raise ValueError(f"timeout_sec must be positive, got {timeout_sec!r}")

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '1,220p' src/rai_core/rai/tools/ros2/cli.py

Repository: RobotecAI/rai

Length of output: 6071


🏁 Script executed:

python3 - <<'PY'
import math
from threading import Timer

vals = [float('nan'), float('inf'), float('-inf'), 0.1, -1.0, 1]
for v in vals:
    try:
        print(type(v).__name__, v, 'finite=', math.isfinite(v), '<=0=', (v <= 0))
    except Exception as e:
        print(type(v).__name__, v, 'error comparing:', e)

# Probe Timer construction/start behavior with NaN/inf without executing callbacks long-term.
def cb():
    print("callback fired")

for v in [float('nan'), float('inf'), 0.001]:
    t = Timer(v, cb)
    print("Timer", v, "interval attr:", t.interval)
PY

Repository: RobotecAI/rai

Length of output: 445


🏁 Script executed:

python3 - <<'PY'
import math
from threading import Timer

vals = [float('nan'), float('inf'), float('-inf'), 0.1, -1.0, 1]
for v in vals:
    print(type(v).__name__, v, 'finite=', math.isfinite(v), '<=0=', (v <= 0))

for v in [float('nan'), float('inf'), 0.001]:
    t = Timer(v, lambda: None)
    print("Timer", v, "interval attr:", t.interval)
PY

Repository: RobotecAI/rai

Length of output: 445


🏁 Script executed:

python3 - <<'PY'
import time
from threading import Timer

results = []

def mark(label):
    results.append((label, time.monotonic()))

start = time.monotonic()
for label, interval in [("nan", float("nan")), ("inf", float("inf")), ("short", 0.05)]:
    t = Timer(interval, mark, args=(label,))
    t.daemon = True
    t.start()

time.sleep(0.2)
print("elapsed", round(time.monotonic() - start, 3))
print("results", results)
PY

Repository: RobotecAI/rai

Length of output: 826


Reject non-finite timeout values. float("nan") bypasses the <= 0 check and reaches Timer, where it can fire immediately; float("inf") raises an OverflowError in the timer thread. Add math.isfinite(timeout_sec) here to reject both.

🤖 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 `@src/rai_core/rai/tools/ros2/cli.py` around lines 25 - 30, Update the
timeout_sec validation in the ROS2 CLI timeout handling to reject non-finite
numeric values by checking math.isfinite(timeout_sec) alongside the existing
type and positive-value checks. Preserve the current TypeError behavior for
invalid types and raise the appropriate validation error before creating the
Timer for NaN or infinity.

@Bartok9

Bartok9 commented Jul 22, 2026

Copy link
Copy Markdown

Thanks @maciejmajek — CI is now fully green here (the license header + zero-timeout alignment landed via #826, which is merged).

On the CodeRabbit review, both flagged items are small and optional:

  • messages/artifacts.py: create path.parent with parents=True, exist_ok=True before opening the DB (and drop the test's own mkdir so it exercises prod dir-creation).
  • tools/ros2/cli.py: add math.isfinite(timeout_sec) to the timeout validation to reject NaN/inf, and widen the annotation to int | float.

Since this branch lives on RobotecAI/rai I can't push directly — happy to fold these into a quick follow-up PR from my fork if you'd like them in, or leave them for a later pass. Whatever's cleanest for your merge order. 🎻

@codecov

codecov Bot commented Jul 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.91837% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.50%. Comparing base (e54f8ca) to head (e1745a6).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/rai_core/rai/communication/ros2/api/action.py 50.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #824      +/-   ##
==========================================
+ Coverage   73.19%   74.50%   +1.31%     
==========================================
  Files          82       82              
  Lines        3582     3621      +39     
==========================================
+ Hits         2622     2698      +76     
+ Misses        960      923      -37     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants