Jido.AI.Prompt (Jido AI v0.5.1)

View Source

A module that provides struct-based prompt generation.

The struct-based approach provides full visibility into the prompt's content when inspecting the agent state, making it easier to debug and understand the conversation flow.

Examples

# Create a simple prompt with a single message
prompt = Jido.AI.Prompt.new(%{
  messages: [
    %{role: :user, content: "Hello"}
  ]
})

# Create a prompt with EEx templates
prompt = Jido.AI.Prompt.new(%{
  messages: [
    %{role: :system, content: "You are a <%= @assistant_type %>", engine: :eex},
    %{role: :user, content: "Hello <%= @name %>", engine: :eex}
  ],
  params: %{
    assistant_type: "helpful assistant",
    name: "Alice"
  }
})

# Create a prompt with Liquid templates
prompt = Jido.AI.Prompt.new(%{
  messages: [
    %{role: :system, content: "You are a {{ assistant_type }}", engine: :liquid},
    %{role: :user, content: "Hello {{ name }}", engine: :liquid}
  ],
  params: %{
    assistant_type: "helpful assistant",
    name: "Alice"
  }
})

# Render the prompt to get the final messages
messages = Jido.AI.Prompt.render(prompt)
# => [
#      %{role: :system, content: "You are a helpful assistant"},
#      %{role: :user, content: "Hello Alice"}
#    ]

Summary

Types

t()

A complete prompt with messages and parameters

Functions

Adds a new message to the prompt.

Compares two versions of a prompt and returns the differences.

Gets a specific version of the prompt.

Lists all available versions of the prompt.

Creates a new prompt struct from the given attributes.

Creates a new prompt with a single message.

Creates a new version of the prompt.

Renders the prompt into a list of messages with interpolated content.

Converts the prompt to a single text string.

Validates and converts the prompt option.

Types

t()

@type t() :: %Jido.AI.Prompt{
  history: [map()],
  id: String.t(),
  messages: [Jido.AI.Prompt.MessageItem.t()],
  metadata: map(),
  params: map(),
  version: non_neg_integer()
}

A complete prompt with messages and parameters

Functions

add_message(prompt, role, content, opts \\ [])

@spec add_message(t(), atom(), String.t(), keyword()) :: t()

Adds a new message to the prompt.

Enforces the rule that system messages can only appear first in the message list. Raises ArgumentError if attempting to add a system message in any other position.

Examples

iex> alias Jido.AI.Prompt
iex> prompt = Prompt.new(%{
...>   messages: [
...>     %{role: :user, content: "Hello"}
...>   ]
...> })
iex> updated = Prompt.add_message(prompt, :assistant, "Hi there!")
iex> length(updated.messages)
2
iex> List.last(updated.messages).content
"Hi there!"

compare_versions(prompt, version1, version2)

@spec compare_versions(t(), non_neg_integer(), non_neg_integer()) ::
  {:ok, %{added_messages: [map()], removed_messages: [map()]}}
  | {:error, String.t()}

Compares two versions of a prompt and returns the differences.

Examples

iex> alias Jido.AI.Prompt
iex> prompt = Prompt.new(:user, "Hello")
iex> v2 = Prompt.new_version(prompt, fn p -> Prompt.add_message(p, :assistant, "Hi there!") end)
iex> {:ok, diff} = Prompt.compare_versions(v2, 2, 1)
iex> diff.added_messages
[%{role: :assistant, content: "Hi there!"}]

get_version(prompt, version)

@spec get_version(t(), non_neg_integer()) :: {:ok, t()} | {:error, String.t()}

Gets a specific version of the prompt.

Returns the current prompt if version matches the current version, or reconstructs a historical version from the history.

Examples

iex> alias Jido.AI.Prompt
iex> prompt = Prompt.new(:user, "Hello")
iex> updated = Prompt.new_version(prompt, fn p -> Prompt.add_message(p, :assistant, "Hi there!") end)
iex> {:ok, original} = Prompt.get_version(updated, 1)
iex> length(original.messages)
1
iex> hd(original.messages).content
"Hello"

