Lesson 08 Livebook: AI Studio Mode
This notebook keeps the AI example deterministic by using the lesson’s fake adapter instead of a real model call.
Mix.install([
{:ai_studio_mode, path: "../08_ai_studio_mode"}
])
Application.ensure_all_started(:ai_studio_mode)
Helpers
defmodule Lesson08Helpers do
alias AIStudioMode.StudioJido
def unique_agent_id(prefix) do
"#{prefix}-#{System.unique_integer([:positive])}"
end
def wait_until(fun, attempts \\ 40)
def wait_until(fun, attempts) when attempts > 0 do
case fun.() do
nil ->
Process.sleep(50)
wait_until(fun, attempts - 1)
value ->
value
end
end
def wait_until(_fun, 0) do
raise "condition was not met before the timeout"
end
def safe_stop_family(ceo_id) do
child_ids = [
"#{ceo_id}/product_manager/designer",
"#{ceo_id}/product_manager/qa",
"#{ceo_id}/product_manager",
"#{ceo_id}/cto"
]
Enum.each(child_ids, fn child_id ->
case StudioJido.whereis(child_id) do
nil -> :ok
_pid -> StudioJido.stop_agent(child_id)
end
end)
case StudioJido.whereis(ceo_id) do
nil -> :ok
_pid -> StudioJido.stop_agent(ceo_id)
end
end
end
Run One AI-Assisted Planning Round
alias AIStudioMode.{AIAdapters, CEOAgent, StudioJido}
alias Jido.AgentServer
alias Jido.Signal
ceo_id = Lesson08Helpers.unique_agent_id("ceo-ai")
{:ok, ceo_pid} =
StudioJido.start_agent(CEOAgent,
id: ceo_id,
initial_state: %{ai_adapter: AIAdapters.FakeAdapter}
)
{:ok, _ceo} =
AgentServer.call(
ceo_pid,
Signal.new!("studio.ai_staff_requested", %{}, source: "/ceo")
)
staffed_ceo_state =
Lesson08Helpers.wait_until(fn ->
{:ok, state} = AgentServer.state(ceo_pid)
if Map.has_key?(state.children, :cto) and Map.has_key?(state.children, :product_manager) do
state
end
end)
pm_pid = staffed_ceo_state.children.product_manager.pid
_staffed_pm_state =
Lesson08Helpers.wait_until(fn ->
{:ok, state} = AgentServer.state(pm_pid)
if Map.has_key?(state.children, :designer) and Map.has_key?(state.children, :qa) do
state
end
end)
{:ok, _ceo} =
AgentServer.call(
ceo_pid,
Signal.new!(
"studio.ai_planning_round_requested",
%{
round: 1,
milestone: "vertical slice",
player_promise: "make combat onboarding readable"
},
source: "/ceo"
)
)
final_ceo_state =
Lesson08Helpers.wait_until(fn ->
{:ok, state} = AgentServer.state(ceo_pid)
if length(state.agent.state.alignment_packets) == 1 do
state
end
end)
Lesson08Helpers.safe_stop_family(ceo_id)
%{
alignment_packets: final_ceo_state.agent.state.alignment_packets
}