package_root = Path.expand("../..", __DIR__)
Mix.install(
[
{:kino, "~> 0.14"},
{:jidoka, path: package_root}
],
consolidate_protocols: false,
lockfile: Path.join(package_root, "mix.lock")
)
Code.require_file(Path.expand("../loader.exs", __DIR__))
JidokaExamples.Loader.load!(__DIR__)
alias JidokaExamples.DurableRefund.Agent, as: DurableRefundAgent
alias JidokaExamples.DurableRefund.Scenario
Jidoka.Kino.setup_notebook(model: "test:durable-refund-script", check_provider?: false)Run The Demo
This Livebook runs one deterministic refund agent through asynchronous streaming, cancellation, execution limits, crash recovery, and a safe session fork. It also runs two read-only operations together and proves that model observation order stays stable. Additional sections record redacted local trace data, aggregate usage, and run the same agent under process hosting. It does not use a provider key or network access.
Inspect The Agent
{:ok, _inspection} = Jidoka.Kino.debug_agent(DurableRefundAgent)
{:ok, _diagram} = Jidoka.Kino.agent_diagram(DurableRefundAgent)Stream One Async Request
{:ok, stream_report} = Scenario.async_streaming(observer: self())
unless stream_report.answer == stream_report.text and
length(stream_report.terminal_events) == 1 do
raise "the async stream did not produce one correlated result"
end
%{
answer: stream_report.answer,
thinking: stream_report.thinking,
event_names: Enum.map(stream_report.events, & &1.event)
}Record Usage And A Redacted Local Trace
{:ok, observability_report} = Scenario.observability()
%{
usage: observability_report.usage,
trace_entries: length(observability_report.trace),
last_trace_entry: List.last(observability_report.trace)
}Run Under Process Hosting
{:ok, host_report} = Scenario.process_host()
%{
id: host_report.id,
answer: host_report.result.content,
terminal_status: host_report.terminal.status,
stopped?: Jidoka.whereis(host_report.id) == nil
}Run Parallel Operations In Stable Order
Both policy checks start before either can finish. The scenario releases
B2002 first. Jidoka still gives the model the observations in its requested
order: A1001, then B2002.
{:ok, parallel_report} = Scenario.parallel_operations(observer: self())
unless parallel_report.completion_order == ["B2002", "A1001"] and
parallel_report.observation_order == ["A1001", "B2002"] do
raise "parallel operations did not preserve model order"
end
%{
completion_order: parallel_report.completion_order,
observation_order: parallel_report.observation_order,
answer: parallel_report.answer
}Cancel Active Work
{:ok, cancellation_report} = Scenario.typed_cancellation(observer: self())
unless cancellation_report.cancellation.reason == :cancelled and
cancellation_report.capability_alive? == false and
length(cancellation_report.terminal_events) == 1 do
raise "typed cancellation did not clean up the active capability"
end
%{
cancellation: cancellation_report.cancellation,
terminal_events: cancellation_report.terminal_events
}Enforce Execution Limits
{:ok, budget_report} = Scenario.bounded_execution(observer: self())
%{
max_output_tokens: budget_report.max_tokens,
operation_calls: budget_report.operation_calls,
turn_error: budget_report.turn_result,
timeout_error: budget_report.timeout_result
}Recover After A Worker Crash
The first worker stops after the unsafe refund result is in the durable snapshot. The second worker takes the expired lease and finishes from the stored result.
{:ok, recovery_report} = Scenario.durable_recovery(observer: self())
unless recovery_report.operation_calls == 1 and
recovery_report.session.status == :finished do
raise "crash recovery repeated or lost the refund"
end
%{
answer: recovery_report.answer,
operation_calls: recovery_report.operation_calls,
session_revision: recovery_report.session.revision,
stored_effects: map_size(recovery_report.durable_snapshot.turn_state.journal.results)
}Fork One Safe Snapshot
{:ok, fork_report} = Scenario.safe_fork()
unless fork_report.source_answer != fork_report.branch_answer and
fork_report.branch.lineage.parent_session_id == fork_report.source.session_id and
fork_report.source_replay.status == :finished do
raise "the safe fork did not create an independent lineage-aware branch"
end
%{
source: %{id: fork_report.source.session_id, answer: fork_report.source_answer},
replay: %{
status: fork_report.source_replay.status,
event_count: length(fork_report.source_replay.timeline)
},
branch: %{
id: fork_report.branch.session_id,
answer: fork_report.branch_answer,
lineage: Jidoka.project(fork_report.branch.lineage)
}
}