Chapter 8 — Human in the Loop¶
Setup Instructions¶
To ensure you have the required dependencies to run this notebook, you'll need to have our llm-agents-from-scratch framework installed on the running Jupyter kernel. To do this, you can launch this notebook with the following command while within the project's root directory:
uv run --with jupyter jupyter lab
Alternatively, if you just want to use the published version of llm-agents-from-scratch without local development, you can install it from PyPi by uncommenting the cell below.
Tip: If you're running the notebook on a Windows machine, Git only checks out symlinks as real links when symlink support is turned on in Git (the installer's "Enable symbolic links" option, or cloning with
git clone -c core.symlinks=true) and Windows allows creating them (Developer Mode, or an administrator shell). Otherwise, the.agentsfolder contained in this chapter's notebook directory ends up as a plain text file. In that case, delete it and copychapter-notebooks/shared/.agentsinto this folder.
Setting up the LLM¶
I recommend running these notebooks on Ollama Cloud. It serves much larger models than most laptops can run. The default cloud model is picked by benchmarking candidates on these notebooks, and an automated run checks every notebook against it each week. The notebook status page shows the current model and results.
- Create an API key at https://ollama.com/settings/keys.
- Export it before launching Jupyter:
export OLLAMA_API_KEY=<your key>. - That's all. When a notebook builds its LLM, it detects the key and uses Ollama Cloud.
Prefer to run locally? Install Ollama from https://ollama.com/download
and pull the model with ollama pull qwen3:14b. If no key is set, the
notebook starts the Ollama service for you, so there is no need to run
ollama serve. Local models are smaller, so your outputs will differ from
the recorded ones.
Prefer OpenAI or Anthropic?
- Install the extra:
uv sync --extra openaioruv sync --extra anthropic. - Export
OPENAI_API_KEYorANTHROPIC_API_KEYbefore launching Jupyter. If you forget, you will be prompted for it, which keeps the key out of the saved notebook. - Set
LLM_PROVIDER=openai(oranthropic), or passprovider="openai"tomake_llm(). A key on its own never switches providers, so one exported for unrelated work cannot reroute you.
The switch applies wherever a notebook builds its LLM with make_llm().
A notebook that constructs OllamaLLM directly stays on Ollama. Output on
gpt-5 or Claude will differ from the recorded outputs, and prompt-sensitive
examples (the ch09 evaluator pattern, ch08 supervised trajectories) may
behave noticeably differently.
# Uncomment the line below to install `llm-agents-from-scratch` from PyPi
# !pip install llm-agents-from-scratch
from llm_agents_from_scratch.notebook_utils import make_llm
Examples¶
Example 1: Agent-Initiated Pause with HumanInputTool¶
import logging
from llm_agents_from_scratch import LLMAgent
from llm_agents_from_scratch.data_structures import Task
from llm_agents_from_scratch.logger import enable_console_logging
from llm_agents_from_scratch.tools import SimpleFunctionTool
from llm_agents_from_scratch.tools.default import HumanInputTool
enable_console_logging(logging.INFO)
def next_number(x: int) -> int:
if x % 2 == 0:
return x // 2
return 3 * x + 1
next_number_tool = SimpleFunctionTool(func=next_number)
human_input_tool = HumanInputTool()
llm = make_llm()
agent = LLMAgent(llm=llm, tools=[next_number_tool, human_input_tool])
✓ Using Ollama Cloud (deepseek-v4.1-flash)
task = Task(
instruction=(
"Compute the full Hailstone sequence step by step using next_number. "
"The starting number must come from the human operator — ask them "
"before beginning."
)
)
result = await agent.run(task)
print(result.content)
INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Compute the full Hailstone sequence step by step using next_number. The starting number must come from the human operator — ask them ...[TRUNCATED] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Compute the full Hailstone sequence step by step using next_number. The starting number must come from the human operator — ask th...[TRUNCATED] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__human_input
╭────────────────────────────────────────────────── Human Input ──────────────────────────────────────────────────╮ │ What starting number should I use for the Hailstone sequence? │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
>:
[scripted human] > 6
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 6
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "df86d38c-931e-4bc8-b48e-af8bfc80180e",
"tool_name": "from_scratch__use_skill...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Execute the skill 'stop-at-one' by calling from_scratch__use_skill with arguments {"name": "stop-at-one"}.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Execute the skill 'stop-at-one' by calling from_scratch__use_skill with arguments {"name": "stop-at-one"}.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__use_skill
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: <skill_content name="stop-at-one">
# Stop At One
Compute a full sequence from a starting number down to 1
using the `next_num...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "1cfed387-375c-47a0-9b3c-fadea70c1701",
"tool_name": "next_number",
"argu...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Execute the next step of the 'stop-at-one' skill: call the next_number tool with x=6, then wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Execute the next step of the 'stop-at-one' skill: call the next_number tool with x=6, then wait for the tool result before proceed...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 3
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "51fadb57-aac2-44ed-b9d5-9b7252c43807",
"tool_name": "next_number",
"argu...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Call the next_number tool with x=3 and wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Call the next_number tool with x=3 and wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 10
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "7cf382c4-9ede-45d1-b08d-e3db1e3ca054",
"tool_name": "next_number",
"argu...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Execute the next step of the 'stop-at-one' skill: call the next_number tool with x=10, then wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Execute the next step of the 'stop-at-one' skill: call the next_number tool with x=10, then wait for the tool result before procee...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 5
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I received the result 5. The sequence so far is: 6 → 3 → 10 → 5. Since 5 ≠ 1, I need to continue.
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Call the next_number tool with x=5 and wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Call the next_number tool with x=5 and wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 16
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "14601a9e-5d2d-4b95-872a-eb5251b07e34",
"tool_name": "next_number",
"argu...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Execute the next step of the 'stop-at-one' skill: call the next_number tool with x=16, then wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Execute the next step of the 'stop-at-one' skill: call the next_number tool with x=16, then wait for the tool result before procee...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 8
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "d64e03d8-8224-45e4-a9f5-aff866ba5d13",
"tool_name": "next_number",
"argu...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Execute the next step of the 'stop-at-one' skill: call the next_number tool with x=8, then wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Execute the next step of the 'stop-at-one' skill: call the next_number tool with x=8, then wait for the tool result before proceed...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 4
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "f39d0c17-9114-4c7a-9a1b-f7f5c7541f64",
"tool_name": "next_number",
"argu...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Call the next_number tool with x=4 and wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Call the next_number tool with x=4 and wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 2
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I received the result 2. The sequence so far is: 6 → 3 → 10 → 5 → 16 → 8 → 4 → 2. Since 2 ≠ 1, I need to continue.
Next I'll call next...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Call the next_number tool with x=2 and wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Call the next_number tool with x=2 and wait for the tool result before proceeding.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 1
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I received the result 1. The sequence so far is: 6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1.
Since x == 1, the sequence is complete. Here is ...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : No new step required.
INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: I received the result 1. The sequence so far is: 6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1.
Since x == 1, the sequence is complete. Here ...[TRUNCATED]
I received the result 1. The sequence so far is: 6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1.
Since x == 1, the sequence is complete. Here is the final report:
```
6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1
```
- **Starting number:** 6
- **Total steps taken:** 8 tool calls
- **Maximum value reached:** 16
Example 2: End-of-Loop Approval Gate¶
import logging
from llm_agents_from_scratch import LLMAgent
from llm_agents_from_scratch.data_structures import Task
from llm_agents_from_scratch.logger import enable_console_logging
from llm_agents_from_scratch.tools import SimpleFunctionTool
enable_console_logging(logging.INFO)
def next_number(x: int) -> int:
if x % 2 == 0:
return x // 2
return 3 * x + 1
next_number_tool = SimpleFunctionTool(func=next_number)
llm = make_llm()
agent = LLMAgent(llm=llm, tools=[next_number_tool])
✓ Using Ollama Cloud (deepseek-v4.1-flash)
task = Task(
instruction=(
"Compute the full Hailstone sequence starting from 5, "
"step by step using next_number, until you reach 1."
)
)
result = await agent.run(task, with_approval=True)
print(result.content)
INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Compute the full Hailstone sequence starting from 5, step by step using next_number, until you reach 1.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Compute the full Hailstone sequence starting from 5, step by step using next_number, until you reach 1.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__use_skill
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: <skill_content name="stop-at-one">
# Stop At One
Compute a full sequence from a starting number down to 1
using the `next_num...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "c3363daa-cbfc-4a29-ad73-adafe93c9468",
"tool_name": "next_number",
"argu...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Call the next_number tool with x=5 to compute the first step of the Hailstone sequence.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Call the next_number tool with x=5 to compute the first step of the Hailstone sequence.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 16
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "6e63fe5e-51de-4361-b26e-db2b703b1d03",
"tool_name": "next_number",
"argu...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Call the next_number tool with x=16 to compute the next step of the Hailstone sequence.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Call the next_number tool with x=16 to compute the next step of the Hailstone sequence.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 8
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "800c2592-2fc4-4833-b650-3083937c49df",
"tool_name": "next_number",
"argu...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Call the next_number tool with x=8 to compute the next step of the Hailstone sequence.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Call the next_number tool with x=8 to compute the next step of the Hailstone sequence.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 4
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "1210c562-2099-4436-a246-101d7ccf2ac0",
"tool_name": "next_number",
"argu...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Call the next_number tool with x=4 to compute the next step of the Hailstone sequence.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Call the next_number tool with x=4 to compute the next step of the Hailstone sequence.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 2
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "d81a448b-f940-4ec5-918d-2e987e42d021",
"tool_name": "next_number",
"argu...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Call the next_number tool with x=2 to compute the next step of the Hailstone sequence.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Call the next_number tool with x=2 to compute the next step of the Hailstone sequence.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 1
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: The sequence has reached 1. Let me report the complete result.
The full Hailstone sequence starting from 5:
**5 → 16 → 8 → 4 → 2 → 1*...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : No new step required.
╭───────────────────────────────────────────── Proposed Task Result ──────────────────────────────────────────────╮ │ The sequence has reached 1. Let me report the complete result. │ │ │ │ The full Hailstone sequence starting from 5: │ │ │ │ **5 → 16 → 8 → 4 → 2 → 1** │ │ │ │ - **Starting number:** 5 │ │ - **Total steps taken:** 5 tool calls (next_number called with x = 5, 16, 8, 4, 2) │ │ - **Maximum value reached:** 16 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Approve this result? [y/n]:
[scripted human] > y INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: The sequence has reached 1. Let me report the complete result. The full Hailstone sequence starting from 5: **5 → 16 → 8 → 4 → 2 →...[TRUNCATED] The sequence has reached 1. Let me report the complete result. The full Hailstone sequence starting from 5: **5 → 16 → 8 → 4 → 2 → 1** - **Starting number:** 5 - **Total steps taken:** 5 tool calls (next_number called with x = 5, 16, 8, 4, 2) - **Maximum value reached:** 16
Example 3: Caller-Driven Stepwise Execution with run_supervised()¶
import logging
from llm_agents_from_scratch import LLMAgent
from llm_agents_from_scratch.data_structures import Task
from llm_agents_from_scratch.logger import enable_console_logging
from llm_agents_from_scratch.tools import SimpleFunctionTool
enable_console_logging(logging.INFO)
def next_number(x: int) -> int:
if x % 2 == 0:
return x // 2
return 3 * x + 1
next_number_tool = SimpleFunctionTool(func=next_number)
llm = make_llm()
agent = LLMAgent(llm=llm, tools=[next_number_tool])
✓ Using Ollama Cloud (deepseek-v4.1-flash)
task = Task(
instruction=(
"Compute the full Hailstone sequence starting from 4, "
"step by step using next_number, until you reach 1."
)
)
task_handler = await agent.run_supervised(task, explicit_only_skills=["stop-at-one"])
step = await task_handler.get_next_step(None)
step
TaskStep(id_='07cf9d54-7d9d-44b6-a915-7834b6b8873c', task_id='706eadcb-721b-4dd0-8fa9-f66b1a5b3e0f', instruction='Compute the full Hailstone sequence starting from 4, step by step using next_number, until you reach 1.')
step_result = await task_handler.run_step(step)
step_result
INFO (llm_agents_fs.SupervisedTaskHandler) : ⚙️ Processing Step: Compute the full Hailstone sequence starting from 4, step by step using next_number, until you reach 1.
INFO (llm_agents_fs.SupervisedTaskHandler) : 🛠️ Executing Tool Call: next_number
INFO (llm_agents_fs.SupervisedTaskHandler) : ✅ Successful Tool Call: 2
INFO (llm_agents_fs.SupervisedTaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "6149c893-dc30-4f86-8105-9c182c11923b",
"tool_name": "next_number",
"argu...[TRUNCATED]
TaskStepResult(task_step_id='07cf9d54-7d9d-44b6-a915-7834b6b8873c', content='I need to make the following tool-calls:\n{\n "id_": "6149c893-dc30-4f86-8105-9c182c11923b",\n "tool_name": "next_number",\n "arguments": {\n "x": 2\n }\n}')
step = await task_handler.get_next_step(step_result)
step
INFO (llm_agents_fs.SupervisedTaskHandler) : 🧠 New Step: Call next_number with x=2 to continue computing the Hailstone sequence.
TaskStep(id_='3ebd3c80-5203-41ff-b51a-ed6956056d36', task_id='706eadcb-721b-4dd0-8fa9-f66b1a5b3e0f', instruction='Call next_number with x=2 to continue computing the Hailstone sequence.')
step_result = await task_handler.run_step(step)
step_result
INFO (llm_agents_fs.SupervisedTaskHandler) : ⚙️ Processing Step: Call next_number with x=2 to continue computing the Hailstone sequence. INFO (llm_agents_fs.SupervisedTaskHandler) : 🛠️ Executing Tool Call: next_number INFO (llm_agents_fs.SupervisedTaskHandler) : ✅ Successful Tool Call: 1 INFO (llm_agents_fs.SupervisedTaskHandler) : ✅ Step Result: The Hailstone sequence starting from 4 is now complete: **4 → 2 → 1** - `next_number(4)` = 2 - `next_number(2)` = 1 We've reached 1,...[TRUNCATED]
TaskStepResult(task_step_id='3ebd3c80-5203-41ff-b51a-ed6956056d36', content="The Hailstone sequence starting from 4 is now complete:\n\n**4 → 2 → 1**\n\n- `next_number(4)` = 2\n- `next_number(2)` = 1\n\nWe've reached 1, so the sequence terminates here. The full Hailstone sequence starting from 4 is **4, 2, 1**.")
step = await task_handler.get_next_step(step_result)
step
INFO (llm_agents_fs.SupervisedTaskHandler) : No new step required.
TaskResult(task_id='706eadcb-721b-4dd0-8fa9-f66b1a5b3e0f', content="The Hailstone sequence starting from 4 is now complete:\n\n**4 → 2 → 1**\n\n- `next_number(4)` = 2\n- `next_number(2)` = 1\n\nWe've reached 1, so the sequence terminates here. The full Hailstone sequence starting from 4 is **4, 2, 1**.")
# since result is a TaskResult, we can call complete()
await task_handler.complete(step)
print(result.content)
The sequence has reached 1. Let me report the complete result. The full Hailstone sequence starting from 5: **5 → 16 → 8 → 4 → 2 → 1** - **Starting number:** 5 - **Total steps taken:** 5 tool calls (next_number called with x = 5, 16, 8, 4, 2) - **Maximum value reached:** 16
Note on the Agent Inspector
The agent above can also be driven step-by-step through a browser UI using the Agent Inspector (
llm-agents-from-scratch-inspector). Install it withpip install llm-agents-from-scratch-inspector, then create a launch script that exposes anagent_builderat module scope:
# main.py
from llm_agents_from_scratch import LLMAgentBuilder
from llm_agents_from_scratch.data_structures import Task
from llm_agents_from_scratch.notebook_utils import make_llm
from llm_agents_from_scratch.tools import SimpleFunctionTool
def next_number(x: int) -> int:
if x % 2 == 0:
return x // 2
return 3 * x + 1
agent_builder = (
LLMAgentBuilder()
.with_llm(make_llm())
.with_tool(SimpleFunctionTool(func=next_number))
)
default_task = Task(
instruction=(
"Compute the full Hailstone sequence starting from 4, "
"step by step using next_number, until you reach 1."
)
)
Then launch:
agent-inspector launch main.py
make_llm()picks the LLM the same way it does in this notebook: Ollama Cloud whenOLLAMA_API_KEYis set, otherwise a local Ollama service, which it starts if one isn't already running. To use OpenAI or Anthropic, setLLM_PROVIDERas described in "Setting up the LLM" at the top of this notebook. The Inspector works the same either way.A browser tab opens where you can enter a task, create a session, and step through
get_next_step()/run_step()interactively. See the Inspector repository for full usage instructions.