| defmodule PerplexityMacro.ControlPlane do
|
| @moduledoc """
|
| Elixir/OTP CONTROL PLANE β top of `Agent Console` stack.
|
|
|
| Elixir / OTP
|
| CONTROL PLANE (this module)
|
| β
|
| βββββββββββ΄βββββββββββ
|
| βΌ βΌ
|
| Python workers Elixir services
|
| AI / ML / data concurrency / state
|
| (Adapters, WASM: (VM, TraceHub 50k,
|
| Python execution) ROM mailbox, ResearchBroker,
|
| Phoenix LiveView)
|
| β β
|
| ββββββββββββ¬ββββββββββ
|
| βΌ
|
| Tool layer
|
| APIs / WASM / DB
|
| (Tavily, Wiki, WASM Box,
|
| Swift Gateway typed JSON)
|
|
|
| Browser WebLLM is the *instruction model* that drives this plane:
|
| Browser WebLLM ββinstruction ABIββ> ControlPlane ββ> Python workers | Elixir services ββ> Tool layer
|
| ControlPlane owns: fuel, transcript_hash, WORM seal, capability policy (CONFIRM 0x2A),
|
| and routes `java.execute` β WASM Box vs `tool.call` β local or Swift gateway (optional).
|
| """
|
| use GenServer
|
|
|
| def start_link(opts), do: GenServer.start_link(__MODULE__, opts, name: __MODULE__)
|
|
|
| @impl true
|
| def init(_opts) do
|
| {:ok, %{python_workers: :pool, elixir_services: %{vm: PerplexityMacro.VM, trace_hub: PerplexityMacro.TraceHub, broker: PerplexityMacro.ResearchBroker},
|
| gateway_status: :offline, state: %{fuel: 128, transcript_hash: 0, history: []}}}
|
| end
|
|
|
|
|
| def dispatch(instr), do: GenServer.call(__MODULE__, {:dispatch, instr}, 30_000)
|
| def gateway_status, do: GenServer.call(__MODULE__, :gateway_status)
|
|
|
| @impl true
|
| def handle_call({:dispatch, %{op: "java.execute"}=instr}, _from, s) do
|
|
|
|
|
| result = case PerplexityMacro.WASMBox.execute(instr.code, %{}) do
|
| {:ok, r} -> r
|
| {:error, e} -> %{error: inspect(e)}
|
| end
|
| tlv = PerplexityMacro.Evidence.encode_tlv(result)
|
| PerplexityMacro.VM.commit_evidence(tlv)
|
| {:reply, {:ok, result, s.state}, s}
|
| end
|
|
|
| def handle_call({:dispatch, %{op: "tool.call"}=instr}, _from, s) do
|
|
|
| cap = instr.name |> String.to_atom()
|
| route = if PerplexityMacro.Capability.sensitive?(cap) and s.gateway_status == :offline do
|
|
|
| {:local, :mock}
|
| else
|
| {:gateway_or_local, cap}
|
| end
|
| result = case route do
|
| {:local, _} -> mock_tool(instr)
|
| {:gateway_or_local, _} ->
|
| case PerplexityMacro.ToolRouter.route(%{capability: cap, query: instr.arguments["query"] || ""}) do
|
| {:ok, tlv} -> tlv
|
| {:error, :confirm_required} -> %{error: "CONFIRM 0x2A required"}
|
| end
|
| end
|
| tlv = PerplexityMacro.Evidence.encode_tlv(result)
|
| PerplexityMacro.VM.commit_evidence(tlv)
|
| {:reply, {:ok, result, s.state}, s}
|
| end
|
|
|
| def handle_call({:dispatch, %{op: "vm.execute"}}, _from, s), do: {:reply, {:ok, PerplexityMacro.VM.snapshot(), s.state}, s}
|
| def handle_call({:dispatch, %{op: "final", content: c}}, _from, s), do: {:reply, {:ok, %{final: c}, s.state}, s}
|
| def handle_call(:gateway_status, _from, s), do: {:reply, s.gateway_status, s}
|
|
|
| defp mock_tool(%{name: name, arguments: args}) do
|
| %{title: name, url: "#{name}://mock", content: inspect(args), source_hash: :erlang.phash2(args, 0xFFFFFFFF)}
|
| end
|
| end
|
|
|