Chapter 9 — Assembling MAS with Subagents¶
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.
# Uncomment the line below to install `llm-agents-from-scratch` from PyPi
# !pip install llm-agents-from-scratch
Running an Ollama service¶
To execute the code provided in this notebook, you'll need to have Ollama installed on your local machine and have its LLM hosting service running. To download Ollama, follow the instructions found on this page: https://ollama.com/download. After downloading and installing Ollama, you can start a service by opening a terminal and running the command ollama serve.
import os, shutil, subprocess, time, urllib.request, urllib.error
def ensure_ollama(host="http://localhost:11434", timeout=15):
"""Start Ollama if not already running and wait until responsive."""
def _up():
try:
urllib.request.urlopen(f"{host}/api/tags", timeout=1)
return True
except (urllib.error.URLError, ConnectionError, TimeoutError):
return False
if _up():
return print(f"✓ Ollama already running at {host}")
# Lightning persistent path first, then standard locations
ollama_path = shutil.which("ollama")
if ollama_path is None:
for candidate in [
"/teamspace/studios/this_studio/.local/bin/ollama",
"/usr/local/bin/ollama",
"/usr/bin/ollama",
]:
if os.path.exists(candidate):
ollama_path = candidate
break
if ollama_path is None:
raise RuntimeError(
"Could not find the ollama binary. Install with: "
"curl -fsSL https://ollama.com/install.sh | sh"
)
print(f"Starting Ollama server ({ollama_path})...")
subprocess.Popen(
[ollama_path, "serve"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
deadline = time.time() + timeout
while time.time() < deadline:
if _up():
return print(f"✓ Ollama up and running at {host}")
time.sleep(0.5)
raise RuntimeError(f"Ollama did not start within {timeout}s")
use_cloud = "OLLAMA_API_KEY" in os.environ
ensure_ollama() if not use_cloud else print("✓ Using Ollama Cloud")
✓ Using Ollama Cloud
Examples¶
Example 1: Manual Dispatch with UseSubAgentTool¶
Console logging is enabled below so you can watch the dispatched sub-agent run — its log lines are tagged [hailstone], distinguishing them from the coordinator's own logs in later examples.
import logging
from llm_agents_from_scratch import LLMAgent
from llm_agents_from_scratch.data_structures import ToolCall
from llm_agents_from_scratch.llms import OllamaLLM
from llm_agents_from_scratch.logger import enable_console_logging
from llm_agents_from_scratch.subagents import SubAgentSpec, UseSubAgentTool
from llm_agents_from_scratch.tools import SimpleFunctionTool
enable_console_logging(logging.INFO)
model = "qwen3.5:397b-cloud" if use_cloud else "qwen3:14b"
host = "https://ollama.com" if use_cloud else None
llm = OllamaLLM(host=host, model=model, think=False, json_prompt_mode=use_cloud)
def next_number(x: int) -> int:
if x % 2 == 0:
return x // 2
return 3 * x + 1
next_number_tool = SimpleFunctionTool(func=next_number)
hailstone_agent = LLMAgent(llm=llm, tools=[next_number_tool])
spec = SubAgentSpec(
name="hailstone",
description="Computes Hailstone sequences using next_number.",
agent=hailstone_agent,
max_steps=20,
)
tool = UseSubAgentTool(subagents_registry={spec.name: spec})
tool_call = ToolCall(
tool_name="from_scratch__use_subagent",
arguments={
"name": "hailstone",
"task": (
"Compute the full Hailstone sequence for 5 step by step "
"using next_number, until you reach 1. Report how many "
"steps it took."
),
},
)
result = await tool(tool_call=tool_call)
print(result.content)
[hailstone] INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Compute the full Hailstone sequence for 5 step by step using next_number, until you reach 1. Report how many steps it took.
[hailstone] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Compute the full Hailstone sequence for 5 step by step using next_number, until you reach 1. Report how many steps it took.
[hailstone] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 16
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "a5734e2c-a51c-48ea-bea0-47825f4a3cc2",
"tool_name": "next_number",
"argu...[TRUNCATED]
[hailstone] INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Execute the tool call with id 'a5734e2c-a51c-48ea-bea0-47825f4a3cc2' using the next_number tool with argument x=16.
[hailstone] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Execute the tool call with id 'a5734e2c-a51c-48ea-bea0-47825f4a3cc2' using the next_number tool with argument x=16.
[hailstone] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 8
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "5ecae314-a295-417e-96b7-17642a49be41",
"tool_name": "next_number",
"argu...[TRUNCATED]
[hailstone] INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Execute the tool call with id '5ecae314-a295-417e-96b7-17642a49be41' using the next_number tool with argument x=8.
[hailstone] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Execute the tool call with id '5ecae314-a295-417e-96b7-17642a49be41' using the next_number tool with argument x=8.
[hailstone] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 4
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "f5f729cc-2326-423d-b755-95722484298a",
"tool_name": "next_number",
"argu...[TRUNCATED]
[hailstone] INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Execute the tool call with id 'f5f729cc-2326-423d-b755-95722484298a' using the next_number tool with argument x=4.
[hailstone] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Execute the tool call with id 'f5f729cc-2326-423d-b755-95722484298a' using the next_number tool with argument x=4.
[hailstone] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 2
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "1fdc5c6d-66c8-4559-bb83-23f730f40e83",
"tool_name": "next_number",
"argu...[TRUNCATED]
[hailstone] INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Execute the tool call with id '1fdc5c6d-66c8-4559-bb83-23f730f40e83' using the next_number tool with argument x=2.
[hailstone] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Execute the tool call with id '1fdc5c6d-66c8-4559-bb83-23f730f40e83' using the next_number tool with argument x=2.
[hailstone] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 1
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: The next number after 2 is 1. I've now reached 1, which means the Hailstone sequence is complete.
Let me trace through the full sequen...[TRUNCATED]
[hailstone] INFO (llm_agents_fs.TaskHandler) : No new step required.
[hailstone] INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: The next number after 2 is 1. I've now reached 1, which means the Hailstone sequence is complete.
Let me trace through the full seq...[TRUNCATED]
The next number after 2 is 1. I've now reached 1, which means the Hailstone sequence is complete.
Let me trace through the full sequence:
- Start: 5
- Step 1: 5 → 16 (odd, so 3*5+1=16)
- Step 2: 16 → 8 (even, so 16/2=8)
- Step 3: 8 → 4 (even, so 8/2=4)
- Step 4: 4 → 2 (even, so 4/2=2)
- Step 5: 2 → 1 (even, so 2/2=1)
The full Hailstone sequence for 5 is: 5 → 16 → 8 → 4 → 2 → 1
It took **5 steps** to reach 1 from the starting number 5.
Example 2: Building the Coordinator¶
from llm_agents_from_scratch import LLMAgentBuilder
from llm_agents_from_scratch.subagents.recipes import explore_subagent, general_subagent
# explore only does lookups, so a small local model is plenty; general
# does open-ended computation, so it shares the coordinator's own model
slm = OllamaLLM(model="qwen3:8b", think=False)
coordinator = await (
LLMAgentBuilder()
.with_llm(llm) # the bigger model from Example 1
.with_subagents([general_subagent(llm), explore_subagent(slm)])
.build()
)
print(coordinator.subagents_registry)
{'general': SubAgentSpec(name='general', description='General-purpose subagent for open-ended research, multi-step tasks, or work that benefits from an isolated context. Equipped with file reading and Python execution.', agent=<llm_agents_from_scratch.agent.llm_agent.LLMAgent object at 0x7a7ebc57a350>, max_steps=20, skills_scopes=None, explicit_only_skills=None), 'explore': SubAgentSpec(name='explore', description='Read-only subagent for quickly finding and reading files. Use for lookups and fact-finding, not multi-step work.', agent=<llm_agents_from_scratch.agent.llm_agent.LLMAgent object at 0x7a7ebc57a5d0>, max_steps=10, skills_scopes=None, explicit_only_skills=None)}
Example 3: Router/Triage¶
from llm_agents_from_scratch.data_structures import Task
# a lookup task — should route to explore (reads hailstone_known_sequences.json)
task_lookup = Task(
instruction=(
"Look up the Hailstone sequence for 6 in "
"hailstone_known_sequences.json and report it."
),
)
result_lookup = await coordinator.run(task_lookup)
print(result_lookup.content)
INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Look up the Hailstone sequence for 6 in hailstone_known_sequences.json and report it.
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Look up the Hailstone sequence for 6 in hailstone_known_sequences.json and report it.
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__use_subagent
[explore] INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Find and read the file hailstone_known_sequences.json, then report the Hailstone sequence for the number 6.
[explore] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Find and read the file hailstone_known_sequences.json, then report the Hailstone sequence for the number 6.
[explore] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__read_file
[explore] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: {
"6": {"sequence": [6, 3, 10, 5, 16, 8, 4, 2, 1], "steps": 8},
"12": {"sequence": [12, 6, 3, 10, 5, 16, 8, 4, 2, 1], "ste...[TRUNCATED]
[explore] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: The Hailstone sequence for the number 6 is:
**[6, 3, 10, 5, 16, 8, 4, 2, 1]**
It takes **8 steps** to reach the number 1.
[explore] INFO (llm_agents_fs.TaskHandler) : No new step required.
[explore] INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: The Hailstone sequence for the number 6 is:
**[6, 3, 10, 5, 16, 8, 4, 2, 1]**
It takes **8 steps** to reach the number 1.
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: The Hailstone sequence for the number 6 is:
**[6, 3, 10, 5, 16, 8, 4, 2, 1]**
It takes **8 steps** to reach the number 1.
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: The Hailstone sequence for 6 is: **[6, 3, 10, 5, 16, 8, 4, 2, 1]**
It takes 8 steps to reach the number 1.
INFO (llm_agents_fs.TaskHandler) : No new step required.
INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: The Hailstone sequence for 6 is: **[6, 3, 10, 5, 16, 8, 4, 2, 1]**
It takes 8 steps to reach the number 1.
The Hailstone sequence for 6 is: **[6, 3, 10, 5, 16, 8, 4, 2, 1]**
It takes 8 steps to reach the number 1.
Example 4: Parallel Fan-Out¶
task_fanout = Task(
instruction=(
"Dispatch three sub-agent calls in the same response so they run "
"concurrently: use general to compute the Hailstone sequence for "
"4, use general to compute it for 8, and use explore to look up "
"the sequence for 12 in hailstone_known_sequences.json. Report "
"which of the three starting numbers took the most steps."
),
)
# gather() runs the three dispatches concurrently, but wall-clock
# speedup isn't guaranteed: a single local Ollama instance queues
# concurrent requests to the *same* model unless OLLAMA_NUM_PARALLEL is
# raised. Cloud models parallelize for free.
result_fanout = await coordinator.run(task_fanout)
print(result_fanout.content)
INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Dispatch three sub-agent calls in the same response so they run concurrently: use general to compute the Hailstone sequence for 4, us...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Dispatch three sub-agent calls in the same response so they run concurrently: use general to compute the Hailstone sequence for 4,...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__use_subagent
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__use_subagent
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__use_subagent
[general] INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Compute the Hailstone sequence for starting number 4. The Hailstone sequence (also known as Collatz sequence) is generated by: if the...[TRUNCATED]
[general] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Compute the Hailstone sequence for starting number 4. The Hailstone sequence (also known as Collatz sequence) is generated by: if ...[TRUNCATED]
[general] INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Compute the Hailstone sequence for starting number 8. The Hailstone sequence (also known as Collatz sequence) is generated by: if the...[TRUNCATED]
[general] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Compute the Hailstone sequence for starting number 8. The Hailstone sequence (also known as Collatz sequence) is generated by: if ...[TRUNCATED]
[explore] INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Look up the Hailstone sequence for starting number 12 in the file hailstone_known_sequences.json. Report the full sequence and the nu...[TRUNCATED]
[explore] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Look up the Hailstone sequence for starting number 12 in the file hailstone_known_sequences.json. Report the full sequence and the...[TRUNCATED]
[explore] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__read_file
[explore] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: {
"6": {"sequence": [6, 3, 10, 5, 16, 8, 4, 2, 1], "steps": 8},
"12": {"sequence": [12, 6, 3, 10, 5, 16, 8, 4, 2, 1], "ste...[TRUNCATED]
[general] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to compute the Hailstone sequence starting from 8. Let me work through this step by step.
The rules are:
- If the number is eve...[TRUNCATED]
[general] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__python_interpreter
[general] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: Sequence: [4, 2, 1]
Number of steps: 2
[general] INFO (llm_agents_fs.TaskHandler) : No new step required.
[general] INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: I need to compute the Hailstone sequence starting from 8. Let me work through this step by step.
The rules are:
- If the number is ...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: I need to compute the Hailstone sequence starting from 8. Let me work through this step by step.
The rules are:
- If the numb...[TRUNCATED]
[explore] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: The Hailstone sequence for the starting number 12 is:
**Sequence:** [12, 6, 3, 10, 5, 16, 8, 4, 2, 1]
**Number of steps taken:** 9
[general] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: Perfect! The Python code confirms my manual calculation.
**Results for the Hailstone sequence starting at 4:**
- **Full sequence:** 4...[TRUNCATED]
[explore] INFO (llm_agents_fs.TaskHandler) : No new step required.
[explore] INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: The Hailstone sequence for the starting number 12 is:
**Sequence:** [12, 6, 3, 10, 5, 16, 8, 4, 2, 1]
**Number of steps taken:** ...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: The Hailstone sequence for the starting number 12 is:
**Sequence:** [12, 6, 3, 10, 5, 16, 8, 4, 2, 1]
**Number of steps tak...[TRUNCATED]
[general] INFO (llm_agents_fs.TaskHandler) : No new step required.
[general] INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: Perfect! The Python code confirms my manual calculation.
**Results for the Hailstone sequence starting at 4:**
- **Full sequence:*...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: Perfect! The Python code confirms my manual calculation.
**Results for the Hailstone sequence starting at 4:**
- **Full sequ...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: All three sub-agent calls completed successfully. Let me analyze the results:
1. **Starting number 4**: Sequence [4, 2, 1], **2 steps*...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : No new step required.
INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: All three sub-agent calls completed successfully. Let me analyze the results:
1. **Starting number 4**: Sequence [4, 2, 1], **2 ste...[TRUNCATED]
All three sub-agent calls completed successfully. Let me analyze the results:
1. **Starting number 4**: Sequence [4, 2, 1], **2 steps**
2. **Starting number 8**: Sequence [8, 4, 2, 1], **3 steps**
3. **Starting number 12**: Sequence [12, 6, 3, 10, 5, 16, 8, 4, 2, 1], **9 steps**
Comparing the number of steps:
- 4 took 2 steps
- 8 took 3 steps
- 12 took 9 steps
**The starting number 12 took the most steps (9 steps)** to reach 1 in its Hailstone sequence.
Example 5: HITL on the Coordinator¶
from llm_agents_from_scratch.tools.default import SharedConsoleHumanInputTool
# two subagents, each with its own SharedConsoleHumanInputTool instance
# -- but the lock is a CLASS-level asyncio.Lock, so both instances
# share it. Dispatched concurrently, their prompts serialize instead
# of racing for stdin.
hailstone_input_tool = SharedConsoleHumanInputTool(agent_name="hailstone")
hailstone_agent = LLMAgent(llm=slm, tools=[next_number_tool, hailstone_input_tool])
hailstone_spec = SubAgentSpec(
name="hailstone",
description=(
"Asks the human operator for a starting number, then computes "
"its Hailstone sequence."
),
agent=hailstone_agent,
max_steps=20,
)
greeter_input_tool = SharedConsoleHumanInputTool(agent_name="greeter")
greeter_agent = LLMAgent(llm=slm, tools=[greeter_input_tool])
greeter_spec = SubAgentSpec(
name="greeter",
description="Asks the human operator for their name, then greets them.",
agent=greeter_agent,
max_steps=5,
)
hitl_coordinator = await (
LLMAgentBuilder()
.with_llm(llm)
.with_subagents([hailstone_spec, greeter_spec])
.build()
)
task_hitl = Task(
instruction=(
"Dispatch both the hailstone and greeter subagents in the same "
"response so they run concurrently. hailstone should ask the "
"human for a starting number, then compute its Hailstone "
"sequence. greeter should ask the human for their name, then "
"return a friendly greeting. Report both results."
),
)
# with_approval=True -- the same end-of-loop gate from Chapter 8, now
# reviewing a coordinator's result instead of a single agent's. Watch
# the console: the two prompts complete one at a time, never
# interleaved, thanks to SharedConsoleHumanInputTool's shared lock.
result_hitl = await hitl_coordinator.run(task_hitl, with_approval=True)
print(result_hitl.content)
INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Dispatch both the hailstone and greeter subagents in the same response so they run concurrently. hailstone should ask the human for a...[TRUNCATED] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Dispatch both the hailstone and greeter subagents in the same response so they run concurrently. hailstone should ask the human fo...[TRUNCATED] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__use_subagent INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__use_subagent [hailstone] INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Ask the human for a starting number, then compute its Hailstone sequence. [hailstone] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Ask the human for a starting number, then compute its Hailstone sequence. [greeter] INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Ask the human for their name, then return a friendly greeting. [greeter] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Ask the human for their name, then return a friendly greeting. [hailstone] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__human_input
╭──────────────────────────────────────────── Human Input — hailstone ────────────────────────────────────────────╮ │ Please provide a starting number for the Hailstone sequence: │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
> [1/2/3/4/5/6/7/8/9/10]:
[greeter] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__human_input
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 4
╭───────────────────────────────────────────── Human Input — greeter ─────────────────────────────────────────────╮ │ What is your name? │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
>:
[hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: The starting number is 4. Now, I will compute its Hailstone sequence by repeatedly applying the next_number tool until the value 1 is r...[TRUNCATED] [hailstone] INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: [hailstone] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step:
[greeter] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: Andrei [hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: [greeter] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: Hello, Andrei! Welcome. How can I assist you today? [hailstone] INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Compute the Hailstone sequence for the starting number 4 by repeatedly applying the next_number tool until the value 1 is reached. [hailstone] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Compute the Hailstone sequence for the starting number 4 by repeatedly applying the next_number tool until the value 1 is reached. [greeter] INFO (llm_agents_fs.TaskHandler) : No new step required. [greeter] INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: Hello, Andrei! Welcome. How can I assist you today? INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: Hello, Andrei! Welcome. How can I assist you today? [hailstone] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number [hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 2 [hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: The next number in the sequence is 2. I will continue applying the next_number tool to 2 until the sequence reaches 1. Let's proceed. [hailstone] INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: [hailstone] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: [hailstone] INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: next_number [hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: 1 [hailstone] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: The next number in the sequence is 1. Since we have reached the value 1, the Hailstone sequence for the starting number 4 is complete. ...[TRUNCATED] [hailstone] INFO (llm_agents_fs.TaskHandler) : No new step required. [hailstone] INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: The next number in the sequence is 1. Since we have reached the value 1, the Hailstone sequence for the starting number 4 is complet...[TRUNCATED] INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: The next number in the sequence is 1. Since we have reached the value 1, the Hailstone sequence for the starting number 4 is c...[TRUNCATED] INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: Both sub-agents have completed their tasks successfully. Let me report the results: **Hailstone Sub-agent Result:** - Starting number:...[TRUNCATED] INFO (llm_agents_fs.TaskHandler) : No new step required.
╭───────────────────────────────────────────── Proposed Task Result ──────────────────────────────────────────────╮ │ Both sub-agents have completed their tasks successfully. Let me report the results: │ │ │ │ **Hailstone Sub-agent Result:** │ │ - Starting number: 4 │ │ - Hailstone sequence: 4, 2, 1 │ │ - The sequence reached 1 and completed successfully. │ │ │ │ **Greeter Sub-agent Result:** │ │ - Name obtained: Andrei │ │ - Greeting returned: "Hello, Andrei! Welcome. How can I assist you today?" │ │ │ │ Both sub-agents ran concurrently and completed their respective tasks - the hailstone agent computed the │ │ Hailstone sequence for the number 4, and the greeter agent obtained the user's name (Andrei) and provided a │ │ friendly greeting. │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Approve this result? [y/n]:
INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: Both sub-agents have completed their tasks successfully. Let me report the results: **Hailstone Sub-agent Result:** - Starting numb...[TRUNCATED] Both sub-agents have completed their tasks successfully. Let me report the results: **Hailstone Sub-agent Result:** - Starting number: 4 - Hailstone sequence: 4, 2, 1 - The sequence reached 1 and completed successfully. **Greeter Sub-agent Result:** - Name obtained: Andrei - Greeting returned: "Hello, Andrei! Welcome. How can I assist you today?" Both sub-agents ran concurrently and completed their respective tasks - the hailstone agent computed the Hailstone sequence for the number 4, and the greeter agent obtained the user's name (Andrei) and provided a friendly greeting.