Omni.UI.Helpers (Omni UI v0.1.0)

Copy Markdown View Source

Shared helper functions used across Omni.UI components.

Provides utilities for formatting token usage, building CSS class lists, rendering markdown, and working with Omni data structures.

Summary

Functions

Builds a CSS class string from various input formats.

Finds the label for a value in a flat or grouped options list.

Pretty-prints a value as JSON.

Formats a list of Omni.Model structs into grouped select options.

Formats a token cost as a dollar amount with 4 decimal places.

Formats a token count for compact display.

Extracts and pretty-prints the text content from a tool result.

Syntax-highlights a code string as HTML.

Returns the Tailwind utility classes that apply markdown typography styles.

Returns a string key for an Omni.Model in "provider:model" format.

Returns a human-readable position string like "2/5" for an element among its siblings.

Formats a datetime as a short "time ago" label.

Converts a markdown string to HTML using MDEx with GFM and Mermaid support.

Functions

attachment_url(content)

@spec attachment_url(Omni.Content.Attachment.t()) :: String.t()

Returns a URL for an Omni.Content.Attachment.

For base64-encoded attachments, returns a data URI. For URL-sourced attachments, returns the URL as-is.

Examples

iex> attachment = %Omni.Content.Attachment{media_type: "image/png", source: {:base64, "abc123"}}
iex> Omni.UI.Helpers.attachment_url(attachment)
"data:image/png;base64,abc123"

iex> attachment = %Omni.Content.Attachment{media_type: "image/png", source: {:url, "https://example.com/img.png"}}
iex> Omni.UI.Helpers.attachment_url(attachment)
"https://example.com/img.png"

cls(input)

@spec cls(String.t()) :: String.t()
@spec cls(list()) :: String.t()
@spec cls(map()) :: String.t()

Builds a CSS class string from various input formats.

Accepts a string, a list, or a map:

  • String — returned as-is.
  • List — falsy values (nil, false) are filtered out, remaining entries are joined with spaces.
  • Map — keys whose values are truthy are included, joined with spaces.

Examples

iex> Omni.UI.Helpers.cls("foo bar")
"foo bar"

iex> Omni.UI.Helpers.cls(["foo", nil, "bar", false])
"foo bar"

iex> Omni.UI.Helpers.cls(%{"active" => true, "hidden" => false})
"active"

find_option_label(options, value)

@spec find_option_label([map()], String.t() | nil) :: String.t() | nil

Finds the label for a value in a flat or grouped options list.

Searches through options of the form %{value: v, label: l} or grouped options %{options: [%{value: v, label: l}]}. Returns the matching label or nil if not found.

Examples

iex> options = [%{value: "a", label: "Alpha"}, %{value: "b", label: "Beta"}]
iex> Omni.UI.Helpers.find_option_label(options, "b")
"Beta"

iex> grouped = [%{label: "Group", options: [%{value: "x", label: "X-ray"}]}]
iex> Omni.UI.Helpers.find_option_label(grouped, "x")
"X-ray"

iex> Omni.UI.Helpers.find_option_label([%{value: "a", label: "A"}], "z")
nil

format_json(str)

@spec format_json(String.t() | term()) :: String.t()

Pretty-prints a value as JSON.

When given a string, attempts to decode it as JSON first. If decoding succeeds, re-encodes it with pretty formatting. If the input is already a decoded data structure, encodes it directly. Falls back to the original string or inspect/1 if encoding fails.

Examples

iex> Omni.UI.Helpers.format_json(~s|{"a":1}|)
~s|{\n  "a": 1\n}|

iex> Omni.UI.Helpers.format_json("not json")
"not json"

iex> Omni.UI.Helpers.format_json(%{"key" => "value"})
~s|{\n  "key": "value"\n}|

format_model_options(models)

@spec format_model_options([Omni.Model.t()] | nil) :: [map()] | nil

Formats a list of Omni.Model structs into grouped select options.

Groups models by provider name, sorts both groups and models alphabetically, and returns a list of %{label: provider, options: [%{value: key, label: name}]} maps suitable for the select component. Returns nil for nil or empty input.

