# `Planck.Agent.Message`
[🔗](https://github.com/alexdesousa/planck/blob/v0.1.0/lib/planck/agent/message.ex#L1)

An agent-side message with metadata.

Wraps `Planck.AI.Message` content parts with an id, timestamp, and metadata map.
Messages with a `{:custom, atom()}` role are UI-only and filtered out before the
context is sent to the LLM.

# `role`

```elixir
@type role() :: :user | :assistant | :tool_result | {:custom, atom()}
```

# `t`

```elixir
@type t() :: %Planck.Agent.Message{
  content: [Planck.AI.Message.content_part()],
  id: non_neg_integer() | String.t(),
  metadata: map(),
  role: role(),
  timestamp: DateTime.t()
}
```

# `estimate_tokens`

```elixir
@spec estimate_tokens([t()]) :: non_neg_integer()
```

Estimate the token count for a list of messages using a character-based
approximation (4 characters ≈ 1 token). Fast enough for real-time display
and compaction threshold checks; not a substitute for model tokenization.

# `new`

```elixir
@spec new(role(), [Planck.AI.Message.content_part()], map()) :: t()
```

Build a new message with a generated id and current UTC timestamp.

# `to_ai_messages`

```elixir
@spec to_ai_messages([t()]) :: [Planck.AI.Message.t()]
```

Convert a list of agent messages to `Planck.AI.Message` structs.

`{:custom, :summary}` messages are converted to `:user` so the LLM sees
compacted context. All other `{:custom, _}` messages are dropped.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
