Powered by AppSignal & Oban Pro

Lesson 06 Livebook: Mesh Coordination

livebooks/06_mesh_coordination.livemd

Lesson 06 Livebook: Mesh Coordination

Orpheus has two probes on the same contact now. The trouble starts when both reports survive.

Mix.install([
  {:helios_fleet, path: "../06_mesh_coordination"}
])

Application.ensure_all_started(:helios_fleet)

Helpers

defmodule Lesson06Helpers do
  alias HeliosFleet.Runtime

  def unique_agent_id(prefix) do
    "#{prefix}-#{System.unique_integer([:positive])}"
  end

  def safe_stop_family(parent_id) do
    child_ids = [
      "#{parent_id}/khepri/port_relay",
      "#{parent_id}/khepri/starboard_relay",
      "#{parent_id}/menhit/port_relay",
      "#{parent_id}/menhit/starboard_relay",
      "#{parent_id}/khepri",
      "#{parent_id}/menhit"
    ]

    Enum.each(child_ids, fn child_id ->
      case Runtime.whereis(child_id) do
        nil -> :ok
        _pid -> Runtime.stop_agent(child_id)
      end
    end)

    case Runtime.whereis(parent_id) do
      nil -> :ok
      _pid -> Runtime.stop_agent(parent_id)
    end
  end
end

Compare Two Arcs

alias HeliosFleet
alias Jido.AgentServer
alias Jido.Signal

vessel_id = Lesson06Helpers.unique_agent_id("orpheus")
{:ok, pid} = HeliosFleet.start_command_vessel(vessel_id)

{:ok, _vessel} =
  AgentServer.call(
    pid,
    Signal.new!(
      "fleet.command.mesh_deployment_requested",
      %{
        mesh_id: "mesh-icefall",
        target: "ice fragment 6R"
      },
      source: "/orpheus/bridge"
    )
  )

Process.sleep(50)
{:ok, command_state} = AgentServer.state(pid)
khepri_pid = command_state.children.khepri.pid
menhit_pid = command_state.children.menhit.pid

for {probe_pid, corridor, vector, classification} <- [
      {khepri_pid, "icefall-west", "port_arc", "volatile_ice"},
      {menhit_pid, "icefall-east", "starboard_arc", "derelict_relay"}
    ] do
  {:ok, _probe} =
    AgentServer.call(
      probe_pid,
      Signal.new!(
        "fleet.probe.relay_chain_requested",
        %{corridor: corridor, relays: ["port_relay", "starboard_relay"]},
        source: "/orpheus/bridge"
    )
  )

  Process.sleep(50)
  {:ok, probe_state} = AgentServer.state(probe_pid)
  port_relay_pid = probe_state.children.port_relay.pid

  {:ok, _relay} =
    AgentServer.call(
      port_relay_pid,
      Signal.new!(
        "relay.hold_corridor_assigned",
        %{corridor: corridor, vector: vector},
        source: "/khepri"
      )
    )

  Process.sleep(50)

  {:ok, _probe} =
    AgentServer.call(
      probe_pid,
      Signal.new!(
        "sensors.contact_classified",
        %{target: "ice fragment 6R", classification: classification, confidence: "medium"},
        source: "/sensor/mast"
      )
    )

  {:ok, _probe} =
    AgentServer.call(
      probe_pid,
      Signal.new!("fleet.probe.command_update_requested", %{}, source: "/orpheus/bridge")
    )
end

Process.sleep(50)

{:ok, updated_command_state} = AgentServer.state(pid)

Lesson06Helpers.safe_stop_family(vessel_id)

%{
  fleet_updates: updated_command_state.agent.state.fleet_updates,
  mesh_snapshots: updated_command_state.agent.state.mesh_snapshots
}