format_token_cost(cost)

@spec format_token_cost(number() | nil) :: String.t()

Formats a token cost as a dollar amount with 4 decimal places.

Returns "-" for nil.

Examples

iex> Omni.UI.Helpers.format_token_cost(0.0123)
"0.0123"

iex> Omni.UI.Helpers.format_token_cost(nil)
"-"

format_token_count(count)

@spec format_token_count(non_neg_integer() | nil) :: String.t()

Formats a token count for compact display.

Counts under 1,000 are shown as-is. Counts from 1,000–9,999 are shown with one decimal place (e.g. "1.5k"). Counts of 10,000+ are rounded to the nearest thousand (e.g. "42k"). Returns "-" for nil.

Examples

iex> Omni.UI.Helpers.format_token_count(500)
"500"

iex> Omni.UI.Helpers.format_token_count(1_500)
"1.5k"

iex> Omni.UI.Helpers.format_token_count(42_000)
"42k"

iex> Omni.UI.Helpers.format_token_count(nil)
"-"

format_tool_result(result)

@spec format_tool_result(Omni.Content.ToolResult.t()) :: String.t()

Extracts and pretty-prints the text content from a tool result.

Filters for Omni.Content.Text entries in the result's content list, joins their text, and formats the combined string as JSON.

Examples

iex> result = %Omni.Content.ToolResult{tool_use_id: "1", name: "search", content: [%Omni.Content.Text{text: ~s|{"ok":true}|}]}
iex> Omni.UI.Helpers.format_tool_result(result)
~s|{\n  "ok": true\n}|

highlight_code(code, lang \\ nil)

@spec highlight_code(String.t(), String.t() | nil) :: Phoenix.HTML.safe()

Syntax-highlights a code string as HTML.

Uses Lumis with inline styles (catppuccin_macchiato theme) so the output is self-contained — no external CSS needed. When lang is nil, Lumis auto-detects the language. The lang value can be a language name ("elixir", "json") or a filename ("report.html").

Returns a Phoenix.HTML.safe/0 tuple for direct use in HEEx templates.

md_styles()

@spec md_styles() :: [String.t()]

Returns the Tailwind utility classes that apply markdown typography styles.

Applied at the chat_interface/1 level via descendant selectors targeting the .mdex class, so individual markdown components stay minimal.

model_key(model)

@spec model_key(Omni.Model.t()) :: String.t()

Returns a string key for an Omni.Model in "provider:model" format.

Uses Omni.Model.to_ref/1 to resolve the provider atom and model ID, then joins them with a colon.

sibling_pos(id, siblings)

@spec sibling_pos(term(), list()) :: String.t()

Returns a human-readable position string like "2/5" for an element among its siblings.

Examples

iex> Omni.UI.Helpers.sibling_pos(:b, [:a, :b, :c])
"2/3"

time_ago(dt, fallback_format \\ "%Y-%m-%d %H:%M")

@spec time_ago(DateTime.t(), String.t()) :: String.t()

Formats a datetime as a short "time ago" label.

Returns one of:

  • "just now" for under a minute
  • "Xm ago" / "Xh ago" / "Xd ago" for up to a week
  • a formatted absolute date beyond that (default: "Apr 13")

The second argument is the Calendar.strftime/2 format string used for the absolute-date fallback, so callers can control how old dates render (e.g. the chat timestamp might want to include the year, the sessions list might prefer month + day).

Examples

iex> Omni.UI.Helpers.time_ago(DateTime.utc_now())
"just now"

iex> dt = DateTime.add(DateTime.utc_now(), -300, :second)
iex> Omni.UI.Helpers.time_ago(dt)
"5m ago"

to_md(text, opts \\ [])

@spec to_md(
  String.t(),
  keyword()
) :: Phoenix.HTML.safe()

Converts a markdown string to HTML using MDEx with GFM and Mermaid support.

Returns a Phoenix.HTML.safe/0 tuple for direct use in HEEx templates.

Options

  • :streaming - when true, enables MDEx streaming mode for incremental rendering of in-progress content. Defaults to false.