Skip to main content
Glama

sample_messages

Read-onlyIdempotent

Collect live ROS 2 topic messages up to a set count within a timeout, returning payloads, timestamps, summaries, and rates; use mock mode for demo samples.

Instructions

ROS 2 graph only; on a DDS-only setup use list_endpoints or peek_dds_samples on DCPSPublication / DCPSSubscription. Collect up to count live messages from a ROS 2 topic, waiting at most timeout_s seconds, as a SampleResult. Live mode streams ros2 topic echo with the publishers' QoS (latched topics work) and returns what arrived by the deadline: count is the actual number and note says N of M messages and why it is short (no publisher, silent, slow or too large to print in time; a latched topic usually holds one message, so use count 1). Each sample has payload (nested named values), timestamp_ns (the publisher's clock, sim time on a simulation, 0 for a headerless message such as std_msgs/String; see stamp_source) and received_ns (wall clock when the CLI printed it). Arrays: arrays, strings and bytes are cut at 128 elements by default (a 541-beam LaserScan loses beams 128 and up); cut fields are listed in payload._truncated_fields and note. Raise max_array_length (up to 65536, or null) or set arrays_summary_only. A message over the 1 MiB cap (TOPICFORGE_MAX_SAMPLE_BYTES) is dropped with a note. Mock mode returns demo-robot samples instantly. Raises an MCP error without a ros2 CLI, for an unknown topic, or when the CLI fails. Read-only; never publishes. Logs: min_log_level / node (/rosout only) stream until timeout_s (at most 2000 messages) and return the NEWEST count matches in stamp order; peek_bag_samples returns the FIRST matches. Summary and rate: LaserScan, Odometry, Imu, Image and PointCloud2 samples carry a summary of the whole message (other types: null); rate gives frequency, interval spread and a verdict measured on received_ns (when the CLI printed each message). Use count >= 10 (50 above 20 Hz); a multi-publisher topic such as /tf reads erratic without being broken. Duration: ros2 CLI behind the ROS lock, one call at a time; returns within timeout_s (at most 40) plus about 3 s to stop the CLI and decode; ends within 45 s, less time to collect after a wait; busy error if the lock is held (retry).

Input Schema

NameRequiredDescriptionDefault
nodeNo`/rosout` only: keep logs of this node and its child loggers, e.g. `/robot1/driver` (also `driver`, `robot1.driver`). Exact name, never a prefix. Other topics: error.
countNoMessages to wait for, default 5, at most 50 (more is capped and `note` says so); 0 returns nothing. Fewer arrive when the topic is slow or `timeout_s` runs out.
topicYesFully qualified ROS 2 topic name starting with `/`, e.g. `/cmd_vel`. Segments are letters, digits and underscores (not starting with a digit); anything else is rejected before reaching the `ros2` CLI.
timeout_sNoSeconds to wait, 1..40, default 10, covering topic lookup and CLI start-up. The call returns within `timeout_s` plus a few seconds, with what arrived and a `note`. Raise it for a topic slower than 1 Hz.
min_log_levelNo`/rosout` (`rcl_interfaces/msg/Log`) only: keep messages at or above this level (debug 10, info 20, warn 30, error 40, fatal 50). Other topics: error.
max_array_lengthNoLongest array, string or bytes value returned in full, 1..65536, default 128 (a 541-beam `LaserScan` is cut to 128 ranges; its `summary` still covers all). Longer values are cut and listed in `_truncated_fields`. Null returns everything (large for images and clouds; a message over 1 MiB is dropped with a note).
arrays_summary_onlyNoWhen true, arrays become a type-and-length summary: use it to read the non-array fields of large messages. Default false.

Output Schema

