Packages

A Fair Source multi-agent runtime with deterministic agent scoring and replayable run history.

Retired package: Deprecated - superseded — operator console moved to the Syntropy app

Current section

Files

Jump to
syntropy lib syntropy_web live tasks_live.ex
Raw

lib/syntropy_web/live/tasks_live.ex

defmodule SyntropyWeb.TasksLive do
use SyntropyWeb, :live_view
import SyntropyWeb.RuntimeViewHelpers
alias Syntropy.{HistoryStore, RecommendationStore, TaskScheduler}
@history_limit 20
@impl true
def mount(_params, _session, socket) do
if connected?(socket) do
Phoenix.PubSub.subscribe(Syntropy.PubSub, "lattice:events")
end
{:ok, assign(socket, task_entries: build_task_entries())}
end
@impl true
def handle_info({:lattice_event, _event}, socket) do
{:noreply, assign(socket, task_entries: build_task_entries())}
end
@impl true
def render(assigns) do
~H"""
<main class="dashboard">
<section>
<p class="eyebrow">// SYNTROPY</p>
<h1>Task History</h1>
<nav>
<.link navigate={~p"/"}>Lattice</.link>
<span> · </span>
<.link navigate={~p"/history"}>History</.link>
</nav>
</section>
<section>
<%= if @task_entries == [] do %>
<p id="tasks-empty">No completed tasks yet.</p>
<% else %>
<ul id="task-history">
<%= for entry <- @task_entries do %>
<li id={"task-#{entry.task.task_id}"}>
<article>
<h2><%= entry.task.task_id %></h2>
<p><strong>Node:</strong> <%= node_id_for(entry.task) %></p>
<p>
<strong>Strategy:</strong> <%= entry.task.strategy %>
-> <%= entry.task.resolved_mode %>
</p>
<p>
<strong>Selected Agents:</strong>
<%= Enum.join(entry.task.selected_agent_ids, ", ") %>
</p>
<p><strong>Synthesis:</strong> <%= entry.task.synthesis %></p>
<%= if entry.snapshot do %>
<p>
<strong>Snapshot:</strong>
<.link navigate={graph_path(entry.snapshot.id, List.first(entry.task.selected_agent_ids))}>
<%= entry.snapshot.id %>
</.link>
<span> · </span>
<span>node <%= node_id_for(entry.snapshot) %></span>
<span> · </span>
<.link navigate={~p"/history?snapshot=#{entry.snapshot.id}"}>history detail</.link>
</p>
<% end %>
<p>
<strong>Graph:</strong>
<%= for {agent_id, index} <- Enum.with_index(entry.task.selected_agent_ids) do %>
<span>
<%= if index > 0, do: ", " %>
<.link navigate={graph_path(entry.snapshot && entry.snapshot.id, agent_id)}>
<%= agent_id %>
</.link>
</span>
<% end %>
</p>
<%= if entry.recommendations != [] do %>
<p>
<strong>Recommendations:</strong>
<%= for {recommendation, index} <- Enum.with_index(entry.recommendations) do %>
<span>
<%= if index > 0, do: ", " %>
<.link
navigate={
graph_path(
entry.snapshot && entry.snapshot.id,
List.first(recommendation.candidate_agent_ids)
)
}
>
<%= recommendation.id %>
</.link> (<%= recommendation.status %>, node <%= node_id_for(recommendation) %>)
</span>
<% end %>
</p>
<% end %>
<div>
<h3>Selection Trace</h3>
<ul>
<%= for trace <- entry.task.selection_trace do %>
<li>
<strong><%= trace.agent_name %></strong>
<span> · rank <%= trace.rank %></span>
<span> · rel <%= format_score(trace.relevance) %></span>
<span> · pos <%= format_score(trace.position) %></span>
<span> · cap <%= format_score(trace.capacity) %></span>
<span> · total <%= format_score(trace.composite) %></span>
<span><%= if trace.selected, do: " · selected", else: "" %></span>
</li>
<% end %>
</ul>
</div>
</article>
</li>
<% end %>
</ul>
<% end %>
</section>
</main>
"""
end
defp build_task_entries do
snapshots = HistoryStore.recent(@history_limit)
snapshots_by_task_id =
Map.new(snapshots, fn snapshot ->
{snapshot.task_id, snapshot}
end)
recommendations = RecommendationStore.recent(@history_limit)
recommendations_by_id = Map.new(recommendations, &{&1.id, &1})
Enum.map(TaskScheduler.recent(@history_limit), fn task ->
%{
task: task,
snapshot: Map.get(snapshots_by_task_id, task.task_id),
recommendations:
task.recommendation_ids
|> Enum.map(&Map.get(recommendations_by_id, &1))
|> Enum.reject(&is_nil/1)
}
end)
end
defp graph_path(snapshot_id, agent_id) do
params =
%{}
|> maybe_put("snapshot", snapshot_id)
|> maybe_put("agent", agent_id)
~p"/?#{params}"
end
defp maybe_put(params, _key, nil), do: params
defp maybe_put(params, key, value), do: Map.put(params, key, value)
end