Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 9 additions & 20 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,17 @@
# Changelog

## Unreleased
## v0.5.0 - 2026-09-01
Comment thread
tom-ehh marked this conversation as resolved.

### Changes

- Escape raw HTML blocks in rendered markdown: LLM responses and system prompts can no longer inject markup (e.g. `<script>`) into the dashboard, and malformed markdown renders best-effort instead of raising
- Honor the `:transport` router option - `"longpoll"` previously fell through to websocket
- Use `Legion.running?/1` when sending chat messages, so agents running on other nodes (Postgres tracker) no longer crash the dashboard
- Render persisted agents whose module no longer exists instead of crashing, and show `"unknown"` for a missing agent module name
- Evict the oldest stored event when an agent passes the per-agent cap, instead of silently dropping new events
- Monitor HumanTool askers so pending questions from crashed or timed-out evals are cleaned up
- Guard all telemetry-handler sends against a restarting tracker, which previously could detach the handler
- Show "Load more" only when the tracker actually holds more agents
- Convert trace durations from native time units instead of assuming nanoseconds
- Style markdown in trace response boxes (previously referenced non-existent `prose` classes)
- Ship only `priv/static/app.css` and `priv/static/app.js` in the Hex package

- Add LLM usage tracking: `LegionWeb.AgentTracker` gains a `get_usage/1` callback, implemented by the telemetry and Postgres trackers, and the agent header shows input / output tokens and cost, with a `Usage` overlay listing totals and every request
- Add the configurable `LegionWeb.AgentTracker` interface, with telemetry-based tracking as the default
- Add `LegionWeb.AgentTracker.Postgres` for loading persisted agents and conversation events from a PostgreSQL-backed `Legion.Store`, with live updates from database notifications
- Align dashboard records, routes, PubSub messages, and human-tool integration with Legion's `agent_id` and `parent_agent_id` terminology
- Ship compiled dashboard CSS and JavaScript with the package
- Update project attribution and repository links to Software Mansion
- Add `LegionWeb.Markup` - highlight trace code in the language of the agent's `Legion.Sandbox` (Lua by default) and system-prompt fenced blocks by their fence language, backed by `makeup_syntect`
- Pluggable agent tracking - the [`LegionWeb.AgentTracker`](https://hexdocs.pm/legion_web/LegionWeb.AgentTracker.html) behaviour, [`LegionWeb.AgentTracker.Telemetry`](https://hexdocs.pm/legion_web/LegionWeb.AgentTracker.Telemetry.html) (default), [`LegionWeb.AgentTracker.Postgres`](https://hexdocs.pm/legion_web/LegionWeb.AgentTracker.Postgres.html) reading a [`Legion.Store.Postgres`](https://hexdocs.pm/legion/Legion.Store.Postgres.html) with live database notifications
- LLM usage - [`get_usage/1`](https://hexdocs.pm/legion_web/LegionWeb.AgentTracker.html#c:get_usage/1) tracker callback, tokens and estimated cost in the agent header, `Usage` overlay listing every request
- Syntax highlighting - [`LegionWeb.Markup`](https://hexdocs.pm/legion_web/LegionWeb.Markup.html) highlights trace code in the agent's [`Legion.Sandbox`](https://hexdocs.pm/legion/Legion.Sandbox.html) language (Lua by default) and system-prompt fences by language, via [makeup_syntect](https://hexdocs.pm/makeup_syntect)
- Agent identity - `agent_id` and `parent_agent_id` across records, routes, PubSub, and human-tool integration, matching Legion 0.5
- Markdown - styled trace responses, raw HTML escaped, malformed input rendered best-effort
- Pagination - agent list loads 20 agents at a time with a "Load more" button
- Hex package ships compiled assets (`priv/static/app.css`, `priv/static/app.js`)
- Fixes - [`:transport`](https://hexdocs.pm/legion_web/LegionWeb.Router.html#legion_dashboard/2) router option honored, cross-node agents via [`Legion.running?/1`](https://hexdocs.pm/legion/Legion.html#running?/1), persisted agents with a missing module, oldest-event eviction at the per-agent cap, pending HumanTool questions cleaned up on crash / timeout, telemetry handler survives tracker restarts, trace durations in native time units

## v0.3.0 - 2026-04-21

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ Add `legion_web` to your dependencies alongside `legion`:
```elixir
def deps do
[
{:legion, "~> 0.3"},
{:legion_web, "~> 0.3"}
{:legion, "~> 0.5"},
{:legion_web, "~> 0.5"}
]
end
```
Expand Down
2 changes: 1 addition & 1 deletion lib/legion_web/usage_aggregator.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule LegionWeb.UsageAggregator do
@moduledoc """
Aggregates and formats the per-request LLM usage entries returned by
`LegionWeb.AgentTracker.get_usage/1`.
`c:LegionWeb.AgentTracker.get_usage/1`.

Entries are the string-keyed maps Legion records for each LLM request
(`"input_tokens"`, `"output_tokens"`, `"cached_tokens"`, `"reasoning_tokens"`,
Expand Down
4 changes: 2 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule LegionWeb.MixProject do
use Mix.Project

@source_url "https://github.com/software-mansion-labs/legion_web"
@version "0.3.0"
@version "0.5.0"

def project do
[
Expand Down Expand Up @@ -60,7 +60,7 @@ defmodule LegionWeb.MixProject do

defp deps do
[
{:legion, git: "https://github.com/software-mansion-labs/legion.git"},
{:legion, "~> 0.5"},
{:phoenix, "~> 1.7"},
{:phoenix_html, "~> 4.0"},
{:phoenix_live_view, "~> 1.0"},
Expand Down
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"igniter": {:hex, :igniter, "0.8.3", "9de74d3885efae43b0b58dc6f7b816963c4bbd391e6b6fe6922ee21c4e384c76", [:mix], [{:ex_ast, "~> 0.5", [hex: :ex_ast, repo: "hexpm", optional: false]}, {:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4.5", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "afc5e3848d885e680da5c3b65e5e7717555a08cd12305190ff2be76427af39ff"},
"jason": {:hex, :jason, "1.4.5", "2e3a008590b0b8d7388c20293e9dcc9cf3e5d642fd2a114e4cbbb52e595d940a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b0c823996102bcd0239b3c2444eb00409b72f6a140c1950bc8b457d836b30684"},
"jsv": {:hex, :jsv, "0.22.0", "3a2bb35dd7d1ca0034437bee8099214e40d391a5e4f058f5a0800aef91c4dfeb", [:mix], [{:abnf_parsec, "~> 2.0", [hex: :abnf_parsec, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:idna, "~> 6.0 or ~> 7.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:texture, ">= 1.2.1", [hex: :texture, repo: "hexpm", optional: false]}], "hexpm", "79bae1f970413c86771051a8ea0bd553cc1e866d285270be539f1ef3ca044f3c"},
"legion": {:git, "https://github.com/software-mansion-labs/legion.git", "a430b1ee108b3a11602f259c7da3390b3e7e069a", []},
"legion": {:hex, :legion, "0.5.0", "33b4962efd035b9375523f300d1146389641ba315ac6fe78d20c42722bb70069", [:mix], [{:ecto_sql, "~> 3.13", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:lua, "~> 1.0", [hex: :lua, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.22", [hex: :postgrex, repo: "hexpm", optional: false]}, {:req_llm, "~> 1.20", [hex: :req_llm, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:vault, "~> 0.2", [hex: :vault, repo: "hexpm", optional: false]}], "hexpm", "ec1cad9943f530e4d9bace6da5c6a5d7fe566371854a2faccbf5afff1f8555df"},
"llm_db": {:hex, :llm_db, "2026.8.4", "3a0428bcd82aa31ea3fd8eaa0d62a8a454ecbc2048aebd3a276bf5d2fb60c5d6", [:mix], [{:dotenvy, "~> 1.1", [hex: :dotenvy, repo: "hexpm", optional: false]}, {:igniter, "~> 0.7", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:toml, "~> 0.7", [hex: :toml, repo: "hexpm", optional: false]}, {:zoi, "~> 0.10", [hex: :zoi, repo: "hexpm", optional: false]}], "hexpm", "570665bb4089005000e2e1e5ac28a5304769c9f16bedcebb4c3ffcbe38fce75b"},
"lua": {:hex, :lua, "1.0.2", "f349d1b8c18ac2747d698aa78fbd0b50626462cb4f4703a51b59e571d143542f", [:mix], [], "hexpm", "cf14ab77c27f1acf2fb933b82530bd728dab8a69e7a05757e21a3b49180d4690"},
"makeup": {:hex, :makeup, "1.2.2", "882d46dc0905e9ff7abf2aab61a7e6b3dcc555533977d8a23b06019e6c89ac94", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "9a1a24e5b343b8ae16abea0822c10a6f75da27af7fa802ada5251f7579bfccfa"},
Expand Down
Loading