NameRequiredDescriptionDefault
noteNoWhy `samples` is empty or limited, when not obvious; else `None`.
rateNoHow the topic delivered the messages, with a verdict; `null` for `peek_dds_samples`. Use `count` >= 10.
countYesNumber of samples in `samples`: fewer than requested when the topic gave fewer, never more than 50 (a larger request is capped to 50).
topicYes
samplesYesThe samples, in backend order.
mode_effectiveYes`live` or `mock` (fixtures).

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed44 schema fields changedv0.8.0
    • addedInput schema / properties / min_log_level
      Added value: +{
      +  "anyOf": [
      +    {
      +      "enum": [
      +        "debug",
      +        "info",
      +        "warn",
      +        "error",
      +        "fatal"
      +      ],
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "`/rosout` (`rcl_interfaces/msg/Log`) only: keep messages at or above this level (debug 10, info 20, warn 30, error 40, fatal 50). Other topics: error."
      +}
    • addedInput schema / properties / node
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "`/rosout` only: keep logs of this node and its child loggers, e.g. `/robot1/driver` (also `driver`, `robot1.driver`). Exact name, never a prefix. Other topics: error."
      +}
    • removedOutput schema / $defs / ImageSummary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "data_length": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Pixel buffer size in bytes (see `data_length_basis`)."
      -    },
      -    "data_length_basis": {
      -      "anyOf": [
      -        {
      -          "enum": [
      -            "payload",
      -            "step_x_height"
      -          ],
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`payload` (counted) or `step_x_height` (array cut, so step times height)."
      -    },
      -    "encoding": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Pixel encoding, e.g. `rgb8`."
      -    },
      -    "frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`header.frame_id` of the camera."
      -    },
      -    "height": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Pixels."
      -    },
      -    "is_bigendian": {
      -      "anyOf": [
      -        {
      -          "type": "boolean"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Big-endian pixels."
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "One sentence when partial; else `null`."
      -    },
      -    "step": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Row length, bytes."
      -    },
      -    "summary_type": {
      -      "const": "image",
      -      "type": "string"
      -    },
      -    "width": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Pixels."
      -    }
      -  },
      -  "required": [
      -    "summary_type",
      -    "frame_id",
      -    "width",
      -    "height",
      -    "encoding",
      -    "step",
      -    "is_bigendian",
      -    "data_length",
      -    "data_length_basis"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / ImuSummary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "angular_velocity_norm": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Norm of `angular_velocity`, rad/s."
      -    },
      -    "frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`header.frame_id` of the IMU."
      -    },
      -    "linear_acceleration_norm": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Norm of `linear_acceleration`, m/s^2."
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "One sentence when a value is unusable; else `null`."
      -    },
      -    "orientation_valid": {
      -      "description": "False when the IMU gives no orientation: `roll`, `pitch`, `yaw` are `null`.",
      -      "type": "boolean"
      -    },
      -    "pitch": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Rotation about y, radians."
      -    },
      -    "roll": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Rotation about x, radians."
      -    },
      -    "summary_type": {
      -      "const": "imu",
      -      "type": "string"
      -    },
      -    "yaw": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Rotation about z, radians."
      -    }
      -  },
      -  "required": [
      -    "summary_type",
      -    "frame_id",
      -    "orientation_valid",
      -    "roll",
      -    "pitch",
      -    "yaw",
      -    "angular_velocity_norm",
      -    "linear_acceleration_norm"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / LaserScanSummary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "angle_increment": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Angle between beams, rad."
      -    },
      -    "angle_max": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Bearing of the last beam, rad."
      -    },
      -    "angle_min": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Bearing of beam 0, rad."
      -    },
      -    "beam_count": {
      -      "description": "Beams in `ranges`.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "closest_obstacle": {
      -      "anyOf": [
      -        {
      -          "$ref": "#/$defs/ScanReturn"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Closest valid return of the scan; `null` with `note`."
      -    },
      -    "finite_count": {
      -      "description": "Beams with a finite range.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`header.frame_id`; every angle is in this sensor frame, not the base frame."
      -    },
      -    "inf_count": {
      -      "description": "Beams at `+inf`.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "nan_count": {
      -      "description": "Beams at `nan`.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "neg_inf_count": {
      -      "description": "Beams at `-inf`.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "One sentence when the summary is partial; else `null`."
      -    },
      -    "out_of_range_count": {
      -      "description": "Finite ranges outside `range_min`..`range_max` (not valid).",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "range_max": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Largest valid range, m."
      -    },
      -    "range_min": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Smallest valid range, m."
      -    },
      -    "sectors": {
      -      "$ref": "#/$defs/ScanSectors",
      -      "description": "Closest valid return per sector."
      -    },
      -    "summary_type": {
      -      "const": "laser_scan",
      -      "type": "string"
      -    }
      -  },
      -  "required": [
      -    "summary_type",
      -    "frame_id",
      -    "beam_count",
      -    "angle_min",
      -    "angle_max",
      -    "angle_increment",
      -    "range_min",
      -    "range_max",
      -    "finite_count",
      -    "inf_count",
      -    "neg_inf_count",
      -    "nan_count",
      -    "out_of_range_count",
      -    "closest_obstacle",
      -    "sectors"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / MessageSample / properties / received_ns / anyOf
      Removed value: -[
      -  {
      -    "type": "integer"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / MessageSample / properties / received_ns / default
      Removed value: -null
    • addedOutput schema / $defs / MessageSample / properties / received_ns / type
      Added value: +[
      +  "integer",
      +  "null"
      +]
    • removedOutput schema / $defs / MessageSample / properties / recorded_ns / anyOf
      Removed value: -[
      -  {
      -    "type": "integer"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / MessageSample / properties / recorded_ns / default
      Removed value: -null
    • addedOutput schema / $defs / MessageSample / properties / recorded_ns / type
      Added value: +[
      +  "integer",
      +  "null"
      +]
    • removedOutput schema / $defs / MessageSample / properties / summary / anyOf
      Removed value: -[
      -  {
      -    "discriminator": {
      -      "mapping": {
      -        "image": "#/$defs/ImageSummary",
      -        "imu": "#/$defs/ImuSummary",
      -        "laser_scan": "#/$defs/LaserScanSummary",
      -        "odometry": "#/$defs/OdometrySummary",
      -        "point_cloud2": "#/$defs/PointCloud2Summary"
      -      },
      -      "propertyName": "summary_type"
      -    },
      -    "oneOf": [
      -      {
      -        "$ref": "#/$defs/LaserScanSummary"
      -      },
      -      {
      -        "$ref": "#/$defs/OdometrySummary"
      -      },
      -      {
      -        "$ref": "#/$defs/ImuSummary"
      -      },
      -      {
      -        "$ref": "#/$defs/ImageSummary"
      -      },
      -      {
      -        "$ref": "#/$defs/PointCloud2Summary"
      -      }
      -    ]
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / MessageSample / properties / summary / default
      Removed value: -null
    • addedOutput schema / $defs / MessageSample / properties / summary / properties
      Added value: +{
      +  "summary_type": {
      +    "enum": [
      +      "laser_scan",
      +      "odometry",
      +      "imu",
      +      "image",
      +      "point_cloud2"
      +    ],
      +    "type": "string"
      +  }
      +}
    • addedOutput schema / $defs / MessageSample / properties / summary / required
      Added value: +[
      +  "summary_type"
      +]
    • addedOutput schema / $defs / MessageSample / properties / summary / type
      Added value: +[
      +  "object",
      +  "null"
      +]
    • removedOutput schema / $defs / OdometrySummary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "angular_z": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`twist.twist.angular.z`, rad/s."
      -    },
      -    "child_frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`child_frame_id` (frame of the twist)."
      -    },
      -    "frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`header.frame_id` (frame of the pose)."
      -    },
      -    "linear_speed": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Norm of `twist.twist.linear`, m/s."
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "One sentence when a value is missing; else `null`."
      -    },
      -    "position_x": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`pose.pose.position.x`, m."
      -    },
      -    "position_y": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`pose.pose.position.y`, m."
      -    },
      -    "position_z": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`pose.pose.position.z`, m."
      -    },
      -    "summary_type": {
      -      "const": "odometry",
      -      "type": "string"
      -    },
      -    "yaw": {
      -      "anyOf": [
      -        {
      -          "type": "number"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Heading from the pose quaternion, radians."
      -    }
      -  },
      -  "required": [
      -    "summary_type",
      -    "frame_id",
      -    "child_frame_id",
      -    "linear_speed",
      -    "angular_z",
      -    "position_x",
      -    "position_y",
      -    "position_z",
      -    "yaw"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / PointCloud2Summary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "fields": {
      -      "description": "Point layout.",
      -      "items": {
      -        "$ref": "#/$defs/PointFieldSummary"
      -      },
      -      "type": "array"
      -    },
      -    "frame_id": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`header.frame_id` of the cloud."
      -    },
      -    "height": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Rows (1: unorganized)."
      -    },
      -    "is_dense": {
      -      "anyOf": [
      -        {
      -          "type": "boolean"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "True when no point is invalid."
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "One sentence when partial; else `null`."
      -    },
      -    "point_count": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "`width` times `height`."
      -    },
      -    "point_step": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Bytes per point."
      -    },
      -    "row_step": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Bytes per row."
      -    },
      -    "summary_type": {
      -      "const": "point_cloud2",
      -      "type": "string"
      -    },
      -    "width": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Points per row."
      -    }
      -  },
      -  "required": [
      -    "summary_type",
      -    "frame_id",
      -    "width",
      -    "height",
      -    "point_count",
      -    "point_step",
      -    "row_step",
      -    "is_dense",
      -    "fields"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / PointFieldSummary
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "count": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Elements per point."
      -    },
      -    "datatype": {
      -      "description": "Element type, e.g. `FLOAT32`.",
      -      "type": "string"
      -    },
      -    "name": {
      -      "description": "Field name, e.g. `x`.",
      -      "type": "string"
      -    },
      -    "offset": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Byte offset in a point."
      -    }
      -  },
      -  "required": [
      -    "name",
      -    "datatype",
      -    "offset",
      -    "count"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / ScanReturn
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "beam_index": {
      -      "description": "Index in `ranges`.",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "bearing": {
      -      "description": "Beam direction in radians, sensor frame: 0 is +x, counter-clockwise positive.",
      -      "type": "number"
      -    },
      -    "range": {
      -      "description": "Distance, meters.",
      -      "type": "number"
      -    }
      -  },
      -  "required": [
      -    "range",
      -    "bearing",
      -    "beam_index"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / ScanSector
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "beam_count": {
      -      "description": "Beams inside the sector (0: not covered).",
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    "closest": {
      -      "anyOf": [
      -        {
      -          "$ref": "#/$defs/ScanReturn"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "description": "Closest valid return in the sector; `null` with `note`."
      -    },
      -    "note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Why `closest` is `null`; `null` when it is set."
      -    }
      -  },
      -  "required": [
      -    "beam_count",
      -    "closest"
      -  ],
      -  "type": "object"
      -}
    • removedOutput schema / $defs / ScanSectors
      Removed value: -{
      -  "additionalProperties": false,
      -  "properties": {
      -    "front": {
      -      "$ref": "#/$defs/ScanSector",
      -      "description": "Bearings within +-45 degrees of +x."
      -    },
      -    "left": {
      -      "$ref": "#/$defs/ScanSector",
      -      "description": "Bearings from 45 to 135 degrees."
      -    },
      -    "rear": {
      -      "$ref": "#/$defs/ScanSector",
      -      "description": "Bearings beyond +-135 degrees."
      -    },
      -    "right": {
      -      "$ref": "#/$defs/ScanSector",
      -      "description": "Bearings from -135 to -45 degrees."
      -    }
      -  },
      -  "required": [
      -    "front",
      -    "left",
      -    "right",
      -    "rear"
      -  ],
      -  "type": "object"
      -}
    • addedOutput schema / $defs / TopicRate / properties / clock_basis
      Added value: +{
      +  "description": "Stamp clock: `wall` (stamps are dates), `sim` (since a start), `none` (no stamps), `mixed` (several kinds, e.g. two publishers).",
      +  "enum": [
      +    "wall",
      +    "sim",
      +    "none",
      +    "mixed"
      +  ],
      +  "type": "string"
      +}
    • removedOutput schema / $defs / TopicRate / properties / interval_cv / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / interval_cv / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / TopicRate / properties / interval_median_s / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / interval_median_s / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / TopicRate / properties / max_gap_s / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / max_gap_s / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / TopicRate / properties / mean_interval_s / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / mean_interval_s / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / TopicRate / properties / observed_frequency_hz / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / observed_frequency_hz / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / TopicRate / properties / sim_frequency_hz / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / sim_frequency_hz / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • addedOutput schema / $defs / TopicRate / properties / stamp_age_median_s
      Added value: +{
      +  "description": "Median of arrival minus stamp, s, if `wall`; negative = publisher ahead.",
      +  "type": [
      +    "number",
      +    "null"
      +  ]
      +}
    • addedOutput schema / $defs / TopicRate / properties / stamp_age_p95_s
      Added value: +{
      +  "description": "95th percentile of that age (max under 20 messages).",
      +  "type": [
      +    "number",
      +    "null"
      +  ]
      +}
    • addedOutput schema / $defs / TopicRate / properties / stamp_regression_count
      Added value: +{
      +  "description": "Times a stamp went back versus the previous one.",
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • removedOutput schema / $defs / TopicRate / properties / trailing_gap_s / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / $defs / TopicRate / properties / trailing_gap_s / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / properties / note / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / note / default
      Removed value: -null
    • addedOutput schema / properties / note / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / rate / default
      Removed value: -null
  2. Changed56 schema fields changedv0.7.1
    • changedInput schema / properties / arrays_summary_only / description
      Previous value: -"When true, array fields are replaced by a short type and length summary instead of their elements. Use it to inspect the non-array fields of large messages (images, scans, point clouds). Defaults to false."New value: +"When true, arrays become a type-and-length summary: use it to read the non-array fields of large messages. Default false."
    • removedInput schema / properties / arrays_summary_only / title
      Removed value: -"Arrays Summary Only"
    • changedInput schema / properties / count / description
      Previous value: -"Number of messages to wait for. Defaults to 5; at most 50 (a larger request is capped to 50 and `note` says so). 0 returns nothing. `SampleResult.count` is how many arrived: fewer than requested when the topic publishes slowly or the deadline (`timeout_s`) ran out."New value: +"Messages to wait for, default 5, at most 50 (more is capped and `note` says so); 0 returns nothing. Fewer arrive when the topic is slow or `timeout_s` runs out."
    • removedInput schema / properties / count / title
      Removed value: -"Count"
    • changedInput schema / properties / max_array_length / description
      Previous value: -"Longest array, string or bytes value to return in full, 1..65536; longer ones are cut after their first N elements or characters and the field's dotted path is listed in the sample's `_truncated_fields`. Defaults to 128, the `ros2 topic echo` default, which cuts a 541-beam `LaserScan` after 128 ranges. Pass null to return everything in full (large for images and point clouds; a message over the server's size cap, 1 MiB by default, is dropped with a note, and a very large message may not print before the deadline)."New value: +"Longest array, string or bytes value returned in full, 1..65536, default 128 (a 541-beam `LaserScan` is cut to 128 ranges; its `summary` still covers all). Longer values are cut and listed in `_truncated_fields`. Null returns everything (large for images and clouds; a message over 1 MiB is dropped with a note)."
    • removedInput schema / properties / max_array_length / title
      Removed value: -"Max Array Length"
    • changedInput schema / properties / timeout_s / description
      Previous value: -"Seconds to wait for the messages, 1..45, default 10. Bounds the whole call, topic lookup and the `ros2` CLI start-up (a few seconds on a slow machine) included: the call returns within about `timeout_s` + 2 s. Whatever arrived by then is returned with a `note`. Raise it for a topic that publishes slower than 1 Hz. The server handles one call at a time, so a long wait delays other tool calls."New value: +"Seconds to wait, 1..40, default 10, covering topic lookup and CLI start-up. The call returns within `timeout_s` plus a few seconds, with what arrived and a `note`. Raise it for a topic slower than 1 Hz."
    • changedInput schema / properties / timeout_s / maximum
      Previous value: -45New value: +40
    • removedInput schema / properties / timeout_s / title
      Removed value: -"Timeout S"
    • changedInput schema / properties / topic / description
      Previous value: -"Fully qualified ROS2 topic name starting with `/`, e.g. `/cmd_vel` or `/camera/image_raw`. Each `/`-separated segment must start with a letter or underscore and contain only letters, digits, and underscores; everything else (whitespace, quotes, shell metacharacters, `//`, trailing `/`) is rejected before reaching the `ros2` CLI."New value: +"Fully qualified ROS 2 topic name starting with `/`, e.g. `/cmd_vel`. Segments are letters, digits and underscores (not starting with a digit); anything else is rejected before reaching the `ros2` CLI."
    • removedInput schema / properties / topic / title
      Removed value: -"Topic"
    • removedInput schema / title
      Removed value: -"sample_messagesArguments"
    • addedOutput schema / $defs / ImageSummary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "data_length": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Pixel buffer size in bytes (see `data_length_basis`)."
      +    },
      +    "data_length_basis": {
      +      "anyOf": [
      +        {
      +          "enum": [
      +            "payload",
      +            "step_x_height"
      +          ],
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`payload` (counted) or `step_x_height` (array cut, so step times height)."
      +    },
      +    "encoding": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Pixel encoding, e.g. `rgb8`."
      +    },
      +    "frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`header.frame_id` of the camera."
      +    },
      +    "height": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Pixels."
      +    },
      +    "is_bigendian": {
      +      "anyOf": [
      +        {
      +          "type": "boolean"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Big-endian pixels."
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "One sentence when partial; else `null`."
      +    },
      +    "step": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Row length, bytes."
      +    },
      +    "summary_type": {
      +      "const": "image",
      +      "type": "string"
      +    },
      +    "width": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Pixels."
      +    }
      +  },
      +  "required": [
      +    "summary_type",
      +    "frame_id",
      +    "width",
      +    "height",
      +    "encoding",
      +    "step",
      +    "is_bigendian",
      +    "data_length",
      +    "data_length_basis"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / ImuSummary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "angular_velocity_norm": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Norm of `angular_velocity`, rad/s."
      +    },
      +    "frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`header.frame_id` of the IMU."
      +    },
      +    "linear_acceleration_norm": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Norm of `linear_acceleration`, m/s^2."
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "One sentence when a value is unusable; else `null`."
      +    },
      +    "orientation_valid": {
      +      "description": "False when the IMU gives no orientation: `roll`, `pitch`, `yaw` are `null`.",
      +      "type": "boolean"
      +    },
      +    "pitch": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Rotation about y, radians."
      +    },
      +    "roll": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Rotation about x, radians."
      +    },
      +    "summary_type": {
      +      "const": "imu",
      +      "type": "string"
      +    },
      +    "yaw": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Rotation about z, radians."
      +    }
      +  },
      +  "required": [
      +    "summary_type",
      +    "frame_id",
      +    "orientation_valid",
      +    "roll",
      +    "pitch",
      +    "yaw",
      +    "angular_velocity_norm",
      +    "linear_acceleration_norm"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / LaserScanSummary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "angle_increment": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Angle between beams, rad."
      +    },
      +    "angle_max": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Bearing of the last beam, rad."
      +    },
      +    "angle_min": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Bearing of beam 0, rad."
      +    },
      +    "beam_count": {
      +      "description": "Beams in `ranges`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "closest_obstacle": {
      +      "anyOf": [
      +        {
      +          "$ref": "#/$defs/ScanReturn"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Closest valid return of the scan; `null` with `note`."
      +    },
      +    "finite_count": {
      +      "description": "Beams with a finite range.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`header.frame_id`; every angle is in this sensor frame, not the base frame."
      +    },
      +    "inf_count": {
      +      "description": "Beams at `+inf`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "nan_count": {
      +      "description": "Beams at `nan`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "neg_inf_count": {
      +      "description": "Beams at `-inf`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "One sentence when the summary is partial; else `null`."
      +    },
      +    "out_of_range_count": {
      +      "description": "Finite ranges outside `range_min`..`range_max` (not valid).",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "range_max": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Largest valid range, m."
      +    },
      +    "range_min": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Smallest valid range, m."
      +    },
      +    "sectors": {
      +      "$ref": "#/$defs/ScanSectors",
      +      "description": "Closest valid return per sector."
      +    },
      +    "summary_type": {
      +      "const": "laser_scan",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "summary_type",
      +    "frame_id",
      +    "beam_count",
      +    "angle_min",
      +    "angle_max",
      +    "angle_increment",
      +    "range_min",
      +    "range_max",
      +    "finite_count",
      +    "inf_count",
      +    "neg_inf_count",
      +    "nan_count",
      +    "out_of_range_count",
      +    "closest_obstacle",
      +    "sectors"
      +  ],
      +  "type": "object"
      +}
    • removedOutput schema / $defs / MessageSample / description
      Removed value: -"A single sampled message on a topic."
    • removedOutput schema / $defs / MessageSample / properties / message_type / description
      Removed value: -"ROS2 message type of this sample, e.g. `geometry_msgs/msg/Twist`."
    • removedOutput schema / $defs / MessageSample / properties / message_type / title
      Removed value: -"Message Type"
    • changedOutput schema / $defs / MessageSample / properties / payload / description
      Previous value: -"Message fields as nested named values, e.g. `{\"header\": {\"stamp\": {\"sec\": 12, \"nanosec\": 5}, \"frame_id\": \"base_laser\"}, \"ranges\": [1.0, 1.001]}`. Non-finite floats are the strings `nan`, `inf`, `-inf`. Live `sample_messages` adds `_truncated_fields` (dotted paths of arrays, strings or bytes cut at `max_array_length`; a string of exactly that length plus `...` that was not cut is listed too) when something was cut, and `_raw_text` (the unparsed output) only when a message could not be parsed. With `arrays_summary_only` an array is a string like `<sequence type: float, length: 541>`. Large messages may be dropped to keep tool output bounded."New value: +"Message fields as nested values; `nan`/`inf` are strings. Live `sample_messages` adds `_truncated_fields` (cut paths) and `_raw_text` (unparsable output)."
    • removedOutput schema / $defs / MessageSample / properties / payload / title
      Removed value: -"Payload"
    • changedOutput schema / $defs / MessageSample / properties / received_ns / description
      Previous value: -"Wall-clock nanoseconds since epoch at which the `ros2` CLI printed this message, after it deserialized and formatted it: not the network receive time, and it lags more for large messages. Accurate to a fraction of a second. Live `sample_messages` only; `None` otherwise."New value: +"Wall-clock ns when the `ros2` CLI printed the message (live `sample_messages` only)."
    • removedOutput schema / $defs / MessageSample / properties / received_ns / title
      Removed value: -"Received Ns"
    • changedOutput schema / $defs / MessageSample / properties / recorded_ns / description
      Previous value: -"Nanoseconds at which the recorder wrote this message into the bag (the bag's own record time, wall clock unless the recorder ran on simulated time). `peek_bag_samples` only; `None` for live samples, where `received_ns` plays that role."New value: +"Bag record time in ns (`peek_bag_samples` only)."
    • removedOutput schema / $defs / MessageSample / properties / recorded_ns / title
      Removed value: -"Recorded Ns"
    • removedOutput schema / $defs / MessageSample / properties / stamp_source / anyOf
      Removed value: -[
      -  {
      -    "enum": [
      -      "header",
      -      "none",
      -      "recorded"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / MessageSample / properties / stamp_source / default
      Removed value: -null
    • changedOutput schema / $defs / MessageSample / properties / stamp_source / description
      Previous value: -"Where `timestamp_ns` comes from: `header` (the message's `header.stamp`), `none` (headerless live message, `timestamp_ns` is 0) or `recorded` (headerless message from a bag, `timestamp_ns` is the bag record time). `None` when the backend does not say."New value: +"Origin of `timestamp_ns`: `header`, `payload`, `recorded` (bag record time), `dds_source` or `none` (0)."
    • addedOutput schema / $defs / MessageSample / properties / stamp_source / enum
      Added value: +[
      +  "header",
      +  "payload",
      +  "recorded",
      +  "dds_source",
      +  "none"
      +]
    • removedOutput schema / $defs / MessageSample / properties / stamp_source / title
      Removed value: -"Stamp Source"
    • addedOutput schema / $defs / MessageSample / properties / stamp_source / type
      Added value: +"string"
    • addedOutput schema / $defs / MessageSample / properties / summary
      Added value: +{
      +  "anyOf": [
      +    {
      +      "discriminator": {
      +        "mapping": {
      +          "image": "#/$defs/ImageSummary",
      +          "imu": "#/$defs/ImuSummary",
      +          "laser_scan": "#/$defs/LaserScanSummary",
      +          "odometry": "#/$defs/OdometrySummary",
      +          "point_cloud2": "#/$defs/PointCloud2Summary"
      +        },
      +        "propertyName": "summary_type"
      +      },
      +      "oneOf": [
      +        {
      +          "$ref": "#/$defs/LaserScanSummary"
      +        },
      +        {
      +          "$ref": "#/$defs/OdometrySummary"
      +        },
      +        {
      +          "$ref": "#/$defs/ImuSummary"
      +        },
      +        {
      +          "$ref": "#/$defs/ImageSummary"
      +        },
      +        {
      +          "$ref": "#/$defs/PointCloud2Summary"
      +        }
      +      ]
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Condensed reading of the whole message (see `summary_type`); `null` for other types and DDS peeks."
      +}
    • changedOutput schema / $defs / MessageSample / properties / timestamp_ns / description
      Previous value: -"Nanoseconds from the message's own top-level `header.stamp` (`stamp_source` `header`), or 0 when the message has no header (`stamp_source` `none`, e.g. `std_msgs/String`, `geometry_msgs/Twist`). It is the publisher's clock, not the arrival time: on simulated time it is sim time since the simulation started (a few seconds, not a date) and 0 is a valid value. From `peek_bag_samples` a message without a header gets the bag record time instead (`stamp_source` `recorded`), also given in `recorded_ns`. Use `received_ns` for when the CLI printed the message. Mock samples with a header carry synthetic increasing values."New value: +"Publisher-clock ns: `header.stamp`, else the time in the body of `Clock`, `TFMessage` or `Log`, else 0 (see `stamp_source`); not the arrival time."
    • removedOutput schema / $defs / MessageSample / properties / timestamp_ns / title
      Removed value: -"Timestamp Ns"
    • removedOutput schema / $defs / MessageSample / properties / topic / description
      Removed value: -"Fully qualified topic name the sample was taken from, e.g. `/cmd_vel`."
    • removedOutput schema / $defs / MessageSample / properties / topic / title
      Removed value: -"Topic"
    • changedOutput schema / $defs / MessageSample / required
      Previous value: -[
      -  "topic",
      -  "message_type",
      -  "timestamp_ns"
      -]New value: +[
      +  "topic",
      +  "message_type",
      +  "timestamp_ns",
      +  "stamp_source"
      +]
    • removedOutput schema / $defs / MessageSample / title
      Removed value: -"MessageSample"
    • addedOutput schema / $defs / OdometrySummary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "angular_z": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`twist.twist.angular.z`, rad/s."
      +    },
      +    "child_frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`child_frame_id` (frame of the twist)."
      +    },
      +    "frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`header.frame_id` (frame of the pose)."
      +    },
      +    "linear_speed": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Norm of `twist.twist.linear`, m/s."
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "One sentence when a value is missing; else `null`."
      +    },
      +    "position_x": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`pose.pose.position.x`, m."
      +    },
      +    "position_y": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`pose.pose.position.y`, m."
      +    },
      +    "position_z": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`pose.pose.position.z`, m."
      +    },
      +    "summary_type": {
      +      "const": "odometry",
      +      "type": "string"
      +    },
      +    "yaw": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Heading from the pose quaternion, radians."
      +    }
      +  },
      +  "required": [
      +    "summary_type",
      +    "frame_id",
      +    "child_frame_id",
      +    "linear_speed",
      +    "angular_z",
      +    "position_x",
      +    "position_y",
      +    "position_z",
      +    "yaw"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / PointCloud2Summary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "fields": {
      +      "description": "Point layout.",
      +      "items": {
      +        "$ref": "#/$defs/PointFieldSummary"
      +      },
      +      "type": "array"
      +    },
      +    "frame_id": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`header.frame_id` of the cloud."
      +    },
      +    "height": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Rows (1: unorganized)."
      +    },
      +    "is_dense": {
      +      "anyOf": [
      +        {
      +          "type": "boolean"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "True when no point is invalid."
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "One sentence when partial; else `null`."
      +    },
      +    "point_count": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "`width` times `height`."
      +    },
      +    "point_step": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Bytes per point."
      +    },
      +    "row_step": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Bytes per row."
      +    },
      +    "summary_type": {
      +      "const": "point_cloud2",
      +      "type": "string"
      +    },
      +    "width": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Points per row."
      +    }
      +  },
      +  "required": [
      +    "summary_type",
      +    "frame_id",
      +    "width",
      +    "height",
      +    "point_count",
      +    "point_step",
      +    "row_step",
      +    "is_dense",
      +    "fields"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / PointFieldSummary
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "count": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Elements per point."
      +    },
      +    "datatype": {
      +      "description": "Element type, e.g. `FLOAT32`.",
      +      "type": "string"
      +    },
      +    "name": {
      +      "description": "Field name, e.g. `x`.",
      +      "type": "string"
      +    },
      +    "offset": {
      +      "anyOf": [
      +        {
      +          "type": "integer"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Byte offset in a point."
      +    }
      +  },
      +  "required": [
      +    "name",
      +    "datatype",
      +    "offset",
      +    "count"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / ScanReturn
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "beam_index": {
      +      "description": "Index in `ranges`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "bearing": {
      +      "description": "Beam direction in radians, sensor frame: 0 is +x, counter-clockwise positive.",
      +      "type": "number"
      +    },
      +    "range": {
      +      "description": "Distance, meters.",
      +      "type": "number"
      +    }
      +  },
      +  "required": [
      +    "range",
      +    "bearing",
      +    "beam_index"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / ScanSector
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "beam_count": {
      +      "description": "Beams inside the sector (0: not covered).",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "closest": {
      +      "anyOf": [
      +        {
      +          "$ref": "#/$defs/ScanReturn"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Closest valid return in the sector; `null` with `note`."
      +    },
      +    "note": {
      +      "anyOf": [
      +        {
      +          "type": "string"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "default": null,
      +      "description": "Why `closest` is `null`; `null` when it is set."
      +    }
      +  },
      +  "required": [
      +    "beam_count",
      +    "closest"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / ScanSectors
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "front": {
      +      "$ref": "#/$defs/ScanSector",
      +      "description": "Bearings within +-45 degrees of +x."
      +    },
      +    "left": {
      +      "$ref": "#/$defs/ScanSector",
      +      "description": "Bearings from 45 to 135 degrees."
      +    },
      +    "rear": {
      +      "$ref": "#/$defs/ScanSector",
      +      "description": "Bearings beyond +-135 degrees."
      +    },
      +    "right": {
      +      "$ref": "#/$defs/ScanSector",
      +      "description": "Bearings from -135 to -45 degrees."
      +    }
      +  },
      +  "required": [
      +    "front",
      +    "left",
      +    "right",
      +    "rear"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / TopicRate
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "basis": {
      +      "description": "Clock the rate is measured on: `received_ns` (live) or `recorded_ns` (bag).",
      +      "enum": [
      +        "received_ns",
      +        "recorded_ns"
      +      ],
      +      "type": "string"
      +    },
      +    "interval_cv": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Interval standard deviation over mean; `null` under 2 messages."
      +    },
      +    "interval_median_s": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Median interval; `null` under 2 messages."
      +    },
      +    "max_gap_s": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Longest interval; `null` under 2 messages."
      +    },
      +    "mean_interval_s": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Mean interval; `null` under 2 messages."
      +    },
      +    "message_count": {
      +      "description": "Messages the rate is computed from.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "observed_frequency_hz": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Messages per second on `basis`, drain excluded; the rate the caller received. `null` under 2 messages."
      +    },
      +    "sim_frequency_hz": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Same rate on the messages' own stamps (publisher clock); `null` without advancing stamps."
      +    },
      +    "startup_burst_count": {
      +      "description": "Leading messages set aside as a start-up drain (live only); still in `message_count`.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "trailing_gap_s": {
      +      "anyOf": [
      +        {
      +          "type": "number"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Time from the last message to the end of a live observation; else `null`."
      +    },
      +    "verdict": {
      +      "description": "First match: `silent` (none), `insufficient` (under 5), `intermittent` (an interval over 3x the median), `stable` (cv < 0.2), `jittery` (< 0.5), `erratic`. Describes this window, not a diagnosis.",
      +      "enum": [
      +        "silent",
      +        "insufficient",
      +        "intermittent",
      +        "stable",
      +        "jittery",
      +        "erratic"
      +      ],
      +      "type": "string"
      +    },
      +    "verdict_note": {
      +      "description": "The verdict in plain words.",
      +      "type": "string"
      +    },
      +    "window_s": {
      +      "description": "Observation length, seconds.",
      +      "minimum": 0,
      +      "type": "number"
      +    }
      +  },
      +  "required": [
      +    "basis",
      +    "message_count",
      +    "startup_burst_count",
      +    "window_s",
      +    "mean_interval_s",
      +    "interval_median_s",
      +    "max_gap_s",
      +    "interval_cv",
      +    "observed_frequency_hz",
      +    "sim_frequency_hz",
      +    "trailing_gap_s",
      +    "verdict",
      +    "verdict_note"
      +  ],
      +  "type": "object"
      +}
    • changedOutput schema / description
      Previous value: -"Envelope returned by the `sample_messages` tool."New value: +"Samples returned by `sample_messages`, `peek_dds_samples` and `peek_bag_samples`."
    • changedOutput schema / properties / count / description
      Previous value: -"Number of samples actually returned. May be 0 (no publisher active in live mode, or empty mock fixture), less than the requested count (topic yielded fewer messages within the timeout), or capped by the the silent maximum of 50: request `count > 50` and you will receive at most 50 without warning."New value: +"Number of samples in `samples`: fewer than requested when the topic gave fewer, never more than 50 (a larger request is capped to 50)."
    • removedOutput schema / properties / count / title
      Removed value: -"Count"
    • changedOutput schema / properties / mode_effective / description
      Previous value: -"Runtime mode the adapter served this response in: `live` (real ROS2 introspection) or `mock` (deterministic fixtures). Lets a caller tell a real graph from a demo one without calling `health_check`."New value: +"`live` or `mock` (fixtures)."
    • removedOutput schema / properties / mode_effective / title
      Removed value: -"Mode Effective"
    • changedOutput schema / properties / note / description
      Previous value: -"Why `samples` is empty or limited, when the cause is not obvious (for example payload decoding is disabled for DDS user topics). `None` when there is nothing to add."New value: +"Why `samples` is empty or limited, when not obvious; else `None`."
    • removedOutput schema / properties / note / title
      Removed value: -"Note"
    • addedOutput schema / properties / rate
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/TopicRate"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "How the topic delivered the messages, with a verdict; `null` for `peek_dds_samples`. Use `count` >= 10."
      +}
    • changedOutput schema / properties / samples / description
      Previous value: -"The sampled messages, ordered as received from the backend."New value: +"The samples, in backend order."
    • removedOutput schema / properties / samples / title
      Removed value: -"Samples"
    • removedOutput schema / properties / topic / description
      Removed value: -"Topic the samples were taken from, echoed from the request."
    • removedOutput schema / properties / topic / title
      Removed value: -"Topic"
  3. Changed9 schema fields changedv0.6.3
    • changedInput schema / properties / count / description
      Previous value: -"Maximum number of recent messages to return. Defaults to 5; silently clamped to 50 (the hard cap that keeps tool output bounded; read it from `health_check.max_sample_count`). Negative values raise an error. The returned `SampleResult.count` reflects the actual number of samples produced: it can be lower than the request (empty topic, timeout, mock fixture shorter than requested)."New value: +"Number of messages to wait for. Defaults to 5; at most 50 (a larger request is capped to 50 and `note` says so). 0 returns nothing. `SampleResult.count` is how many arrived: fewer than requested when the topic publishes slowly or the deadline (`timeout_s`) ran out."
    • addedInput schema / properties / count / maximum
      Added value: +50
    • changedInput schema / properties / max_array_length / description
      Previous value: -"Longest array, string or bytes value to return in full, 1..65536; longer ones are cut. A cut array is listed in the sample's `_truncated_after_columns` (index of the last kept column); a cut string or bytes value is kept as its first N characters plus `...` and listed in `_truncated_columns`. Defaults to 128, the `ros2 topic echo` default, which cuts a 541-beam `LaserScan` after 128 ranges. Pass null to return everything in full (large for images and point clouds; a message over the server's size cap, 1 MiB by default, is dropped with a note, and a very large message may not print within the echo timeout)."New value: +"Longest array, string or bytes value to return in full, 1..65536; longer ones are cut after their first N elements or characters and the field's dotted path is listed in the sample's `_truncated_fields`. Defaults to 128, the `ros2 topic echo` default, which cuts a 541-beam `LaserScan` after 128 ranges. Pass null to return everything in full (large for images and point clouds; a message over the server's size cap, 1 MiB by default, is dropped with a note, and a very large message may not print before the deadline)."
    • addedInput schema / properties / timeout_s
      Added value: +{
      +  "default": 10,
      +  "description": "Seconds to wait for the messages, 1..45, default 10. Bounds the whole call, topic lookup and the `ros2` CLI start-up (a few seconds on a slow machine) included: the call returns within about `timeout_s` + 2 s. Whatever arrived by then is returned with a `note`. Raise it for a topic that publishes slower than 1 Hz. The server handles one call at a time, so a long wait delays other tool calls.",
      +  "maximum": 45,
      +  "minimum": 1,
      +  "title": "Timeout S",
      +  "type": "number"
      +}
    • changedOutput schema / $defs / MessageSample / properties / payload / description
      Previous value: -"Structured message payload. **In live mode the parser exposes the message fields as positional CSV columns** keyed as `col_0`, `col_1`, ... (`header.stamp.sec`/`nanosec` are stripped out into `timestamp_ns` when detected). The raw CSV row is preserved verbatim under the reserved `_raw_text` key so clients can re-parse against the message's IDL when needed. In mock mode the payload is fully structured and `_raw_text` is absent. Large messages (e.g. images) may be summarized to keep tool output bounded."New value: +"Message fields as nested named values, e.g. `{\"header\": {\"stamp\": {\"sec\": 12, \"nanosec\": 5}, \"frame_id\": \"base_laser\"}, \"ranges\": [1.0, 1.001]}`. Non-finite floats are the strings `nan`, `inf`, `-inf`. Live `sample_messages` adds `_truncated_fields` (dotted paths of arrays, strings or bytes cut at `max_array_length`; a string of exactly that length plus `...` that was not cut is listed too) when something was cut, and `_raw_text` (the unparsed output) only when a message could not be parsed. With `arrays_summary_only` an array is a string like `<sequence type: float, length: 541>`. Large messages may be dropped to keep tool output bounded."
    • addedOutput schema / $defs / MessageSample / properties / received_ns
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "integer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Wall-clock nanoseconds since epoch at which the `ros2` CLI printed this message, after it deserialized and formatted it: not the network receive time, and it lags more for large messages. Accurate to a fraction of a second. Live `sample_messages` only; `None` otherwise.",
      +  "title": "Received Ns"
      +}
    • addedOutput schema / $defs / MessageSample / properties / recorded_ns
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "integer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Nanoseconds at which the recorder wrote this message into the bag (the bag's own record time, wall clock unless the recorder ran on simulated time). `peek_bag_samples` only; `None` for live samples, where `received_ns` plays that role.",
      +  "title": "Recorded Ns"
      +}
    • addedOutput schema / $defs / MessageSample / properties / stamp_source
      Added value: +{
      +  "anyOf": [
      +    {
      +      "enum": [
      +        "header",
      +        "none",
      +        "recorded"
      +      ],
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Where `timestamp_ns` comes from: `header` (the message's `header.stamp`), `none` (headerless live message, `timestamp_ns` is 0) or `recorded` (headerless message from a bag, `timestamp_ns` is the bag record time). `None` when the backend does not say.",
      +  "title": "Stamp Source"
      +}
    • changedOutput schema / $defs / MessageSample / properties / timestamp_ns / description
      Previous value: -"Timestamp in nanoseconds since epoch. In live mode this is the `header.stamp` of the sampled message when present: the live adapter invokes `ros2 topic echo --csv --once`, whose flattened CSV exposes `header.stamp.sec`/`nanosec` as the first two columns for any `Header`-stamped message. **Headerless message types** (e.g. `std_msgs/String`, `geometry_msgs/Twist`) carry no embedded timestamp, and `timestamp_ns` falls back to 0; an rclpy-backed adapter will eventually expose rmw receive times for those. Mock mode emits monotonically increasing values for deterministic ordering."New value: +"Nanoseconds from the message's own top-level `header.stamp` (`stamp_source` `header`), or 0 when the message has no header (`stamp_source` `none`, e.g. `std_msgs/String`, `geometry_msgs/Twist`). It is the publisher's clock, not the arrival time: on simulated time it is sim time since the simulation started (a few seconds, not a date) and 0 is a valid value. From `peek_bag_samples` a message without a header gets the bag record time instead (`stamp_source` `recorded`), also given in `recorded_ns`. Use `received_ns` for when the CLI printed the message. Mock samples with a header carry synthetic increasing values."
  4. First observedv0.5.6

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the read-only annotation, the description discloses QoS/latching behavior, timeout and truncation behavior, the 1 MiB cap, mock mode, MCP errors, lock contention and `busy` retry behavior, and total duration bounds. It never contradicts the annotations: it is consistently read-only and non-publishing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long and dense, but it is front-loaded with the graph/alternative caveat and then organized by mode, truncation, logging, summary/rate, and duration. Some parameter details duplicate the schema, which prevents a 5, but most sentences add useful operational context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex sampling tool with timeout, truncation, QoS, logging, and lock behavior, the description covers what an agent needs to invoke it correctly. An output schema exists, so it reasonably omits full return-value documentation while still explaining key result fields like `payload`, `note`, `summary`, and `rate`.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already explains each parameter, but the description adds operational meaning: `count` is the actual number returned, latched topics usually need `count` 1, and `node`/`min_log_level` apply only to `/rosout`. It also explains the practical effect of `max_array_length` and `arrays_summary_only` on large messages.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: collect up to `count` live messages from a ROS 2 `topic` as a `SampleResult`. It immediately distinguishes the ROS 2 graph scope from DDS-only workflows by naming `list_endpoints` and `peek_dds_samples` as alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says this is for the ROS 2 graph only and routes DDS-only setups to `list_endpoints` or `peek_dds_samples`. It also distinguishes live versus mock mode and explains the `peek_bag_samples` ordering difference for log-style queries.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.