Annotai.Annotation (Annotai v0.1.0)

Copy Markdown View Source

The canonical representation of a developer annotation.

An annotation is created in the browser by the widget (POST /annotai/api/annotations), enriched and owned by Annotai.Store, and read by the AI agent through the tools in Annotai.MCP.

This struct is the single source of truth for an annotation's shape. It is built from the widget's string-keyed JSON via new/1, and serialized back to string-keyed JSON at the HTTP and MCP edges through the derived Jason.Encoder — atom fields such as :status encode as their string names (e.g. "pending"), which is exactly what the widget reads back.

Timestamps are kept as ISO-8601 strings so they survive the JSON round-trip unchanged.

Summary

Types

A reply-thread entry: %{"role" => _, "content" => _, "at" => _}.

t()

Functions

Build an annotation from the widget's string-keyed JSON params.

Return the annotation with each image's base64 "data" stripped, keeping only metadata (id, mime, width, height).

The valid lifecycle statuses, in order.

Types

message()

@type message() :: %{optional(String.t()) => String.t()}

A reply-thread entry: %{"role" => _, "content" => _, "at" => _}.

status()

@type status() :: :pending | :acknowledged | :resolved | :dismissed

t()

@type t() :: %Annotai.Annotation{
  anchor_frac: map() | nil,
  anchor_index: non_neg_integer() | nil,
  bounding_box: map() | nil,
  comment: String.t() | nil,
  component: String.t() | nil,
  css_classes: String.t() | nil,
  element: String.t() | nil,
  element_path: String.t() | nil,
  id: String.t() | nil,
  images: [map()],
  inserted_at: String.t() | nil,
  nearby_text: String.t() | nil,
  phx_selector: String.t() | nil,
  point: map() | nil,
  resolved_at: String.t() | nil,
  resolved_by: :human | :agent | nil,
  selected_text: String.t() | nil,
  source_file: String.t() | nil,
  source_line: non_neg_integer() | nil,
  status: status(),
  thread: [message()],
  url: String.t() | nil
}

Functions

new(params)

@spec new(map()) :: t()

Build an annotation from the widget's string-keyed JSON params.

Unrecognized keys are ignored; status is normalized to an atom (defaulting to :pending). id and inserted_at are left nil for Annotai.Store.put/1 to fill in. resolved_by/resolved_at are never accepted from the client.

redact_images(annotation)

@spec redact_images(t()) :: t()

Return the annotation with each image's base64 "data" stripped, keeping only metadata (id, mime, width, height).

Used at every JSON edge (REST responses, the MCP text block) so heavy image bytes never ride along the annotation list / 2s poll. The bytes are fetched on demand from the image route and embedded as MCP image blocks instead.

statuses()

@spec statuses() :: [status()]

The valid lifecycle statuses, in order.