Skip to content

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

Open
Danipiza wants to merge 24 commits intomainfrom
feature/ros2-cli
Open

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

Conversation

@Danipiza
Copy link
Contributor

@Danipiza Danipiza commented Dec 3, 2025

New commands

- ros2 node
    Commands:
        info  Output information about a node
        list  Output a list of available nodes

- ros2 topic
    Commands:
        bw     Display bandwidth used by topic
        delay  Display delay of topic from timestamp in header
        echo   Output messages from a topic
        find   Output a list of available topics of a given type
        hz     Print the average receiving rate to screen
        info   Print information about a topic
        list   Output a list of available topics
        pub    Publish a message to a topic
        type   Print a topic's type

- ros2 service
    Commands:
        call  Call a service
        echo  Echo a service
        find  Output a list of available services of a given type
        info  Print information about a service
        list  Output a list of available services
        type  Output a service's type

- ros2 action
    Commands:
        info       Print information about an action
        list       Output a list of action names
        send_goal  Send an action goal
        type       Print a action's type
        echo       Echo a action
        find       Find actions from type


- ros2 param
    Commands:
        delete    Delete parameter
        describe  Show descriptive information about declared parameters
        dump      Show all of the parameters of a node in a YAML file format
        get       Get parameter
        list      Output a list of available parameters
        load      Load parameter file for a node
        set       Set parameter

Stream-able commands examples:

execute the following command: "ros2 topic echo /turtle1/pose" for a maximum number of lines of 100000
execute the following command: "ros2 topic hz /turtle1/pose" for a maximum number of lines of 100000
execute the following command: "ros2 topic delay /turtle1/pose" for a maximum number of lines of 100000
execute the following command: "ros2 topic pub /chatter std_msgs/msg/String" for a maximum number of lines of 100000
execute the following command: "ros2 topic bw /turtle1/pose" for a maximum number of lines of 100000
execute the following command: "ros2 service echo /turtlesim/describe_parameters" for a maximum number of lines of 100000

Copy link
Contributor

@cferreiragonz cferreiragonz left a comment

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

base_args = ["ros2", "topic", "echo", topic_name]
execute_subprocess(console, base_args, max_duration, max_lines)

result["output"] = "True"
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the point of returning "True" here? Shouldn't we output the last message received or similar? I am worried that this uncertainty in the output might affect the performance of the library. Why do we return the listed topics in some calls but in others we just return a string "True"?. If the purpose of the tools is just to print info for the user and the LLM will never receive info about the real output I would be very clear about this in the tool description so the LLM can know that this tools are just for debugging and not for linking and making complex plans. Also, I would take the same approach for every command, instead of returning the real output in some of them and none in others. We can discuss about this to clarify it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added "True" only in the tools that have streaming commands that use the function execute_subprocess() like ros2 topic echo <topic_name>. These commands prints a lot of information and are finished when the user send a kill signal (or when the query specifies a max_duration or max_lines variables). The "one-shot" commands like ros2 topic list use the function run_oneshot_cmd() that returns a string with the output of the comand.

We could try to change the implementation of execute_subprocess() to return a string with all printed lines by the streaming command. Also, I have to mention that this streaming command are being executed async, so technically the user could query VulcanAI to do other stuff, but the terminal output would be joined with both, the query and the streaming command.

Copy link
Contributor

@cferreiragonz cferreiragonz left a comment

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
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?

_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
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
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

@Danipiza
Copy link
Contributor Author

Danipiza commented Feb 5, 2026

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

Copy link
Contributor

@cferreiragonz cferreiragonz left a comment

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

)
return {"published": False, "count": 0, "topic": topic}

with node.node_lock:
Copy link
Contributor

Choose a reason for hiding this comment

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

This raises an error if the node given does not have this attribute. This is hard to find out. We should avoid it or documented properly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Remove unnecessary topic check, just check if the topic is not None and then check if the topic exists, if not execute suggestion_string().

Done in 622e2d4

Copy link
Contributor

Choose a reason for hiding this comment

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

This problem remains. This forces the user to create a Node with an attribute node_lock without even knowing what node_lock is.

As said before, we need to provide a custom Node with the logic needed. If this lock is inevitable, we should document it properly as user will have to add it to their custom nodes, otherwise, we should get rid of it.



@vulcanai_tool
class Ros2SubscribeTool(AtomicTool):
Copy link
Contributor

Choose a reason for hiding this comment

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

As agreed internally:

  • We need to be able to stop the execution of a subscriber, and it would probably apply to every "stream" command. For the moment, new requests would cancel the current execution and stop the subscribing process. This will also fix the issue that the input bar has not focus when a subscription is running, but it does when a plan is re-run.
  • We could send the output to a new popup or window on the right column
  • When a topic is not found, we should also check if the name is just missing the initial "/".
  • A brief description or title is missing in the new pop-up that appears when suggesting a topic.
  • It would be nice to avoid the overlapping of the Bullet list in the suggestion list, (check image). Also, we could center the text of the buttons below.
Image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in 622e2d4

Copy link
Contributor Author

@Danipiza Danipiza Feb 19, 2026

Choose a reason for hiding this comment

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

1. We need to be able to stop the execution of a subscriber, ....

The subscriber and publisher did not had the "Ctr+C" signal handle. Now, both tools can be stopped manually.
Changed the TextArea focus issue. Now, when the TextArea is at the bottom, it moves automatically to the latest line, however when the user scroll up, it does not focus.

2. We could send the output to a new popup or window on the right column

Added new pop-up stream panel for the tools tat that writes in the main terminal as a sub-process, like publish, subscribe or ros2 topic echo <topic_name>

3. When a topic is not found, we should also check if the name is just missing the initial "/".

Changed the suggestion_string() function, first it checks if it starts with a "/" for the ros2 categories that starts with the escape symbol such as Topic, Interface or Node.

4. A brief description or title is missing in the new pop-up that appears when suggesting a topic.

Added a brief description in the suggestion_string() pop-up. Now it shows what the user input and the category of the ros2 tool.

5. It would be nice to avoid the overlapping of the Bullet list in the suggestion list, ...

Changed the Bullet list icon for a square with a mark in the chosen one. Also removed the border in the pop-up.

Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: danipiza <dpizarrogallego@gmail.com>
)
return {"published": False, "count": 0, "topic": topic}

with node.node_lock:
Copy link
Contributor

Choose a reason for hiding this comment

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

This problem remains. This forces the user to create a Node with an attribute node_lock without even knowing what node_lock is.

As said before, we need to provide a custom Node with the logic needed. If this lock is inevitable, we should document it properly as user will have to add it to their custom nodes, otherwise, we should get rid of it.

Signed-off-by: danipiza <dpizarrogallego@gmail.com>
@Danipiza
Copy link
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

Danipiza and others added 6 commits March 3, 2026 07:36
…, ...)

Signed-off-by: danipiza <dpizarrogallego@gmail.com>
Signed-off-by: Carlos Ferreira González <carlosferreira@eprosima.com>
Signed-off-by: Carlos Ferreira González <carlosferreira@eprosima.com>
Signed-off-by: Carlos Ferreira González <carlosferreira@eprosima.com>
Signed-off-by: Carlos Ferreira González <carlosferreira@eprosima.com>
Signed-off-by: Carlos Ferreira González <carlosferreira@eprosima.com>
Copy link
Contributor

@cferreiragonz cferreiragonz left a comment

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```

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