Loading the notebook…
Loading the notebook…
Notebooks · Autopilot · 38
Every long-running run should show signs of life. This notebook demos Autopilot.stream() — a generator that yields events in real time, and live_renderer.render_stream() — a pretty TUI consumer. Drop-in components for…
Its imports and arguments are checked against shipit-agent 3.0. The outputs were saved when it was written, for an earlier release.
from pathlib import Path
import sys
# Resolve the repo root whether this cell is running from ./notebooks
# or from the repo root — mirrors the existing 01–36 notebook series.
ROOT = (
Path.cwd().resolve().parent
if Path.cwd().name == "notebooks"
else Path.cwd().resolve()
)
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from examples.run_multi_tool_agent import build_llm_from_env
# Bedrock Llama 4 Scout is the default model this library ships with
# (see `shipit_agent/config.py`). No model name required — the helper
# reads `AWS_REGION` / credentials from env and returns an adapter that
# works with every Autopilot / Agent class.
llm = build_llm_from_env("bedrock")
print("Bedrock LLM ready:", type(llm).__name__)autopilot.stream() returns a Python iterator of {"kind": str, **payload} dicts. Every iteration emits autopilot.iteration; periodic autopilot.heartbeat events prove the run is alive during long idle stretches.
from shipit_agent.autopilot import Autopilot, BudgetPolicy
from shipit_agent.deep import Goal
goal = Goal(
objective="List the top 5 Python HTTP client libraries and their tradeoffs.",
success_criteria=["At least 5 libraries listed", "Each has a one-line tradeoff"],
)
autopilot = Autopilot(
llm=llm,
goal=goal,
budget=BudgetPolicy(max_seconds=300, max_iterations=6, max_tool_calls=15),
heartbeat_every_seconds=20,
)The simplest consumer just prints the kind for every event. Use this when you want full control of how the UI renders.
for ev in autopilot.stream(run_id="http-libs-v1"):
kind = ev["kind"]
if kind == "autopilot.run_started":
print(f"🚀 run_started — goal: {ev['goal']['objective']}")
elif kind == "autopilot.iteration":
met = ev["criteria_met"]
score = f"{sum(met)}/{len(met)}"
print(f"✓ iter {ev['iteration']} — {score} criteria met")
elif kind == "autopilot.heartbeat":
print(f"♥ heartbeat iter={ev['iteration']}")
elif kind == "autopilot.budget_exceeded":
print(f"⛔ budget: {ev['reason']}")
elif kind == "autopilot.result":
print(f"🏁 {ev['status']} — {ev['iterations']} iters")render_stream gives you a Claude-Desktop-style formatted feed for free. Three modes: tui (ANSI colour), jsonl (machine readable), plain (CI logs).
from shipit_agent.autopilot import Autopilot, BudgetPolicy
from shipit_agent.deep import Goal
from shipit_agent.live_renderer import render_stream
autopilot2 = Autopilot(
llm=llm,
goal=Goal(
objective="Write a haiku about Bedrock Llama",
success_criteria=["Three lines", "5-7-5 syllables"],
),
budget=BudgetPolicy(max_iterations=4, max_seconds=120),
)
# `fmt="plain"` is notebook-friendly (no ANSI escapes).
final = render_stream(autopilot2.stream(run_id="haiku-v1"), fmt="plain")
print("\nfinal status:", final and final.get("status"))For durable logs or a browser-side UI, jsonl is the right mode: one event per line, always valid JSON.
from pathlib import Path
import io
from shipit_agent.live_renderer import render_stream
autopilot3 = Autopilot(
llm=llm,
goal=Goal(objective="2+2?", success_criteria=["Answer is 4"]),
budget=BudgetPolicy(max_iterations=2, max_seconds=60),
)
buffer = io.StringIO()
render_stream(autopilot3.stream(run_id="math-v1"), fmt="jsonl", out=buffer)
for line in buffer.getvalue().strip().split("\n")[:6]:
print(line[:120])For a production dashboard you often want to push to Slack / Datadog / custom webhook on each heartbeat. Any callable taking dict works:
heartbeats = []
def record(ev):
if ev.get("kind") == "autopilot.heartbeat":
heartbeats.append(ev)
autopilot4 = Autopilot(
llm=llm,
goal=Goal(
objective="Who invented Python?", success_criteria=["Mentions Guido van Rossum"]
),
budget=BudgetPolicy(max_iterations=3, max_seconds=90),
heartbeat_every_seconds=5, # aggressive for demo
on_heartbeat=record,
)
for _ in autopilot4.stream(run_id="guido-v1"):
pass
print(f"Captured {len(heartbeats)} heartbeat events during the run.")Autopilot.stream() yields events; the final one is always autopilot.result.render_stream(stream, fmt=...) formats them: tui | plain | jsonl.on_heartbeat=callable pushes heartbeat events to any sink you want.Next: 39 — Persistence & the scheduler daemon.