A playground for exploring the pi library
(@earendil-works/pi-*, the "pi.dev" project) to build AI agents.
Pi is an open-source AI agent framework with a unified multi-provider LLM API (OpenAI, Anthropic, Google, Mistral, xAI, and many more), token/cost tracking, tool calling, and an extensible agent core. We start with TypeScript Jupyter notebooks so we can experiment interactively.
The notebooks run on the Deno Jupyter kernel. @earendil-works/pi-ai is an
ESM-only package (its exports map defines only the import condition, no
require). Node's CommonJS-based Jupyter kernels (tslab, ijavascript) transpile
to require() and therefore cannot import pi.dev at all. Deno runs TypeScript and
ESM natively, supports top-level await, and loads npm packages via npm: specifiers —
so it runs pi.dev out of the box while staying a TS/JS (non-Python) notebook.
Everything the notebooks need lives in notebooks/ (so the Deno kernel — whose working
directory is the notebook's folder — always finds deno.json):
notebooks/
000-hello-typescript.ipynb # simplest check: TypeScript runs in a notebook
010-hello-world.ipynb # one LLM round-trip via pi-ai (Azure OpenAI)
020-streaming.ipynb # streamSimple + iterating the event stream
030-multi-turn-chat.ipynb # managing Context.messages history + running cost
040-tool-calling.ipynb # Tool + TypeBox schema, the manual agent loop
050-structured-output.ipynb # typed JSON via a forced tool + validateToolCall
060-vision-image-input.ipynb # multimodal ImageContent input
070-reasoning-thinking.ipynb # reasoning levels + ThinkingContent blocks
080-cost-caching-robustness.ipynb # calculateCost, cacheRetention, abort, retries
090-multiple-providers.ipynb # unified API across several models/providers
100-agent-framework.ipynb # @earendil-works/pi-agent-core Agent class
110-coding-agent.ipynb # pi-agent-core coding agent: writes & runs Python
120-coding-agent-sdk.ipynb # pi-coding-agent createAgentSession variant
env.ts # walk-up .env loader
azure.ts # shared registerAzure() provider setup helper
deno.json # import map + npm deps for Deno
deno.lock # pinned dependency lockfile (committed)
.env.example # which API keys are supported
Notebooks 020 onward are a progressive series: each loads env with loadEnvUp()
then registers Azure OpenAI in one call via registerAzure() (from azure.ts),
so the notebook stays focused on the one pi feature it teaches. They all target the
same AZURE_PI_TEST_* env vars as 010. The two coding-agent notebooks (110,
120) additionally use AZURE_PI_TEST_DEPLOYMENT2 and run generated code inside a
sandboxed environment1/ subfolder.
# Deno (the runtime + Jupyter kernel)
brew install deno # or: curl -fsSL https://deno.land/install.sh | sh
# A Jupyter front-end. Either:
# (a) JupyterLab in the browser:
pip3 install jupyterlab
# (b) or just use VS Code with the "Jupyter" extension installed.deno jupyter --install
jupyter kernelspec list # should list "deno"cd notebooks
deno install # reads deno.json / deno.lock, populates node_modules/Keep your key on disk but outside the git folder so it can never be committed.
Create a .env in a parent directory (see notebooks/.env.example for supported keys):
# e.g. one directory above the repo: ../.env
ANTHROPIC_API_KEY=sk-ant-...Cell 1 of each notebook calls loadEnvUp() (from env.ts), which walks up the
directory tree from the notebook folder and loads every .env it finds,
closest-first (a nearer .env wins on conflicts), printing the keys loaded from
each. Anthropic uses Haiku (claude-haiku-4-5) in
01-hello-world.ipynb; add OPENAI_API_KEY or GEMINI_API_KEY to use another provider.
JupyterLab:
cd notebooks
jupyter labOpen a notebook, and in the top-right kernel picker choose Deno.
VS Code:
- Open
notebooks/01-hello-world.ipynb. - Click the kernel picker (top-right) → Select Another Kernel… → Jupyter Kernel… → Deno.
- Run the cells.
⚠️ Do not pick "TypeScript" (tslab). It's a CommonJS kernel and cannot load pi.dev; it fails withCannot find module/Unexpected pending rebuildTimerand also re-saves the wrong kernel into the notebook file. Always choose Deno.If the Deno kernel isn't listed in VS Code, it was installed while VS Code was running:
Cmd/Ctrl+Shift+P→ Developer: Reload Window (and if needed Jupyter: Clear Kernel Cache, then reload again).
env.tsnever overwrites variables already exported in your shell (pass{ override: true }toloadEnvUpif you want it to).- Keys are only ever read from a
.env/ the environment — never write them into a cell. .envis git-ignored; only.env.exampleis committed.- Re-run
deno installinnotebooks/wheneverdeno.jsonchanges.