# `Jido.Character`
[🔗](https://github.com/agentjido/jido_character/blob/v1.0.0/lib/jido_character.ex#L1)

Extensible character definition for AI agents.

## Direct API

    {:ok, bob} = Jido.Character.new(%{name: "Bob"})
    {:ok, bob} = Jido.Character.update(bob, %{identity: %{role: "Assistant"}})
    {:ok, bob} = Jido.Character.validate(bob)
    context = Jido.Character.to_context(bob)
    prompt = Jido.Character.to_system_prompt(bob)

## Raising Variants

    bob = Jido.Character.new!(%{name: "Bob"})
    bob = Jido.Character.update!(bob, %{identity: %{role: "Assistant"}})

## Module-Based Characters

    defmodule MyApp.Characters.Alice do
      use Jido.Character,
        defaults: %{name: "Alice"}
    end

    {:ok, alice} = MyApp.Characters.Alice.new()

## Functions

- `new/1`, `new!/1` - Create a new character from a map of attributes
- `update/2`, `update!/2` - Update an existing character with new attributes
- `validate/1` - Validate a character map
- `to_context/2` - Convert a character to a ReqLLM.Context struct
- `to_system_prompt/2` - Generate a system prompt string from a character
- `evolve/2`, `evolve!/2` - Evolve a character over simulated time

## Error Handling

Functions returning `{:ok, t()} | {:error, errors()}` use Zoi validation errors.
The `errors()` type is a list of `Zoi.Error.t()` structs with detailed information:

    case Jido.Character.new(%{}) do
      {:ok, char} -> char
      {:error, errors} ->
        Enum.each(errors, fn error ->
          IO.puts("Field #{inspect(error.path)}: #{error.message}")
        end)
    end

Use the `!` variants (`new!/1`, `update!/2`) when you prefer exceptions over tuples.

# `errors`

```elixir
@type errors() :: [Zoi.Error.t()]
```

# `t`

```elixir
@type t() :: %{
  :id =&gt; String.t(),
  optional(:name) =&gt; String.t() | nil,
  optional(:description) =&gt; String.t() | nil,
  optional(:identity) =&gt; Jido.Character.Schema.Identity.t() | nil,
  optional(:personality) =&gt; Jido.Character.Schema.Personality.t() | nil,
  optional(:voice) =&gt; Jido.Character.Schema.Voice.t() | nil,
  optional(:memory) =&gt; Jido.Character.Schema.Memory.t() | nil,
  optional(:knowledge) =&gt; [Jido.Character.Schema.KnowledgeItem.t()],
  optional(:instructions) =&gt; [String.t()],
  optional(:extensions) =&gt; map(),
  optional(:created_at) =&gt; DateTime.t() | nil,
  optional(:updated_at) =&gt; DateTime.t() | nil,
  optional(:version) =&gt; non_neg_integer()
}
```

A character map with the following fields:

- `:id` (required) - Unique identifier (String.t())
- `:name` - Character name (String.t() | nil)
- `:description` - Character description (String.t() | nil)
- `:identity` - Who the character is (Schema.Identity.t() | nil)
- `:personality` - How the character behaves (Schema.Personality.t() | nil)
- `:voice` - How the character communicates (Schema.Voice.t() | nil)
- `:memory` - What the character remembers (Schema.Memory.t() | nil)
- `:knowledge` - Permanent facts the character knows ([Schema.KnowledgeItem.t()])
- `:instructions` - Behavioral instructions ([String.t()])
- `:extensions` - Custom extension data (map())
- `:created_at` - Creation timestamp (DateTime.t() | nil)
- `:updated_at` - Last update timestamp (DateTime.t() | nil)
- `:version` - Version number (non_neg_integer())

# `add_expression`

```elixir
@spec add_expression(t(), String.t() | [String.t()]) ::
  {:ok, t()} | {:error, errors()}
```

Add an expression to a character's voice.

## Examples

    {:ok, char} = Jido.Character.add_expression(char, "Let me think about that...")
    {:ok, char} = Jido.Character.add_expression(char, ["Let me think...", "Interesting point!"])

# `add_fact`

```elixir
@spec add_fact(t(), String.t() | [String.t()]) :: {:ok, t()} | {:error, errors()}
```

Add a fact to a character's identity.

## Examples

    {:ok, char} = Jido.Character.add_fact(char, "Has a PhD in Computer Science")
    {:ok, char} = Jido.Character.add_fact(char, ["Has a PhD", "Worked at 3 startups"])

# `add_instruction`

```elixir
@spec add_instruction(t(), String.t() | [String.t()]) ::
  {:ok, t()} | {:error, errors()}
```

Add an instruction to a character.

## Examples

    {:ok, char} = Jido.Character.add_instruction(char, "Always be helpful")

    # Multiple
    {:ok, char} = Jido.Character.add_instruction(char, ["Be helpful", "Be concise"])

# `add_knowledge`

```elixir
@spec add_knowledge(t(), String.t() | map() | [String.t() | map()], keyword()) ::
  {:ok, t()} | {:error, errors()}
```

Add knowledge to a character.

## Examples

    # String shorthand
    {:ok, char} = Jido.Character.add_knowledge(char, "Expert in Elixir")

    # With options
    {:ok, char} = Jido.Character.add_knowledge(char, "Expert in Elixir", category: "skills", importance: 0.9)

    # Multiple items
    {:ok, char} = Jido.Character.add_knowledge(char, ["Knows Elixir", "Knows Python"])

    # Full map
    {:ok, char} = Jido.Character.add_knowledge(char, %{content: "Expert in Elixir", importance: 0.9})

# `add_memory`

```elixir
@spec add_memory(t(), String.t() | map(), keyword()) ::
  {:ok, t()} | {:error, errors()}
```

Add a memory entry to a character.

Memory entries are subject to the character's memory capacity. When adding
an entry would exceed capacity, the oldest entries are dropped to make room.

## Examples

    # String shorthand
    {:ok, char} = Jido.Character.add_memory(char, "User prefers brief answers")

    # With options
    {:ok, char} = Jido.Character.add_memory(char, "Important event", importance: 0.9, category: "events")

    # Full map
    {:ok, char} = Jido.Character.add_memory(char, %{content: "User said hello", importance: 0.5})

# `add_quirk`

```elixir
@spec add_quirk(t(), String.t() | [String.t()]) :: {:ok, t()} | {:error, errors()}
```

Add a quirk to a character's personality.

## Examples

    {:ok, char} = Jido.Character.add_quirk(char, "Uses analogies frequently")
    {:ok, char} = Jido.Character.add_quirk(char, ["Uses analogies", "Asks clarifying questions"])

# `add_trait`

```elixir
@spec add_trait(t(), String.t() | map() | [String.t() | map()], keyword()) ::
  {:ok, t()} | {:error, errors()}
```

Add a trait to a character's personality.

## Examples

    # String shorthand
    {:ok, char} = Jido.Character.add_trait(char, "curious")

    # With intensity
    {:ok, char} = Jido.Character.add_trait(char, "analytical", intensity: 0.9)

    # Multiple
    {:ok, char} = Jido.Character.add_trait(char, ["curious", "patient"])

# `add_value`

```elixir
@spec add_value(t(), String.t() | [String.t()]) :: {:ok, t()} | {:error, errors()}
```

Add a value to a character's personality.

## Examples

    {:ok, char} = Jido.Character.add_value(char, "accuracy")
    {:ok, char} = Jido.Character.add_value(char, ["accuracy", "clarity"])

# `evolve`

```elixir
@spec evolve(
  t(),
  keyword()
) :: {:ok, t()} | {:error, errors()}
```

Evolve a character over a period of simulated time.

Time is relative: pass the delta since the last evolution call.

## Options

  * `:days` - number of days to advance (default: 0)
  * `:years` - number of years to advance (default: 0)
  * `:age?` - whether to update integer `identity.age` (default: true)
  * `:memory?` - whether to apply memory decay (default: true)
  * `:memory_prune_below` - drop memories whose decayed importance
      falls below this threshold (default: 0.05, set to nil to disable)

## Examples

    # Age by one year
    {:ok, older} = Jido.Character.evolve(char, years: 1)

    # Age by 30 days, decay memories
    {:ok, evolved} = Jido.Character.evolve(char, days: 30)

    # Only decay memories, don't age
    {:ok, evolved} = Jido.Character.evolve(char, days: 7, age?: false)

    # Disable memory pruning
    {:ok, evolved} = Jido.Character.evolve(char, days: 30, memory_prune_below: nil)

# `evolve!`

```elixir
@spec evolve!(
  t(),
  keyword()
) :: t()
```

Evolve a character, raising on validation errors.

## Examples

    older = Jido.Character.evolve!(char, years: 1)

Raises `ArgumentError` if validation fails.

# `new`

```elixir
@spec new(map()) :: {:ok, t()} | {:error, errors()}
```

# `new!`

```elixir
@spec new!(map()) :: t()
```

Creates a new character, raising on validation errors.

## Examples

    bob = Jido.Character.new!(%{name: "Bob"})

Raises `ArgumentError` if validation fails.

# `to_context`

```elixir
@spec to_context(
  t(),
  keyword()
) :: ReqLLM.Context.t()
```

# `to_system_prompt`

```elixir
@spec to_system_prompt(
  t(),
  keyword()
) :: String.t()
```

# `update`

```elixir
@spec update(t(), map()) :: {:ok, t()} | {:error, errors()}
```

# `update!`

```elixir
@spec update!(t(), map()) :: t()
```

Updates a character, raising on validation errors.

## Examples

    bob = Jido.Character.update!(bob, %{name: "Robert"})

Raises `ArgumentError` if validation fails.

# `validate`

```elixir
@spec validate(map()) :: {:ok, t()} | {:error, errors()}
```

---

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