* docs: make onboarding friendlier for beginners * docs: build clearer documentation paths Maintainer edit: turn the onboarding follow-up into a layered docs structure for first-time setup, provider selection, troubleshooting, CLI reference, and source-level architecture. This keeps quick start focused while giving advanced users precise reference paths. * docs: render architecture flow with mermaid Maintainer edit: replace the ASCII architecture sketch with a GitHub-rendered Mermaid flowchart so the core runtime path is easier to scan in the PR and README docs. * docs: recommend model presets for model config Maintainer edit: make named modelPresets the primary model configuration path and expand fallback preset examples so string fallbacks are clearly preset names, not raw model IDs. * docs: document api base urls and langfuse setup Maintainer edit: explain when users need apiBase/base URL in quick start and provider docs, and add Langfuse tracing setup with troubleshooting links. * docs: use python module pip consistently Maintainer edit: keep install commands tied to the active Python interpreter by using python -m pip in the Azure optional dependency notes too. * docs: add non-technical getting started path Maintainer edit: add a wizard-first guide for users without terminal or JSON background, including a text TUI menu example and links from the main docs entrypoints. * docs: avoid hard-wrapped prose in user docs Maintainer edit: unwrap ordinary prose across user-facing documentation while preserving markdown structure, code blocks, tables, lists, and prompt/template files. * docs: keep desktop list continuations nested Maintainer edit: preserve list nesting after unwrapping prose in the desktop WebUI sync guide. * docs: add one-command installer Maintainer edit: add auditable macOS/Linux and Windows install scripts that install nanobot-ai and start the onboarding wizard, then document the commands in the main onboarding entrypoints. * docs: add installer dry run mode Maintainer edit: add --dry-run to the one-command installer scripts so users can preview Python detection, install source, pip command, and wizard behavior without changing their environment. * docs: clean installer error output Maintainer edit: make PowerShell installer failures print a concise Error: message instead of Write-Error call-site details. * docs: add provider setup cookbook Maintainer edit: add pasteable provider recipes for common hosted, local, fallback, runtime switching, and Langfuse setups, then link the cookbook from onboarding and troubleshooting entrypoints. * docs: address review feedback * docs: clarify reader paths * docs: explain terminal basics for beginners * docs: clarify wizard navigation * docs: avoid duplicate onboarding steps * docs: add setup status check * docs: explain status output * docs: remove provider recommendation wording * docs: explain status diagnostics * docs: reduce hard-wrapped guidance * docs: migrate config examples to presets * docs: clarify python command fallbacks * docs: improve installer failure recovery * docs: expand install troubleshooting * docs: cover installer download failures * docs: put stable install paths first * docs: add bundled webui quick path * docs: clarify provider-neutral setup * docs: clarify gateway setup for chat surfaces * docs: improve docs navigation paths * docs: add configuration quick jump * docs: clarify provider secret variables * chore: request PR review acknowledgement Empty commit: please read the PR review comments and reply on the PR to confirm that you have received them. This commit intentionally changes no files; it exists only to notify the remote Codex run so it can end its active goal. * docs: add README start here guide * docs: avoid provider recommendation wording * docs: guide next steps after first reply * docs: explain merging JSON snippets * docs: add CLI command chooser * docs: add configuration task map * docs: add deployment readiness guide * docs: simplify WebUI entry paths * docs: add provider recipe chooser * docs: fix provider factual references Update OpenRouter and LongCat model examples, align Bedrock guidance, and make fallback snippets schema-valid. Also correct group policy wording and image-generation provider lists to match the current code. * fix: keep PowerShell installer from closing caller shell * docs: mention self-guided configuration
6.4 KiB
Python SDK
Use nanobot as a library — no CLI, no gateway, just Python.
Before debugging SDK code, prove the same config works from the CLI:
nanobot agent -m "Hello!"
Nanobot.from_config() reuses your normal ~/.nanobot/config.json, so provider, model, tools, and workspace behavior match the CLI unless you override them.
Quick Start
import asyncio
from nanobot import Nanobot
async def main() -> None:
async with Nanobot.from_config() as bot:
result = await bot.run("What time is it in Tokyo?")
print(result.content)
asyncio.run(main())
Use async with when possible so MCP connections and background cleanup work are closed before the event loop exits. If you manage the instance manually, call await bot.aclose() in a finally block.
Common Patterns
Use a specific config or workspace
from nanobot import Nanobot
bot = Nanobot.from_config(
config_path="~/.nanobot/config.json",
workspace="/my/project",
)
Isolate conversations with session_key
Different session keys keep independent conversation history:
await bot.run("hi", session_key="user-alice")
await bot.run("hi", session_key="task-42")
Attach hooks for observability
Hooks let you inspect tool calls, streaming, and iteration state without modifying nanobot internals:
from nanobot.agent import AgentHook, AgentHookContext
class AuditHook(AgentHook):
async def before_execute_tools(self, context: AgentHookContext) -> None:
for tc in context.tool_calls:
print(f"[tool] {tc.name}")
result = await bot.run("Review this change", hooks=[AuditHook()])
API Reference
Nanobot.from_config(config_path=None, *, workspace=None)
Create a Nanobot instance from a config file.
| Param | Type | Default | Description |
|---|---|---|---|
config_path |
str | Path | None |
None |
Path to config.json. Defaults to ~/.nanobot/config.json. |
workspace |
str | Path | None |
None |
Override the workspace directory from config. |
Raises FileNotFoundError if an explicit config path does not exist.
await bot.run(message, *, session_key="sdk:default", hooks=None)
Run the agent once and return a RunResult.
| Param | Type | Default | Description |
|---|---|---|---|
message |
str |
(required) | The user message to process. |
session_key |
str |
"sdk:default" |
Session identifier for conversation isolation. Different keys get independent history. |
hooks |
list[AgentHook] | None |
None |
Lifecycle hooks for this run only. |
await bot.aclose()
Release resources held by the SDK instance, including MCP connections. The async context manager calls this automatically:
async with Nanobot.from_config() as bot:
result = await bot.run("Summarize this repo")
RunResult
| Field | Type | Description |
|---|---|---|
content |
str |
The agent's final text response. |
tools_used |
list[str] |
Reserved for richer SDK introspection; may be empty in current versions. |
messages |
list[dict] |
Reserved for richer SDK introspection; may be empty in current versions. |
Hooks
Hooks let you observe or customize the agent loop. Subclass AgentHook and override the methods you need.
Hook lifecycle
| Method | When |
|---|---|
wants_streaming() |
Return True if you want token-by-token on_stream() callbacks |
before_iteration(context) |
Before each LLM call |
on_stream(context, delta) |
On each streamed token when streaming is enabled |
on_stream_end(context, *, resuming) |
When streaming finishes |
before_execute_tools(context) |
Before tool execution |
after_iteration(context) |
After each iteration |
finalize_content(context, content) |
Transform final output text |
Useful fields on AgentHookContext include:
iterationmessagesresponseusagetool_callstool_resultstool_eventsfinal_contentstop_reasonerror
Example: audit tool calls
from nanobot.agent import AgentHook, AgentHookContext
class AuditHook(AgentHook):
def __init__(self) -> None:
super().__init__()
self.calls: list[str] = []
async def before_execute_tools(self, context: AgentHookContext) -> None:
for tc in context.tool_calls:
self.calls.append(tc.name)
print(f"[audit] {tc.name}({tc.arguments})")
hook = AuditHook()
result = await bot.run("List files in /tmp", hooks=[hook])
print(result.content)
print(f"Tools observed: {hook.calls}")
Example: receive streaming tokens
from nanobot.agent import AgentHook, AgentHookContext
class StreamingHook(AgentHook):
def wants_streaming(self) -> bool:
return True
async def on_stream(self, context: AgentHookContext, delta: str) -> None:
print(delta, end="", flush=True)
async def on_stream_end(self, context: AgentHookContext, *, resuming: bool) -> None:
print()
Compose multiple hooks
Pass multiple hooks when you want to combine behaviors:
result = await bot.run("hi", hooks=[AuditHook(), MetricsHook()])
Async hook methods are fan-out with error isolation. finalize_content is a pipeline: each hook receives the previous hook's output.
Example: post-process final content
from nanobot.agent import AgentHook
class Censor(AgentHook):
def finalize_content(self, context, content):
return content.replace("secret", "***") if content else content
Full Example
import asyncio
import time
from nanobot import Nanobot
from nanobot.agent import AgentHook, AgentHookContext
class TimingHook(AgentHook):
def __init__(self) -> None:
super().__init__()
self._started_at = 0.0
async def before_iteration(self, context: AgentHookContext) -> None:
self._started_at = time.perf_counter()
async def after_iteration(self, context: AgentHookContext) -> None:
elapsed_ms = (time.perf_counter() - self._started_at) * 1000
print(f"[timing] iteration {context.iteration} took {elapsed_ms:.1f}ms")
async def main() -> None:
bot = Nanobot.from_config(workspace="/my/project")
result = await bot.run(
"Explain the main function",
session_key="sdk:demo",
hooks=[TimingHook()],
)
print(result.content)
asyncio.run(main())