lib/bb/mcp/tools/query_events.ex

# SPDX-FileCopyrightText: 2026 James Harton
#
# SPDX-License-Identifier: Apache-2.0

defmodule BB.MCP.Tools.QueryEvents do
  @moduledoc """
  Query pubsub events captured by the current MCP session.

  Each session subscribes to all configured robots' pubsub trees on connect
  and records messages in a ring buffer (capacity configurable via
  `:bb_mcp, :event_buffer_size`, default 1000). This tool returns the most
  recent events, optionally filtered.

  Events arrive in real time so the agent can use this tool after invoking
  a command to inspect motion lifecycle, joint-state changes, or other
  pubsub traffic without polling the robot state.
  """

  use Anubis.Server.Component, type: :tool

  alias Anubis.Server.Response
  alias BB.MCP.EventBuffer
  alias BB.MCP.Tools

  schema do
    field(:robot, :string, description: "Filter to events from one robot")

    field(:message_type, :string,
      description:
        "Substring match against the payload module name (e.g. \"JointState\", " <>
          "\"BB.Command.Event\")"
    )

    field(:path_prefix, :string,
      description: "Dotted path prefix, e.g. \"sensor\" or \"command.move_to_pose\""
    )

    field(:since_ms, :integer,
      description: "Only return events received within the last N milliseconds"
    )

    field(:limit, :integer, description: "Maximum events to return (default 50)")
  end

  @impl true
  def execute(params, frame) do
    filters = build_filters(params)
    buffer = Map.get(frame.assigns, :event_buffer, EventBuffer.new())
    events = EventBuffer.query(buffer, filters)

    payload = %{
      "count" => length(events),
      "capacity" => buffer.capacity,
      "buffered" => length(buffer.events),
      "events" => events
    }

    {:reply, Response.json(Response.tool(), payload), frame}
  end

  defp build_filters(params) do
    %{
      robot: Tools.get_arg(params, :robot),
      message_type: Tools.get_arg(params, :message_type),
      path_prefix: Tools.get_arg(params, :path_prefix),
      since_ms: Tools.get_arg(params, :since_ms),
      limit: Tools.get_arg(params, :limit) || 50
    }
  end
end