list_versions(prompt)

@spec list_versions(t()) :: [non_neg_integer()]

Lists all available versions of the prompt.

Returns a list of version numbers, with the most recent first.

Examples

iex> alias Jido.AI.Prompt
iex> prompt = Prompt.new(:user, "Hello")
iex> v2 = Prompt.new_version(prompt, fn p -> Prompt.add_message(p, :assistant, "Hi there!") end)
iex> v3 = Prompt.new_version(v2, fn p -> Prompt.add_message(p, :user, "How are you?") end)
iex> Prompt.list_versions(v3)
[3, 2, 1]

new(attrs)

Creates a new prompt struct from the given attributes.

Rules

  • Only one system message is allowed
  • If present, the system message must be the first message
  • Messages are rendered without the engine field

Examples

iex> alias Jido.AI.Prompt
iex> prompt = Prompt.new(%{
...>   messages: [
...>     %{role: :user, content: "Hello"}
...>   ]
...> })
iex> prompt.messages |> length()
1
iex> hd(prompt.messages).role
:user
iex> hd(prompt.messages).content
"Hello"

new(role, content, opts \\ [])

Creates a new prompt with a single message.

This is a convenience function for creating a prompt with a single message.

Examples

iex> alias Jido.AI.Prompt
iex> prompt = Prompt.new(:user, "Hello")
iex> prompt.messages |> length()
1
iex> hd(prompt.messages).role
:user
iex> hd(prompt.messages).content
"Hello"

new_version(prompt, change_fn)

@spec new_version(t(), (t() -> t())) :: t()

Creates a new version of the prompt.

This function creates a new version of the prompt by:

  1. Storing the current state in the history
  2. Incrementing the version number
  3. Applying the changes to the prompt

Examples

iex> alias Jido.AI.Prompt
iex> prompt = Prompt.new(:user, "Hello")
iex> updated = Prompt.new_version(prompt, fn p -> Prompt.add_message(p, :assistant, "Hi there!") end)
iex> updated.version
2
iex> length(updated.history)
1
iex> length(updated.messages)
2

render(prompt, override_params \\ %{})

@spec render(t(), map()) :: [%{role: atom(), content: String.t()}]

Renders the prompt into a list of messages with interpolated content.

The rendered messages will only include the role and content fields, excluding the engine field to ensure compatibility with API requests.

Examples

iex> alias Jido.AI.Prompt
iex> prompt = Prompt.new(%{
...>   messages: [
...>     %{role: :user, content: "Hello <%= @name %>", engine: :eex}
...>   ],
...>   params: %{name: "Alice"}
...> })
iex> Prompt.render(prompt)
[%{role: :user, content: "Hello Alice"}]

to_text(prompt, override_params \\ %{})

@spec to_text(t(), map()) :: String.t()

Converts the prompt to a single text string.

This is useful for debugging or when the LLM API expects a single text prompt.

Examples

iex> alias Jido.AI.Prompt
iex> prompt = Prompt.new(%{
...>   messages: [
...>     %{role: :system, content: "You are an assistant"},
...>     %{role: :user, content: "Hello"}
...>   ]
...> })
iex> Prompt.to_text(prompt)
"[system] You are an assistant\n[user] Hello"

validate_prompt_opts(prompt)

@spec validate_prompt_opts(String.t() | t()) :: {:ok, t()} | {:error, String.t()}

Validates and converts the prompt option.

Accepts either:

  • A string, which is converted to a system message in a Prompt struct
  • An existing Prompt struct, which is returned as-is

Examples

iex> Jido.AI.Prompt.validate_prompt_opts("You are a helpful assistant")
{:ok, %Jido.AI.Prompt{messages: [%Jido.AI.Prompt.MessageItem{role: :system, content: "You are a helpful assistant", engine: :none}], id: nil, version: 1, history: [], params: %{}, metadata: %{}}}

iex> prompt = Jido.AI.Prompt.new(:system, "Custom prompt")
iex> Jido.AI.Prompt.validate_prompt_opts(prompt)
{:ok, prompt}