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 attributesupdate/2,update!/2- Update an existing character with new attributesvalidate/1- Validate a character mapto_context/2- Convert a character to a ReqLLM.Context structto_system_prompt/2- Generate a system prompt string from a characterevolve/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)
endUse the ! variants (new!/1, update!/2) when you prefer exceptions over tuples.
Summary
Functions
Add an expression to a character's voice.
Add a fact to a character's identity.
Add an instruction to a character.
Add knowledge to a character.
Add a memory entry to a character.
Add a quirk to a character's personality.
Add a trait to a character's personality.
Add a value to a character's personality.
Evolve a character over a period of simulated time.
Evolve a character, raising on validation errors.
Creates a new character, raising on validation errors.
Updates a character, raising on validation errors.
Types
@type errors() :: [Zoi.Error.t()]
@type t() :: %{ :id => String.t(), optional(:name) => String.t() | nil, optional(:description) => String.t() | nil, optional(:identity) => Jido.Character.Schema.Identity.t() | nil, optional(:personality) => Jido.Character.Schema.Personality.t() | nil, optional(:voice) => Jido.Character.Schema.Voice.t() | nil, optional(:memory) => Jido.Character.Schema.Memory.t() | nil, optional(:knowledge) => [Jido.Character.Schema.KnowledgeItem.t()], optional(:instructions) => [String.t()], optional(:extensions) => map(), optional(:created_at) => DateTime.t() | nil, optional(:updated_at) => DateTime.t() | nil, optional(:version) => 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())
Functions
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 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 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"])
@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 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 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"])
@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 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 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 integeridentity.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 a character, raising on validation errors.
Examples
older = Jido.Character.evolve!(char, years: 1)Raises ArgumentError if validation fails.
Creates a new character, raising on validation errors.
Examples
bob = Jido.Character.new!(%{name: "Bob"})Raises ArgumentError if validation fails.
@spec to_context( t(), keyword() ) :: ReqLLM.Context.t()
Updates a character, raising on validation errors.
Examples
bob = Jido.Character.update!(bob, %{name: "Robert"})Raises ArgumentError if validation fails.