Powered by AppSignal & Oban Pro

Jidoka: Characters And Instructions

07_characters_and_instructions.livemd

Jidoka: Characters And Instructions

Run in Livebook

Characters provide structured persona and voice. Instructions still define the task. Jidoka renders the character before instructions in the effective system prompt.

Setup

Mix.install(
  [
    {:jidoka, git: "https://github.com/mikehostetler/jidoka.git", ref: "924a486f3c1b7e7a943cb3d5ceee0de65f158467"},
    {:kino, "~> 0.19.0"}
  ],
  config: [
    jidoka: [
      model_aliases: %{fast: "anthropic:claude-haiku-4-5"}
    ]
  ]
)
Jidoka.Kino.setup()

Define Characters

defmodule LivebookDemo.Characters.SupportAdvisor do
  use Jido.Character,
    defaults: %{
      name: "Support Advisor",
      identity: %{role: "Support specialist"},
      voice: %{tone: :professional, style: "Clear and concise"},
      instructions: ["Use the configured support persona."]
    }
end

defmodule LivebookDemo.Characters.Agent do
  use Jidoka.Agent

  agent do
    id :livebook_character_agent
  end

  defaults do
    model :fast
    character LivebookDemo.Characters.SupportAdvisor
    instructions "Adapt the answer to the account tier."
  end
end
%{
  configured_character: LivebookDemo.Characters.Agent.character(),
  instructions: LivebookDemo.Characters.Agent.instructions()
}

Inspect The Effective Prompt

request = %{messages: [%{role: :user, content: "hello"}], llm_opts: [], tools: %{}}
state = Jido.AI.Reasoning.ReAct.State.new("hello", nil, request_id: "req-character", run_id: "run-character")

config =
  Jido.AI.Reasoning.ReAct.Config.new(
    model: :fast,
    system_prompt: nil,
    request_transformer: LivebookDemo.Characters.Agent.request_transformer(),
    streaming: false
  )

{:ok, %{messages: [%{role: :system, content: prompt}, %{role: :user, content: "hello"}]}} =
  LivebookDemo.Characters.Agent.request_transformer().transform_request(request, state, config, %{})

prompt

Override Character Per Turn

Runtime character overrides are explicit chat/3 options, so applications can choose when a persona changes.

{:ok, opts} =
  Jidoka.Agent.prepare_chat_opts(
    [
      character: %{
        name: "Runtime Advisor",
        voice: %{tone: :warm},
        instructions: ["Use the runtime persona for this turn only."]
      }
    ],
    %{context: %{}, context_schema: nil}
  )

runtime_context = Keyword.fetch!(opts, :tool_context)

{:ok, %{messages: [%{role: :system, content: runtime_prompt}, _user]}} =
  LivebookDemo.Characters.Agent.request_transformer().transform_request(
    request,
    state,
    config,
    runtime_context
  )

runtime_prompt

Optional Provider Turn

{:ok, pid} =
  Jidoka.Kino.start_or_reuse("livebook-character-agent", fn ->
    LivebookDemo.Characters.Agent.start_link(id: "livebook-character-agent")
  end)

Jidoka.Kino.chat("Character chat", fn ->
  LivebookDemo.Characters.Agent.chat(pid, "Explain the value of character prompts in one sentence.")
end)