Skip to content

[#23896] Create tools for inpection (ros2 cli)#5

Open
Danipiza wants to merge 55 commits into
mainfrom
feature/ros2-cli
Open

[#23896] Create tools for inpection (ros2 cli)#5
Danipiza wants to merge 55 commits into
mainfrom
feature/ros2-cli

Conversation

@Danipiza

@Danipiza Danipiza commented Dec 3, 2025

Copy link
Copy Markdown
Contributor

Description

This branch adds a built-in ROS 2 default tool suite to VulcanAI and wires in the runtime, planner, validator, console, and CI changes needed to support it cleanly.

ROS 2 default tools

  • Added a new ros2_default_tools entry point in pyproject.toml.
  • Added a shared ROS2DefaultToolNode to support default tools when no main node is provided.
- ROS2 NODE
    - List (ros2 node list) output a List of available nodes.
    - Info (ros2 node info <node>) output Information about a node

- ROS2 TOPIC
    - List (ros2 topic list) output a List of available topics.
    - Info (ros2 topic info <topic>) print Information about a topic.
    - Type (ros2 topic type <topic>) print a topic's Type.
    - Find (ros2 topic find <type>) output a List of available topics of a given Type.
    - Bw (ros2 topic bw <topic>) display Bandwidth used by topic.
    - Delay (ros2 topic delay <topic>) display Delay of topic from timestamp in header.
    - Echo (ros2 topic echo <topic>) Output messages from a topic.
    - Hz (ros2 topic hz <topic>) print the average receiving rate (Hz)
    - Pub (ros2 topic pub <topic> <type> <data>) Publish a message to a topic.


- ROS2 SERVICE
    - Call (ros2 service call <service> <type> <args>) call a service.
    - Echo (ros2 service echo <service>) echo a service.
    - Find (ros2 service find <type>) output a List of available services of a given type.
    - Info (ros2 service info <service>) print Information about a service.
    - List (ros2 service list) output a List of available services.
    - Type (ros2 service type <service>) output a service's type.

- ROS2 ACTION
    - Info (ros2 action info <action>) print Information about an action.
    - List (ros2 action list) output a List of action names.
    - Send Goal (ros2 action send_goal <action> <type> <goal>) send an action goal.
    - Type (ros2 action type <action>) print an action's type.
    - Echo (ros2 action echo <action>) echo an action.
    - Find (ros2 action find <type>) find actions from type.

- ROS2 PARAM
    - Delete (ros2 param delete <node> <param>) delete parameter.
    - Describe (ros2 param describe <node> <param>) show descriptive Information about declared parameters.
    - Dump (ros2 param dump <node>) show all of the parameters of a node in a YAML file format.
    - Get (ros2 param get <node> <param>) get parameter.
    - List (ros2 param list) output a List of available parameters.
    - Load (ros2 param load <node> <file>) load parameter file for a node.
    - Set (ros2 param set <node> <param> <value>) set parameter.

Tool registry and tool metadata

  • ToolRegistry now supports auto-loading default tools, with the ability to disable that behavior where needed.
  • Added support for grouped tools via group_name.
  • Added tool_description for user-facing tool listings and input_defaults for documented/defaulted inputs.
  • Improved grouped registration logging and grouped tool rendering.

Planner, validator, and executor

  • Added support for optional schema types like string?, int?, float?, etc.
  • Executor now fills omitted arguments from input_defaults in schema order.
  • Strengthened plan models so plans, plan nodes, and steps cannot be empty/missing required fields.

Console and streaming UX

  • Added a dedicated subprocess/stream output panel for long-running streaming tools.
  • Added support for keeping the main log anchored correctly during spinner/layout changes.
  • Added /debug command and debug-only plan output logging.
  • Improved /rerun handling and validation.
  • Updated copy binding from F3 to F4.
  • Improved grouped tool selection modal and suggestion modal behavior.

Shared tool utilities

  • Moved subprocess execution and suggestion helpers into src/vulcanai/tools/utils.py.
  • Improved streaming subprocess capture, cancellation, output routing, and suggestion handling.

CI and tests

  • Split unit tests in CI so generic unit tests run separately from ROS 2-dependent default tool tests.
  • Added a ROS 2 CI job using a Vulcanexus container for test_default_tools.py.
  • Added extensive new tests for:
    • ROS 2 default tools
    • optional/default argument behavior
    • grouped tool registry behavior
    • stricter validator/model constraints

@cferreiragonz cferreiragonz 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.

First review just checking the code. We can consider creating some tests to check all tools.

I am concerned about the optional input parameters. I don't know how all LLMs will treat them.

I will re-review after reviewing Textualize PR

Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/console/utils.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py
Comment thread src/vulcanai/tools/default_tools.py
Comment thread src/vulcanai/tools/default_tools.py
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/console/utils.py
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/console/utils.py Outdated
Comment thread pyproject.toml Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py
Comment thread src/vulcanai/tools/default_tools.py Outdated

@cferreiragonz cferreiragonz 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.

The default tools also require the user to provide a ROS2 node to the console, which implies building code to use them, we should be able to provide a real default tools where the user could use them without coding

@Danipiza

Copy link
Copy Markdown
Contributor Author

The default tools also require the user to provide a ROS2 node to the console, which implies building code to use them, we should be able to provide a real default tools where the user could use them without coding

Should we disable the publisher/subscriber tools, or add a SharedNode class in default_tool.py to create a ros node if the user have not added one?

Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/tool_registry.py Outdated
Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/core/manager_iterator.py Outdated
Comment thread src/vulcanai/core/manager_iterator.py Outdated
_default_tools: bool = True
):
super().__init__(model, registry, validator, k, max(3, hist_depth), logger)
super().__init__(model, registry, validator, k, max(3, hist_depth), logger, _default_tools)

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.

Suggested change
super().__init__(model, registry, validator, k, max(3, hist_depth), logger, _default_tools)
super().__init__(model=model, registry=registry, validator=validator, k=k, hist_depth=max(3, hist_depth), logger=logger, default_tools=default_tools)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in f2549ac

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.

Remember to apply this

@Danipiza Danipiza May 26, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 237a622

Comment thread src/vulcanai/core/manager_plan.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
@Danipiza

Danipiza commented Feb 5, 2026

Copy link
Copy Markdown
Contributor Author

Also managed the exception in the copy feacture when the user does not have installed a copy apt package.

  • sudo apt-get install xclip,
  • sudo apt-get install xselect (on X11)
  • sudo apt-get install wl-clipboard (on Wayland)

@cferreiragonz

Copy link
Copy Markdown
Contributor

I will test them soon to check each tool individually. In the meantime, could you rebase onto main to solve the conflicts Github complains about.

Comment thread src/vulcanai/console/widget_custom_log_text_area.py

@cferreiragonz cferreiragonz 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.

If no tests are introduced, we should document or list a series of commands to which VulcanAI should correctly answer.

For example:

  • Run a publisher in background and input: "Subscribe to topic /chatter with max message 1".

Note that this could also be done in a test-suite running in a docker container with Vulcanexus and checking the blackboard to verify the output of each call.

Lastly, I am still missing providing a default ROS 2 Node if default tools are enabled and no ROS 2 node is given. Otherwise tools won't work

Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py
Comment thread src/vulcanai/tools/default_tools.py Outdated
@Danipiza Danipiza force-pushed the feature/ros2-cli branch 2 times, most recently from 622e2d4 to 33b292a Compare February 19, 2026 15:28
Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
@Danipiza

Copy link
Copy Markdown
Contributor Author
  • Ensured variables types in publish and subscribe tools to avoid this errors:
Execution failed for 'ros_subscribe': '<=' not supported between instances of 'str' and 'int'  
  • Removed lock in the publish tool.
  • Added custom_node.py with node example. Also added in the __init__.pyi

Done in 3d25f8d

@cferreiragonz cferreiragonz 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.

I added the missing default ROS 2 Node and moved it to the same file as the default tools. I also corrected a bug in the ROS2TopicTool and created tests for its main arguments. I still think we have to much variability by allowing optional input arguments which only work with specific commands (for example the topic_name is required for the info subcommand, but it is not required for the find subcommand), this makes the LLM success rate very low. I also improved some logs.

  • We would need to extend the test suits with a specific test for each tool sub-command to avoid having failing tests with every update.
  • Calling /tools returns: Error: ColorParseError("'topic_name' is not a valid color")
  • It would be great to parse the message: WARNING: topic \[/chatter] does not appear to be published yet shown when subscribing or publishing messages to avoid the trailing forward slash before the bracket.
  • I could not find any informative message stating how to stop a subscriber or publisher. Something like "press Ctrl+C to stop".
  • We need to review how things are displayed because right now "ros2 topic list" does not show any result. The user needs to check the Output dictionary, which right now does not use a pretty format. Additionally, subscribing to any message with max_lines argument automatically closes the new pop-up windows, so no output can be read.
[EXECUTOR] Invoking 'ros_subscribe' with args:'{'topic': '/chatter', 'max_lines': '15'}'
[TOOL ros_subscribe] Subprocess created!
[TOOL ros_subscribe] Returning only the last 10 lines in result['output'].
[EXECUTOR] Executed 'ros_subscribe' in 229.9 ms with result: //<-- This means I had 229.ms to visualize the data
[EXECUTOR] PlanNode PARALLEL succeeded on attempt 1/1```

Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/console/console.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py
Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment on lines +924 to +927
if max_duration is not None and not isinstance(max_duration, (int, float)):
max_duration = None
if max_duration is not None and max_duration <= 0:
max_duration = None

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.

Suggested change
if max_duration is not None and not isinstance(max_duration, (int, float)):
max_duration = None
if max_duration is not None and max_duration <= 0:
max_duration = None
if not isinstance(max_duration, (int, float)) or max_duration <= 0:
max_duration = None

Comment thread src/vulcanai/tools/default_tools.py Outdated
Comment thread src/vulcanai/tools/default_tools.py Outdated
@cferreiragonz cferreiragonz requested review from richiprosima and removed request for richiprosima April 1, 2026 12:50
@Danipiza Danipiza force-pushed the feature/ros2-cli branch 2 times, most recently from 1e6d1cc to a4be233 Compare April 1, 2026 14:09
@Danipiza

Copy link
Copy Markdown
Contributor Author

I will answer the previous review comment here.

I still think we have to much variability by allowing optional input arguments which only work with specific commands (for example the topic_name is required for the info subcommand, but it is not required for the find subcommand), this makes the LLM success rate very low.

I have refactored the tools in multiple commands. And added a new optional variable in the tools called "group_name". This variable groups tools, making it look like subtools. When registering, editing the active tools or executing "/tools" it is displayed with group style.

The tools have better description and tags that makes the LLM choose rapidly the tool to execute with the input of the user. The time execution of the queries have decreased significantly.

Calling /tools returns: Error: ColorParseError("'topic_name' is not a valid color")

Added a new variable "tool_description" to print a brief description of the tools, instead of the entire description of the tool (the one that uses the LLM)

It would be great to parse the message: WARNING: topic \[/chatter] does not appear to be published yet shown when subscribing or publishing messages to avoid the trailing forward slash before the bracket.

I could not find any informative message stating how to stop a subscriber or publisher. Something like "press Ctrl+C to stop".

Already resolved.
Screenshot from 2026-04-23 11-50-15

The informative message was not being displayed because the streaming panel was created at the top of the terminal and pushed the text making it not visible unless the user scroll down. Now the streaming panel is located at the bottom and this issue does not happen.

We need to review how things are displayed because right now "ros2 topic list" does not show any result. The user needs to check the Output dictionary, which right now does not use a pretty format. Additionally, subscribing to any message with max_lines argument automatically closes the new pop-up windows, so no output can be read.

This also happened to me when I used OLlama with CPU (instead of GPU) and with the previous tools. Right now is solved.

We would need to extend the test suits with a specific test for each tool sub-command to avoid having failing tests with every update.

I am currently working with this and also:

  • The implementation of the publisher.
  • Parse "<xxx>" characters the user writes in the terminal
# USER QUERY print me the information of the ros2 topic </chatter>
[USER] >>> print me the information of the ros2 topic 
[MANAGER] Ollama response time: 2.726 seconds
[MANAGER] Prompt tokens: 1219, Completion tokens: 110
[MANAGER] Plan received:
- Plan Summary: Prints the information of the ROS2 topic 

- PlanNode 1: kind=SEQUENCE
[MANAGER] [ERROR] Error handling user request: 'chatter' is not a valid colo

@Danipiza Danipiza removed the request for review from richiprosima April 23, 2026 10:37
@Danipiza Danipiza requested review from cferreiragonz and removed request for cferreiragonz May 26, 2026 08:44
Danipiza added 2 commits May 26, 2026 10:58
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
@Danipiza Danipiza requested review from cferreiragonz and removed request for cferreiragonz May 26, 2026 09:00
Danipiza added 2 commits June 4, 2026 11:13
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
…aky test

Signed-off-by: danipiza <dpizarrogallego@gmail.com>
@Danipiza Danipiza requested review from cferreiragonz and removed request for cferreiragonz June 4, 2026 09:55
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
@Danipiza Danipiza requested review from cferreiragonz and removed request for cferreiragonz June 8, 2026 05:40
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
@Danipiza Danipiza requested review from cferreiragonz and removed request for cferreiragonz June 8, 2026 06:27
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
@Danipiza Danipiza requested review from cferreiragonz and removed request for cferreiragonz June 8, 2026 08:24
Danipiza added 3 commits June 15, 2026 16:17
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
@Danipiza Danipiza requested review from cferreiragonz and removed request for cferreiragonz June 16, 2026 05:12
@Danipiza

Copy link
Copy Markdown
Contributor Author

Added keyboard support in modal screens.

RadioList (suggestions)

  • up, bottom keys to navigate throw the options
  • space to change the selected option
  • enter to submit the option

CheckList (/edit_tools)

  • up, bottom keys to navigate throw the options
  • space to toggle the selected option
  • enter to submit the checklist

Added two new buttons in the /edit_tools modal screen

  • Toggle all tools
  • Toggle default tools

Signed-off-by: danipiza <dpizarrogallego@gmail.com>
@Danipiza Danipiza requested a review from richiprosima June 18, 2026 05:58
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
@Danipiza Danipiza requested review from richiprosima and removed request for richiprosima June 19, 2026 10:28
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