Jido.Character (Jido Character v1.0.0)

Copy Markdown View Source

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

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.

Summary

Types

t()

A character map with the following fields

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

errors()

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

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_expression(character, expression)

@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(character, fact)

@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(character, instruction)

@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(character, content, opts \\ [])

@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(character, content, opts \\ [])

@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(character, quirk)

@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(character, trait, opts \\ [])

@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(character, value)

@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(character, opts \\ [])

@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!(character, opts \\ [])

@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(attrs \\ %{})

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

new!(attrs \\ %{})

@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(character, opts \\ [])

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

to_system_prompt(character, opts \\ [])

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

update(character, attrs)

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

update!(character, attrs)

@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(attrs)

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