github earendil-works/pi v1.5.1

30 minutes ago

New Features

  • Shell login and logout: use pi auth login <provider> and pi auth logout <provider> without starting a session, with API-key and no-browser sign-in options. See Credential commands.
  • Idle prompt cache warming: eligible caches now stay warm for up to 30 minutes between runs when a refresh is expected to pay for itself. See cacheWarming.
  • Anthropic message threads: requests send only new messages while the server continues the conversation, with full-request fallback when earlier context changes. See Anthropic compatibility.
  • Richer Mermaid diagrams: pie charts, author-defined styles, clickable labels on supported terminals, and diagrams in expanded branch and compaction summaries. See Display settings and Markdown transformers.
  • GitHub Copilot classifiers: call Microsoft-Decision-1 through codemode models.classify() for typed decisions and probabilities. See Use classifier models.
  • Package update summaries: pi update --extensions reports each package's npm version or git commit change and distinguishes unchanged, skipped, and warned updates. See Update Pi or packages.

Breaking Changes

  • Custom GrepOperations.readFile callbacks are no longer called for context lines. The field remains accepted as optional and deprecated so existing integrations still compile. The grep tool now takes context lines from ripgrep and no longer reads matched files itself. To search a remote system, override grep's execute(); see Remote Execution (#9276)
  • OpenAI-compatible models no longer send "tools": [] when all tools are disabled in a session that has used tools; the field is omitted. This fixes 400 errors (tools must not be an empty array) from vLLM 0.20+, also behind LiteLLM. If your proxy requires tools once the history has tool calls, such as older LiteLLM versions in front of Anthropic, set compat.requiresToolsWithToolHistory: true for that model in models.json (#11843)

Added

  • pi update now lists each updated package with its npm version or git commit change, for example npm:foo 1.2.0 -> 1.3.0, and prints Packages are already up to date when nothing changed. When nothing changed but an update printed a warning, for example because npm left the old version installed after resolving stale registry metadata, it prints No packages were updated, see the warnings above instead; in offline mode it prints Skipped package updates (offline mode). PackageManager.update() reports each changed package as a new result progress event whose message holds that line (#11707, #11711)
  • Anthropic sessions now use message threads: each request sends only the new messages and the server continues from the previous reply, falling back to the full request when the conversation changed (for example after compaction or a tool list change). On by default for the anthropic provider on api.anthropic.com; set compat.supportsMessageThreads in models.json to enable it for gateways that forward the thread field, or to turn it off. Cache warming does not touch the session's thread (#11545)
  • pi.registerMarkdownTransformer() takes an optional { messageTypes } that selects the Markdown surfaces a transformer runs on. Besides user, assistant, and thinking Markdown, transformers can now opt into custom (custom messages and skill blocks), summary (branch and compaction summaries), and changelog (What's New, /changelog, the Extension Updates notice, and the Update Available note). Without options a transformer runs on user, assistant, and thinking Markdown as before. The built-in Mermaid renderer now also draws diagrams in expanded branch and compaction summaries
  • pi auth login <provider> logs in to a provider from the shell without starting a session, for example pi auth login radius. It signs in with an account in the browser and exits; --api-key saves an API key instead, and --no-browser uses device code or copy-code sign-in instead. Logging in to Radius also configures the Radius MCP server. pi auth logout <provider> removes the stored credentials, like /logout
  • ctx.ui.custom() overlays now honor the blocked option: pi reports blocked program status (OSC 7501) from when the overlay is shown until it calls done(), also while it is hidden with setHidden(). Closing one overlay keeps other open questions blocked (#11816)
  • Added the qwen-token-plan-individual-cn provider for Qwen Token Plan Individual on the China endpoint, using QWEN_TOKEN_PLAN_CN_API_KEY (#7989 by @bigoldcat123)
  • Added Microsoft-Decision-1 classifier support through GitHub Copilot, including codemode models.classify() (#11679 by @Marvae)
  • Added compat.promptCacheKeyMode ("auto", "enabled", or "disabled") to enable prompt cache keys for compatible proxies or omit them for endpoints that reject them. Set it in models.json when using pi (#9442 by @dannote)
  • Added compat.requiresNonNullAssistantContent for OpenAI-compatible endpoints that require an empty string instead of null in assistant messages containing only tool calls. Set it in models.json when using pi (#8118 by @gaoyk19)
  • Added syntax highlighting for Dart, Nix, Groovy, and Gradle files in read and write views (#11643)
  • Added GLM 5.3 to the Qwen Token Plan Individual model allowlist (#11658)
  • Added Claude Fable 5.2 (claude-fable-5-2) to the anthropic provider ($8/$40 per million input/output tokens, 1M context, 128K output). Like Fable 5.1 it uses per-message effort and mid-conversation system messages; requests its safety classifiers refuse before any output are answered by Claude Opus 5 through server-side fallback and billed at Opus 5's price. Claude Fable 5.2 and Mythos 5.2 on other providers, such as OpenRouter's anthropic/claude-fable-5.2, get the same per-message effort support

Changed

  • The default model for the anthropic provider is now Claude Opus 5.5 (claude-opus-5-5) instead of Claude Opus 4.8
  • Default models moved to newer models at the same or a lower price: amazon-bedrock Claude Opus 5.5, azure GPT-6.1 Sol, google and google-vertex Gemini 4 Argon, vercel-ai-gateway GLM 5.3, baseten GLM 5.3, minimax and minimax-cn MiniMax-M3, qwen-token-plan and qwen-token-plan-cn Qwen3.8 Max, opencode-go Kimi K3.1 Pro, and Kimi K2.7 Code instead of Kimi K2.6 for moonshotai, moonshotai-cn, huggingface, opencode, openrouter, cloudflare-workers-ai and cloudflare-ai-gateway
  • cacheWarming now defaults to "idle" instead of "streaming": pi also keeps eligible prompt caches warm for up to 30 minutes between agent runs, but only when a refresh is expected to pay for itself. Set "cacheWarming": "streaming" in global settings for the previous behavior
  • Consecutive cache warms now show as one Cache warmed: $<total> line with the cumulative cost instead of one line per warm
  • The OpenAI Codex provider is shown as "OpenAI Codex" again instead of "OpenAI Codex (legacy)" in /login and the model selector
  • The /login and /logout provider lists and /login <provider> completions now show the preferred partners Radius and OpenRouter first, then all other providers alphabetically. In the provider lists, partners are marked with ✦, the selected Radius row shimmers in the Radius logo colors and the selected OpenRouter row glows in OpenRouter's brand color (lime on dark themes, violet on light themes)
  • Upgraded terminal Mermaid rendering to support more diagram types, including pie charts, author-defined styles, and clickable labels on terminals with hyperlink support (#8158 by @xl0)

Fixed

  • Fixed the grep tool's glob matching from the folder pi was started in instead of from path: with path: "repo", glob: "migrations/main/*.js" returned No matches found even though repo/migrations/main/a.js exists. Globs are now relative to path, the same form grep prints its results in, also when path is a symlink. A leading ./ (./src/*.ts) is ignored instead of matching nothing (#11807, #10998)
  • Fixed prompt template arguments dropping apostrophes and merging words: an apostrophe inside a word, as in doesn't, no longer opens a quote; a quote with no closing match is kept as text; and \" inside "..." (or \' inside '...') gives a literal quote (#11861)
  • Fixed the bash tool reporting only Command timed out when the command had already exited but a background process it started kept writing to its output until the timeout. The error now also reports the shell's exit code and when it exited (#11613)
  • Images in steering and follow-up messages, including prompt() while streaming, are now resized like images in idle prompts instead of being sent and saved at full size (#11738)
  • A failed token refresh of an MCP connection no longer registers an OAuth client or replaces the PKCE verifier of a sign-in in progress, which made that sign-in fail. MCP sign-in now refreshes the stored tokens with the stored client even when the loopback callback port changed, instead of registering a new client and opening the browser. Ctrl+C in /mcp and the --timeout of pi mcp login now also stop a sign-in while it waits up to 25 seconds for another pi process's token refresh, and a refresh lock that fails for another reason than that wait now fails the sign-in instead of opening the browser.
  • Fixed pi mcp list reporting MCP servers with "auth": { "provider": "<provider>" }, such as Radius, as needing sign-in although the provider was signed in: the shell command sent no token. It now sends the provider's /login token and refreshes it when it expired. For these servers the sign-in hint names /login <provider> instead of pi mcp login, and pi mcp login and pi mcp logout point to /login and /logout instead of failing with "does not use OAuth"
  • Fixed RPC mode ignoring an extension's ctx.shutdown() while idle, for example from a timer: the process kept running until the client sent another command. pi now shuts down right away when idle, and a shutdown requested by an extension command waits until the command's prompt response is written (#11599)
  • Fixed changelog notes repeating on every fresh launch when the installed package version has a prerelease suffix, such as 0.1.5-20261020.7: the saved version was read as 0.1.0, so the 0.1.1 to 0.1.5 notes counted as new each time. A saved version without major.minor.patch now shows no notes and is replaced by the installed version, instead of showing the whole changelog (#11703)
  • Fixed RPC mode cutting off shutdown cleanup, such as a pending MCP token refresh, when stdin closed and SIGTERM arrived together, which process managers like Paseo and systemd do. Pi lost the refreshed token and the MCP server revoked the sign-in. Once a shutdown has started, a stdin EOF or a single signal no longer interrupts it; a second signal still exits at once. Print mode likewise no longer dies from a signal that arrives during its final cleanup (#11599)
  • Fixed the grep tool reading every matched file into memory when context was set, which ran out of memory on large files; context now comes from ripgrep, which also fixes UTF-16 files and lone CRs in matched lines, and the match limit notice no longer appears when exactly limit matches exist (#9276, #11423)
  • Fixed the find tool reporting the result limit when exactly limit files match, and limit: 0 in find and ls returning every result or an empty listing; limits below 1 now mean 1 (#7121)
  • Fixed grep match lines, codemode output, compaction summaries of tool results, and MCP error and server summaries cutting an emoji or other non-BMP character in half when truncating, which left an invalid lone surrogate in the text (#7121)
  • Fixed the find tool on Windows returning no results for patterns with Windows separators such as src\**\*.ts, and for every path pattern such as src/**/*.ts with fd 10.5.1, which pi now downloads. Windows path patterns now match the same way with every fd version: src/**/*.ts also finds files directly in src/, and src/*.ts no longer finds files in subdirectories (#9262)
  • Fixed the read tool loading whole files into memory, which ran out of memory on large files even with offset/limit; it now streams the file and keeps only the shown lines. Custom ReadOperations can stream too by providing the new optional createReadStream (#9654)
  • Fixed OAuth logins such as openai and anthropic failing with invalid_grant after pi was stopped while it refreshed an expired token, for example an RPC client that stops pi right after startup while the background catalog refresh runs. The token endpoint had already replaced the refresh token, but pi exited before saving the new one. On exit, pi now waits for a token refresh in progress to be saved (#11692)
  • Fixed Ctrl+P not switching to the only model in scope (or the only available model) when the active model is a different one; it showed "Only one model in scope" instead. Cycling forward from a model outside the scope now also selects the first scoped model instead of skipping it (#11806)
  • Fixed /reload and session switches leaving extension overlays on screen when an extension had more than one ctx.ui.custom({ overlay: true }) open: only the topmost overlay was removed, and the others kept focus and input although the extension that opened them was gone. All extension overlays, including hidden ones, are now removed and disposed; pi's own overlays stay open
  • Fixed /mcp sign-in staying on "Connecting…" for minutes after a successful browser sign-in, with Ctrl+C doing nothing: pi waited for the browser to drop an unused connection to the OAuth callback port. The callback server now closes remaining connections when it shuts down (#11311)
  • Fixed pi aborting (zsh: abort) after repeated image reads, reported on macOS arm64 with Node 24.16. Each image resize starts a worker thread, and pi did not wait for it to stop, so the next resize started a new worker while the previous one was still shutting down. The crash is most likely a Node bug that this overlap triggers and could not be reproduced on Linux; image resizes now wait for the previous worker to stop, which adds about 15 ms per image (#10695)
  • Fixed tool_search and searchTools() not finding a tool by property names and descriptions behind a local $ref, as in MCP input schemas that put their models in $defs. Referenced definitions are read once, so recursive schemas do not loop, and definitions nothing references stay out of the search text (#11803)
  • Fixed the codemode resolves to summary of a tool leaving out field names behind a local $ref, for example structuredContent? instead of structuredContent?: { results } for MCP output schemas that put their models in $defs (#11803)
  • Fixed every codemode script failing with URI malformed when any callable tool, such as an MCP tool, had a $ref with a malformed percent escape (#/$defs/%E0) in its schema, even scripts that do not call that tool. The parameter now renders as unknown in the tool's declaration (#11803)
  • Fixed ctrl+o not expanding or collapsing the output of ! and !! commands run while the agent is working. New !/!! output now starts in the current expand state, the output no longer disappears when a steering or follow-up message is queued, and it moves into the chat when the agent finishes instead of on the next submitted message (#11875)
  • Fixed resuming a session restoring an old thinking level after /tree navigated to before a /thinking change. Like the model, the live thinking level is now recorded on the new branch with the next prompt (#11451)
  • Fixed inline images in fullscreen mode showing only their first row in Orca, while regular mode showed them in full. Fullscreen now draws Kitty images after the rows they cover on every terminal, as it already did for WezTerm (#11835)
  • Fixed the edit tool rewriting the line endings of untouched lines in files with mixed CRLF/LF or lone CR line endings, and running out of memory on large files after the file was already written; the diff now covers only the changed lines and their surroundings and is computed before writing (#8544)
  • Fixed the Windows installer (irm https://pi.dev/install.ps1 | iex) aborting with NativeCommandError in Windows PowerShell 5.1 when npm or Node.js printed any warning, for example npm warn Unknown user config from an unknown .npmrc key. It failed before the action menu when migrating an npm installation, and during managed installs. An invalid managed-install.json also aborted the installer instead of being reported (#11944)
  • Fixed pi update --models failing with Could not refresh model catalogs: openai: OAuth refresh failed for openai: ... invalid_grant when a provider's login had gone stale. Built-in providers whose catalog comes from pi.dev, such as openai, no longer refresh their OAuth token for a catalog refresh at all. For providers that list models with the login, such as Radius and OpenRouter, a failed token refresh now prints a warning naming the provider and pi auth login <provider>, and the other catalogs still refresh; the command fails only for other errors, such as a network failure
  • Fixed the powershell tool reporting Command exited with code 1 under Windows PowerShell 5.1 when a native command succeeded but its stderr was redirected, as in git push 2>&1 | Select-Object -Last 3. Windows PowerShell 5.1 turns that stderr into error records; such commands now report the exit code PowerShell 7 reports (#8842)
  • Fixed deleting a paste marker with Backspace corrupting later short markers such as [paste #2], causing the marker text to be submitted instead of its pasted content (#11923)
  • Fixed dropped provider streams reported as "cut short after the reply had begun" not triggering automatic retries (#11879)
  • Fixed the subagent extension example passing Bun's Windows virtual entry path as part of the prompt when spawning a compiled pi binary (#11865)
  • Fixed the model selector and llama.cpp Hugging Face search moving the selection when a background catalog refresh or search result arrives (#9109)
  • Fixed internal cursor markers leaking into terminal output, including with multiple markers or horizontally clipped content (#9441 by @muyiyr)
  • Fixed the subagent extension example showing running tasks as completed, losing subprocess failure diagnostics, and failing to stop child processes on abort. Agent discovery and trust checks now use each task's working directory, and single and chain results are truncated without losing the full tool details (#8250 by @terrorobe)
  • Fixed large pasted text being replaced by literal paste markers when switching editors, opening custom UI, or restoring queued messages (#10146 by @w-winter)
  • Fixed prompts and session-tree navigation overlapping during asynchronous input hooks, authentication, or branch summaries, which could install the wrong conversation context (#9155 by @acmerfight)
  • Fixed Claude Sonnet 5 requests sending an unsupported temperature parameter (#7961 by @jingtao-wisdomgraph)
  • Fixed extensions loaded through symlinked paths failing to resolve their dependencies by resolving the entry file's real path before importing it (#8112 by @cad0p)
  • Fixed the plan-mode extension example missing completion markers in thinking blocks and common completion phrases, dropping formatted or long plan steps, and sending an extra model turn to acknowledge completion (#7950 by @giannisCKS)
  • Fixed OpenAI Responses requests sending session_id instead of the documented session-id affinity header (#11639)
  • Fixed delivered image-only steering and follow-up messages remaining in the pending queue (#8612 by @wutongyuonce)
  • Fixed cancellation during lazy provider loading or authentication being reported as an error instead of an abort (#8635 by @Mallikarjun-0)
  • Fixed session runtime disposal tearing down extensions before active tools finished aborting and their results were recorded (#9126 by @acmerfight)
  • Fixed the session-tree search cursor not being shown or positioned for input methods (#9157 by @Perlence)
  • Fixed SDK and RPC reloads replacing extensions while a response or compaction was still running; reload now asks the caller to wait (#9222 by @acmerfight)
  • Fixed rendered edit diffs losing shared indentation when a change inserted text at the start of a line (#9274 by @dannote)
  • Fixed ! and !! commands omitting the truncation notice and full-output file link when earlier output chunks had been discarded (#10165 by @acmerfight)
  • Fixed extension selection dialogs growing beyond the terminal height; they now show a scrolling window of up to ten options (#11072 by @DivineDominion)
  • Fixed pi config ignoring custom keybindings from keybindings.json (#11651)
  • Fixed concurrent OAuth refreshes through symlinked paths to the same auth.json by sharing the lock on the resolved file (#11655)
  • Fixed provider connection errors hiding their underlying cause, such as connection refusal or certificate errors, behind generic messages (#11695)
  • Fixed Ctrl+V not pasting clipboard images or text on Windows and WSL; both Ctrl+V and Alt+V are now default paste shortcuts there (#11765)
  • Fixed llama.cpp connection errors omitting the server URL and underlying network error (#11745)
  • Fixed Alacritty hyperlinks not being enabled when TERM_PROGRAM is unset; detection now also uses TERM and ALACRITTY_WINDOW_ID (#11767)
  • Fixed OpenAI Codex SSE retries retaining abort listeners after each backoff, causing listener buildup on repeated retries (#11708)
  • Azure OpenAI models now keep OpenAI's long-context price tier, so requests above 272K input tokens are costed at Azure's long-context rates (#11948)
  • Fixed Anthropic and Bedrock sending strict: "prefer" tools strict again on every request after Claude rejected them for exceeding its strict tool limits, which cost a rejected request (400) per turn. Later requests with the same sessionId now send those tools non-strict right away, until cleanupSessionResources(sessionId) (#11626)
  • Fixed tool arguments for Type.BigInt() and Type.Undefined() parameters being rejected: they convert as TypeBox converted them ("42" and 42 to 42n, null to undefined), now that pi-schema supports both types. Type.Void() still rejects every JSON argument.
  • Fixed Azure GPT-6 Astra, Luna, Sol, GPT-6.1 Sol, and GPT-6.1 Terra using a 272K context window instead of the 1,050,000 tokens Azure Foundry deploys them with (#11742)
  • Fixed OpenRouter rejecting requests with a 400 (This endpoint's maximum context length is ...) for models whose output limit is close to the context window, such as DeepSeek flash. OpenRouter counts the input with its own tokenizer, which can be several percent higher than the provider's count, and pi left only 4,096 tokens spare. pi then treated the 400 as a context overflow and compacted the session, even at around 20% of the window. The default output limit now leaves 15% of the estimated input unused, and near a full window at most 32,768 output tokens are requested (#10497)
  • Fixed Anthropic non-strict tool schemas dropping root $defs and definitions, which left property $refs pointing at nothing. Claude then produced wrong arguments for such tools (common in MCP servers), for example a JSON string instead of an object, and some Anthropic-compatible gateways rejected the request outright (#9557)
  • Fixed OpenCode Go Claude Haiku 5.5 failing with a 400 (Invalid signature in thinking block ... bound to a different conversation) after the tool list, system prompt, or earlier history changed, which left the session failing on every retry. OpenCode Go and Zen Claude 5.5 models, Opus 5, and Fable 5.1 now use per-message effort and send thinking.block_binding: drop_block, like the Anthropic provider (#10954)
  • Fixed Markdown displaying HTML comments (<!-- ... -->) as visible text (#11710)
  • Fixed codemode console.* output and thrown non-Error values printing NaN, Infinity, and -Infinity as null (#11901)
  • Fixed large MCP stdio messages being repeatedly copied and scanned as chunks arrived, causing slow tool responses (#11761)
  • Fixed MCP Streamable HTTP SSE replies with CR-only line endings failing with "stream ended without a response" (#11764)
  • Fixed oversized MCP SSE responses keeping their HTTP connections open after the message-size limit rejected them (#11729)
  • Fixed MCP stdio server subprocesses surviving disconnect or pi exit on POSIX when the server's main process had already exited (#11721)
  • Fixed MCP Streamable HTTP JSON replies bypassing message-size limits and HTTP errors buffering entire response bodies. Oversized replies and error-body content beyond the first 8 KiB are now cancelled (#11335)
  • Fixed valid tool arguments being rejected when their schema combined local $refs with a relative root $id, such as schemas/tool.json (#11697)
  • Fixed the find tool starting an untracked fd process when cancelled during its parent-directory lookup (#11974 by @petrroll)

Don't miss a new pi release

NewReleases is sending notifications on new releases.